savage_driver.c revision 6aec45a7
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_regs.h"
60#include "savage_bci.h"
61#include "savage_streams.h"
62
63#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
64#include "xf86RAC.h"
65#endif
66
67#define TRANSPARENCY_KEY 0xff;
68
69#ifdef XF86DRI
70#define _XF86DRI_SERVER_
71#include "savage_dri.h"
72#include "savage_sarea.h"
73#endif
74
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(int scrnIndex, int flags);
94static void SavageLeaveVT(int scrnIndex, int flags);
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(int scrnIndex, ScreenPtr pScreen, int argc,
102			     char **argv);
103static int SavageInternalScreenInit(int scrnIndex, ScreenPtr pScreen);
104static ModeStatus SavageValidMode(int index, DisplayModePtr mode,
105				  Bool verbose, int flags);
106
107void SavageDGAInit(ScreenPtr);
108static Bool SavageMapMem(ScrnInfoPtr pScrn);
109static void SavageUnmapMem(ScrnInfoPtr pScrn, int All);
110static Bool SavageModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
111static Bool SavageCloseScreen(int scrnIndex, ScreenPtr pScreen);
112static Bool SavageSaveScreen(ScreenPtr pScreen, int mode);
113static void SavageLoadPalette(ScrnInfoPtr pScrn, int numColors,
114			      int *indicies, LOCO *colors,
115			      VisualPtr pVisual);
116static void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors,
117			      int *indicies, LOCO *colors,
118			      VisualPtr pVisual);
119static void SavageUpdateKey(ScrnInfoPtr pScrn, int r, int g, int b);
120static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
121			   int min_n2, int max_n2, long freq_min,
122			   long freq_max, unsigned int *mdiv,
123			   unsigned int *ndiv, unsigned int *r);
124void SavageGEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file);
125void SavagePrintRegs(ScrnInfoPtr pScrn);
126static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags);
127static Bool SavageDDC1(int scrnIndex);
128static unsigned int SavageDDC1Read(ScrnInfoPtr pScrn);
129static void SavageProbeDDC(ScrnInfoPtr pScrn, int index);
130static void SavageGetTvMaxSize(SavagePtr psav);
131static Bool SavagePanningCheck(ScrnInfoPtr pScrn, DisplayModePtr pMode);
132#ifdef XF86DRI
133static Bool SavageCheckAvailableRamFor3D(ScrnInfoPtr pScrn);
134#endif
135static void SavageResetStreams(ScrnInfoPtr pScrn);
136
137extern ScrnInfoPtr gpScrn;
138
139#define iabs(a)	((int)(a)>0?(a):(-(a)))
140
141/*#define TRACEON*/
142#ifdef TRACEON
143#define TRACE(prms)	ErrorF prms
144#else
145#define TRACE(prms)
146#endif
147
148int gSavageEntityIndex = -1;
149
150#ifdef XSERVER_LIBPCIACCESS
151#define SAVAGE_DEVICE_MATCH(d, i) \
152    { 0x5333, (d), PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, (i) }
153
154static const struct pci_id_match savage_device_match[] = {
155    SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE4,         S3_SAVAGE4),
156    SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE3D,        S3_SAVAGE3D),
157    SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE3D_MV,     S3_SAVAGE3D),
158    SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE2000,      S3_SAVAGE2000),
159    SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE_MX_MV,    S3_SAVAGE_MX),
160    SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE_MX,       S3_SAVAGE_MX),
161    SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE_IX_MV,    S3_SAVAGE_MX),
162    SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE_IX,       S3_SAVAGE_MX),
163    SAVAGE_DEVICE_MATCH(PCI_CHIP_PROSAVAGE_PM,    S3_PROSAVAGE),
164    SAVAGE_DEVICE_MATCH(PCI_CHIP_PROSAVAGE_KM,    S3_PROSAVAGE),
165    SAVAGE_DEVICE_MATCH(PCI_CHIP_S3TWISTER_P,     S3_TWISTER),
166    SAVAGE_DEVICE_MATCH(PCI_CHIP_S3TWISTER_K,     S3_TWISTER),
167    SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_MX128,    S3_SUPERSAVAGE),
168    SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_MX64,     S3_SUPERSAVAGE),
169    SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_MX64C,    S3_SUPERSAVAGE),
170    SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IX128SDR, S3_SUPERSAVAGE),
171    SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IX128DDR, S3_SUPERSAVAGE),
172    SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IX64SDR,  S3_SUPERSAVAGE),
173    SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IX64DDR,  S3_SUPERSAVAGE),
174    SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IXCSDR,   S3_SUPERSAVAGE),
175    SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IXCDDR,   S3_SUPERSAVAGE),
176    SAVAGE_DEVICE_MATCH(PCI_CHIP_PROSAVAGE_DDR,   S3_PROSAVAGEDDR),
177    SAVAGE_DEVICE_MATCH(PCI_CHIP_PROSAVAGE_DDRK,  S3_PROSAVAGEDDR),
178
179    { 0, 0, 0 },
180};
181#endif
182
183/* Supported chipsets */
184
185static SymTabRec SavageChips[] = {
186    { PCI_CHIP_SAVAGE4,		"Savage4" },
187    { PCI_CHIP_SAVAGE3D,	"Savage3D" },
188    { PCI_CHIP_SAVAGE3D_MV,	"Savage3D-MV" },
189    { PCI_CHIP_SAVAGE2000,	"Savage2000" },
190    { PCI_CHIP_SAVAGE_MX_MV,	"Savage/MX-MV" },
191    { PCI_CHIP_SAVAGE_MX,	"Savage/MX" },
192    { PCI_CHIP_SAVAGE_IX_MV,	"Savage/IX-MV" },
193    { PCI_CHIP_SAVAGE_IX,	"Savage/IX" },
194    { PCI_CHIP_PROSAVAGE_PM,	"ProSavage PM133" },
195    { PCI_CHIP_PROSAVAGE_KM,	"ProSavage KM133" },
196    { PCI_CHIP_S3TWISTER_P,	"Twister PN133" },
197    { PCI_CHIP_S3TWISTER_K,	"Twister KN133" },
198    { PCI_CHIP_SUPSAV_MX128,	"SuperSavage/MX 128" },
199    { PCI_CHIP_SUPSAV_MX64,	"SuperSavage/MX 64" },
200    { PCI_CHIP_SUPSAV_MX64C,	"SuperSavage/MX 64C" },
201    { PCI_CHIP_SUPSAV_IX128SDR,	"SuperSavage/IX 128" },
202    { PCI_CHIP_SUPSAV_IX128DDR,	"SuperSavage/IX 128" },
203    { PCI_CHIP_SUPSAV_IX64SDR,	"SuperSavage/IX 64" },
204    { PCI_CHIP_SUPSAV_IX64DDR,	"SuperSavage/IX 64" },
205    { PCI_CHIP_SUPSAV_IXCSDR,	"SuperSavage/IXC 64" },
206    { PCI_CHIP_SUPSAV_IXCDDR,	"SuperSavage/IXC 64" },
207    { PCI_CHIP_PROSAVAGE_DDR,	"ProSavage DDR" },
208    { PCI_CHIP_PROSAVAGE_DDRK,	"ProSavage DDR-K" },
209    { -1,			NULL }
210};
211
212static SymTabRec SavageChipsets[] = {
213    { S3_SAVAGE3D,	"Savage3D" },
214    { S3_SAVAGE4,	"Savage4" },
215    { S3_SAVAGE2000,	"Savage2000" },
216    { S3_SAVAGE_MX,	"MobileSavage" },
217    { S3_PROSAVAGE,	"ProSavage" },
218    { S3_TWISTER,       "Twister"},
219    { S3_PROSAVAGEDDR,  "ProSavageDDR"},
220    { S3_SUPERSAVAGE,   "SuperSavage" },
221    { -1,		NULL }
222};
223
224#ifndef XSERVER_LIBPCIACCESS
225/* This table maps a PCI device ID to a chipset family identifier. */
226
227static PciChipsets SavagePciChipsets[] = {
228    { S3_SAVAGE3D,	PCI_CHIP_SAVAGE3D,	RES_SHARED_VGA },
229    { S3_SAVAGE3D,	PCI_CHIP_SAVAGE3D_MV, 	RES_SHARED_VGA },
230    { S3_SAVAGE4,	PCI_CHIP_SAVAGE4,	RES_SHARED_VGA },
231    { S3_SAVAGE2000,	PCI_CHIP_SAVAGE2000,	RES_SHARED_VGA },
232    { S3_SAVAGE_MX,	PCI_CHIP_SAVAGE_MX_MV,	RES_SHARED_VGA },
233    { S3_SAVAGE_MX,	PCI_CHIP_SAVAGE_MX,	RES_SHARED_VGA },
234    { S3_SAVAGE_MX,	PCI_CHIP_SAVAGE_IX_MV,	RES_SHARED_VGA },
235    { S3_SAVAGE_MX,	PCI_CHIP_SAVAGE_IX,	RES_SHARED_VGA },
236    { S3_PROSAVAGE,	PCI_CHIP_PROSAVAGE_PM,	RES_SHARED_VGA },
237    { S3_PROSAVAGE,	PCI_CHIP_PROSAVAGE_KM,	RES_SHARED_VGA },
238    { S3_TWISTER,	PCI_CHIP_S3TWISTER_P,	RES_SHARED_VGA },
239    { S3_TWISTER,	PCI_CHIP_S3TWISTER_K,	RES_SHARED_VGA },
240    { S3_PROSAVAGEDDR,	PCI_CHIP_PROSAVAGE_DDR,	RES_SHARED_VGA },
241    { S3_PROSAVAGEDDR,	PCI_CHIP_PROSAVAGE_DDRK,	RES_SHARED_VGA },
242    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_MX128,	RES_SHARED_VGA },
243    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_MX64,	RES_SHARED_VGA },
244    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_MX64C,	RES_SHARED_VGA },
245    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IX128SDR,	RES_SHARED_VGA },
246    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IX128DDR,	RES_SHARED_VGA },
247    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IX64SDR,	RES_SHARED_VGA },
248    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IX64DDR,	RES_SHARED_VGA },
249    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IXCSDR,	RES_SHARED_VGA },
250    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IXCDDR,	RES_SHARED_VGA },
251    { -1,		-1,			RES_UNDEFINED }
252};
253#endif
254
255typedef enum {
256     OPTION_PCI_BURST
257    ,OPTION_PCI_RETRY
258    ,OPTION_NOACCEL
259    ,OPTION_ACCELMETHOD
260    ,OPTION_LCD_CENTER
261    ,OPTION_LCDCLOCK
262    ,OPTION_MCLK
263    ,OPTION_REFCLK
264    ,OPTION_SHOWCACHE
265    ,OPTION_SWCURSOR
266    ,OPTION_HWCURSOR
267    ,OPTION_SHADOW_FB
268    ,OPTION_ROTATE
269    ,OPTION_USEBIOS
270    ,OPTION_SHADOW_STATUS
271    ,OPTION_CRT_ONLY
272    ,OPTION_TV_ON
273    ,OPTION_TV_PAL
274    ,OPTION_FORCE_INIT
275    ,OPTION_OVERLAY
276    ,OPTION_T_KEY
277    ,OPTION_DISABLE_XVMC
278    ,OPTION_DISABLE_TILE
279    ,OPTION_DISABLE_COB
280    ,OPTION_BCI_FOR_XV
281    ,OPTION_DVI
282    ,OPTION_BUS_TYPE
283    ,OPTION_DMA_TYPE
284    ,OPTION_DMA_MODE
285    ,OPTION_AGP_MODE
286    ,OPTION_AGP_SIZE
287    ,OPTION_DRI
288    ,OPTION_IGNORE_EDID
289    ,OPTION_AGP_FOR_XV
290} SavageOpts;
291
292
293static const OptionInfoRec SavageOptions[] =
294{
295    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN, {0}, FALSE },
296    { OPTION_ACCELMETHOD, "AccelMethod", OPTV_STRING,	{0}, FALSE },
297    { OPTION_HWCURSOR,	"HWCursor",	OPTV_BOOLEAN, {0}, FALSE },
298    { OPTION_SWCURSOR,	"SWCursor",	OPTV_BOOLEAN, {0}, FALSE },
299    { OPTION_SHADOW_FB,	"ShadowFB",	OPTV_BOOLEAN, {0}, FALSE },
300    { OPTION_ROTATE,	"Rotate",	OPTV_ANYSTR, {0}, FALSE },
301    { OPTION_USEBIOS,	"UseBIOS",	OPTV_BOOLEAN, {0}, FALSE },
302    { OPTION_LCDCLOCK,	"LCDClock",	OPTV_FREQ,    {0}, FALSE },
303    { OPTION_SHADOW_STATUS, "ShadowStatus", OPTV_BOOLEAN, {0}, FALSE },
304    { OPTION_CRT_ONLY,  "CrtOnly",      OPTV_BOOLEAN, {0}, FALSE },
305    { OPTION_TV_ON,     "TvOn",         OPTV_BOOLEAN, {0}, FALSE },
306    { OPTION_TV_PAL,    "PAL",          OPTV_BOOLEAN, {0}, FALSE },
307    { OPTION_FORCE_INIT,"ForceInit",    OPTV_BOOLEAN, {0}, FALSE },
308    { OPTION_OVERLAY,	"Overlay",	OPTV_ANYSTR, {0}, FALSE },
309    { OPTION_T_KEY,	"TransparencyKey",	OPTV_ANYSTR, {0}, FALSE },
310    { OPTION_FORCE_INIT,   "ForceInit",   OPTV_BOOLEAN, {0}, FALSE },
311    { OPTION_DISABLE_XVMC, "DisableXVMC", OPTV_BOOLEAN, {0}, FALSE },
312    { OPTION_DISABLE_TILE, "DisableTile", OPTV_BOOLEAN, {0}, FALSE },
313    { OPTION_DISABLE_COB,  "DisableCOB",  OPTV_BOOLEAN, {0}, FALSE },
314    { OPTION_BCI_FOR_XV,   "BCIforXv",    OPTV_BOOLEAN, {0}, FALSE },
315    { OPTION_DVI,          "DVI",       OPTV_BOOLEAN, {0}, FALSE },
316    { OPTION_IGNORE_EDID,  "IgnoreEDID",  OPTV_BOOLEAN, {0}, FALSE },
317#ifdef XF86DRI
318    { OPTION_BUS_TYPE,	"BusType",	OPTV_ANYSTR,  {0}, FALSE },
319    { OPTION_DMA_TYPE,	"DmaType",	OPTV_ANYSTR,  {0}, FALSE },
320    { OPTION_DMA_MODE,  "DmaMode",	OPTV_ANYSTR,  {0}, FALSE },
321    { OPTION_AGP_MODE,	"AGPMode",	OPTV_INTEGER, {0}, FALSE },
322    { OPTION_AGP_SIZE,	"AGPSize",	OPTV_INTEGER, {0}, FALSE },
323    { OPTION_DRI,       "DRI",          OPTV_BOOLEAN, {0}, TRUE },
324    { OPTION_AGP_FOR_XV,   "AGPforXv",    OPTV_BOOLEAN, {0}, FALSE },
325#endif
326    { -1,		NULL,		OPTV_NONE,    {0}, FALSE }
327};
328
329_X_EXPORT DriverRec SAVAGE =
330{
331    SAVAGE_VERSION,
332    SAVAGE_DRIVER_NAME,
333    SavageIdentify,
334#ifdef XSERVER_LIBPCIACCESS
335    NULL,
336#else
337    SavageProbe,
338#endif
339    SavageAvailableOptions,
340    NULL,
341    0,
342    NULL,
343
344#ifdef XSERVER_LIBPCIACCESS
345    savage_device_match,
346    SavagePciProbe
347#endif
348};
349
350#ifdef XFree86LOADER
351
352static MODULESETUPPROTO(SavageSetup);
353
354static XF86ModuleVersionInfo SavageVersRec = {
355    "savage",
356    MODULEVENDORSTRING,
357    MODINFOSTRING1,
358    MODINFOSTRING2,
359    XORG_VERSION_CURRENT,
360    SAVAGE_VERSION_MAJOR, SAVAGE_VERSION_MINOR, SAVAGE_PATCHLEVEL,
361    ABI_CLASS_VIDEODRV,
362    ABI_VIDEODRV_VERSION,
363    MOD_CLASS_VIDEODRV,
364    {0, 0, 0, 0}
365};
366
367_X_EXPORT XF86ModuleData savageModuleData = {
368    &SavageVersRec,
369    SavageSetup,
370    NULL
371};
372
373static pointer SavageSetup(pointer module, pointer opts, int *errmaj,
374			   int *errmin)
375{
376    static Bool setupDone = FALSE;
377
378    if (!setupDone) {
379	setupDone = TRUE;
380	xf86AddDriver(&SAVAGE, module, 1);
381	return (pointer) 1;
382    } else {
383	if (errmaj)
384	    *errmaj = LDR_ONCEONLY;
385	return NULL;
386    }
387}
388
389#endif /* XFree86LOADER */
390
391static SavageEntPtr SavageEntPriv(ScrnInfoPtr pScrn)
392{
393    DevUnion     *pPriv;
394    SavagePtr  psav   = SAVPTR(pScrn);
395    pPriv = xf86GetEntityPrivate(psav->pEnt->index,
396                                 gSavageEntityIndex);
397    return pPriv->ptr;
398}
399
400
401/*
402 * I'd rather have these wait macros be inline, but S3 has made it
403 * darned near impossible.  The bit fields are in a different place in
404 * all three families, the status register has a different address in the
405 * three families, and even the idle vs busy sense flipped in the Sav2K.
406 */
407
408static void
409ResetBCI2K( SavagePtr psav )
410{
411    CARD32 cob = INREG( 0x48c18 );
412    /* if BCI is enabled and BCI is busy... */
413
414    if(
415	(cob & 0x00000008) &&
416	! (ALT_STATUS_WORD0 & 0x00200000)
417    )
418    {
419	ErrorF( "Resetting BCI, stat = %08lx...\n",
420		(unsigned long) ALT_STATUS_WORD0);
421	/* Turn off BCI */
422	OUTREG( 0x48c18, cob & ~8 );
423	usleep(10000);
424	/* Turn it back on */
425	OUTREG( 0x48c18, cob );
426	usleep(10000);
427    }
428}
429
430static Bool
431ShadowWait( SavagePtr psav )
432{
433    BCI_GET_PTR;
434    int loop = 0;
435
436    if( !psav->NoPCIRetry )
437	return 0;
438
439    psav->ShadowCounter = (psav->ShadowCounter + 1) & 0xffff;
440    if (psav->ShadowCounter == 0)
441	psav->ShadowCounter++; /* 0 is reserved for the BIOS
442				  to avoid confusion in the DRM */
443    BCI_SEND( psav->dwBCIWait2DIdle );
444    BCI_SEND( 0x98000000 + psav->ShadowCounter );
445
446    while(
447	(int)(psav->ShadowVirtual[psav->eventStatusReg] & 0xffff) !=
448	psav->ShadowCounter && (loop++ < MAXLOOP)
449    )
450	;
451
452    return loop >= MAXLOOP;
453}
454
455static Bool
456ShadowWaitQueue( SavagePtr psav, int v )
457{
458    int loop = 0;
459    CARD32 slots = MAXFIFO - v;
460
461    if (slots >= psav->bciThresholdHi)
462	slots = psav->bciThresholdHi;
463    else
464	return ShadowWait( psav );
465
466    /* Savage 2000 reports only entries filled in the COB, not the on-chip
467     * queue. Also it reports in qword units instead of dwords. */
468    if (psav->Chipset == S3_SAVAGE2000)
469	slots = (slots - 32) / 4;
470
471    while( ((psav->ShadowVirtual[0] & psav->bciUsedMask) >= slots) && (loop++ < MAXLOOP))
472	;
473
474    return loop >= MAXLOOP;
475}
476
477/* Wait until "v" queue entries are free */
478
479static int
480WaitQueue3D( SavagePtr psav, int v )
481{
482    int loop = 0;
483    CARD32 slots = MAXFIFO - v;
484
485    mem_barrier();
486    if( psav->ShadowVirtual )
487    {
488	psav->WaitQueue = ShadowWaitQueue;
489	return ShadowWaitQueue(psav, v);
490    }
491    else
492    {
493	loop &= STATUS_WORD0;
494	while( ((STATUS_WORD0 & 0x0000ffff) > slots) && (loop++ < MAXLOOP))
495	    ;
496    }
497    return loop >= MAXLOOP;
498}
499
500static int
501WaitQueue4( SavagePtr psav, int v )
502{
503    int loop = 0;
504    CARD32 slots = MAXFIFO - v;
505
506    if( !psav->NoPCIRetry )
507	return 0;
508    mem_barrier();
509    if( psav->ShadowVirtual )
510    {
511	psav->WaitQueue = ShadowWaitQueue;
512	return ShadowWaitQueue(psav, v);
513    }
514    else
515	while( ((ALT_STATUS_WORD0 & 0x001fffff) > slots) && (loop++ < MAXLOOP));
516    return loop >= MAXLOOP;
517}
518
519static int
520WaitQueue2K( SavagePtr psav, int v )
521{
522    int loop = 0;
523    CARD32 slots = (MAXFIFO - v) / 4;
524
525    if( !psav->NoPCIRetry )
526	return 0;
527    mem_barrier();
528    if( psav->ShadowVirtual )
529    {
530	psav->WaitQueue = ShadowWaitQueue;
531	return ShadowWaitQueue(psav, v);
532    }
533    else
534	while( ((ALT_STATUS_WORD0 & 0x000fffff) > slots) && (loop++ < MAXLOOP))
535	    ;
536    if( loop >= MAXLOOP )
537	ResetBCI2K(psav);
538    return loop >= MAXLOOP;
539}
540
541/* Wait until GP is idle and queue is empty */
542
543static int
544WaitIdleEmpty3D(SavagePtr psav)
545{
546    int loop = 0;
547    mem_barrier();
548    if( psav->ShadowVirtual )
549    {
550	psav->WaitIdleEmpty = ShadowWait;
551	return ShadowWait(psav);
552    }
553    loop &= STATUS_WORD0;
554    while( ((STATUS_WORD0 & 0x0008ffff) != 0x80000) && (loop++ < MAXLOOP) );
555    return loop >= MAXLOOP;
556}
557
558static int
559WaitIdleEmpty4(SavagePtr psav)
560{
561    int loop = 0;
562    mem_barrier();
563    if( psav->ShadowVirtual )
564    {
565	psav->WaitIdleEmpty = ShadowWait;
566	return ShadowWait(psav);
567    }
568	/* which is right?*/
569    /*while( ((ALT_STATUS_WORD0 & 0x00a1ffff) != 0x00a00000) && (loop++ < MAXLOOP) );*/ /* tim */
570    while (((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) && (loop++ < MAXLOOP)); /* S3 */
571    return loop >= MAXLOOP;
572}
573
574static int
575WaitIdleEmpty2K(SavagePtr psav)
576{
577    int loop = 0;
578    mem_barrier();
579    if( psav->ShadowVirtual )
580    {
581	psav->WaitIdleEmpty = ShadowWait;
582	return ShadowWait(psav);
583    }
584    loop &= ALT_STATUS_WORD0;
585    while( ((ALT_STATUS_WORD0 & 0x009fffff) != 0) && (loop++ < MAXLOOP) );
586    if( loop >= MAXLOOP )
587	ResetBCI2K(psav);
588    return loop >= MAXLOOP;
589}
590
591/* Wait until GP is idle */
592
593static int
594WaitIdle3D(SavagePtr psav)
595{
596    int loop = 0;
597    mem_barrier();
598    if( psav->ShadowVirtual )
599    {
600	psav->WaitIdle = ShadowWait;
601	return ShadowWait(psav);
602    }
603    while( (!(STATUS_WORD0 & 0x00080000)) && (loop++ < MAXLOOP) );
604    return loop >= MAXLOOP;
605}
606
607static int
608WaitIdle4(SavagePtr psav)
609{
610    int loop = 0;
611    mem_barrier();
612    if( psav->ShadowVirtual )
613    {
614	psav->WaitIdle = ShadowWait;
615	return ShadowWait(psav);
616    }
617	/* which is right?*/
618    /*while( (!(ALT_STATUS_WORD0 & 0x00800000)) && (loop++ < MAXLOOP) );*/ /* tim */
619    while (((ALT_STATUS_WORD0 & 0x00E00000)!=0x00E00000) && (loop++ < MAXLOOP)); /* S3 */
620    return loop >= MAXLOOP;
621}
622
623static int
624WaitIdle2K(SavagePtr psav)
625{
626    int loop = 0;
627    mem_barrier();
628    if( psav->ShadowVirtual )
629    {
630	psav->WaitIdle = ShadowWait;
631	return ShadowWait(psav);
632    }
633    loop &= ALT_STATUS_WORD0;
634    while( (ALT_STATUS_WORD0 & 0x00900000) && (loop++ < MAXLOOP) );
635    return loop >= MAXLOOP;
636}
637
638
639static Bool SavageGetRec(ScrnInfoPtr pScrn)
640{
641    if (pScrn->driverPrivate)
642	return TRUE;
643
644    pScrn->driverPrivate = xnfcalloc(sizeof(SavageRec), 1);
645    return TRUE;
646}
647
648
649static void SavageFreeRec(ScrnInfoPtr pScrn)
650{
651    TRACE(( "SavageFreeRec(%x)\n", pScrn->driverPrivate ));
652    if (!pScrn->driverPrivate)
653	return;
654    SavageUnmapMem(pScrn, 1);
655    xfree(pScrn->driverPrivate);
656    pScrn->driverPrivate = NULL;
657}
658
659
660static const OptionInfoRec * SavageAvailableOptions(int chipid, int busid)
661{
662    return SavageOptions;
663}
664
665
666static void SavageIdentify(int flags)
667{
668    xf86PrintChipsets("SAVAGE",
669		      "driver (version " SAVAGE_DRIVER_VERSION ") for S3 Savage chipsets",
670		      SavageChips);
671}
672
673
674#ifdef XSERVER_LIBPCIACCESS
675static Bool SavagePciProbe(DriverPtr drv, int entity_num,
676			   struct pci_device *dev, intptr_t match_data)
677{
678    ScrnInfoPtr pScrn;
679
680
681    if ((match_data < S3_SAVAGE3D) || (match_data > S3_SAVAGE2000)) {
682 	return FALSE;
683    }
684
685    pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL,
686				NULL, NULL, NULL, NULL, NULL);
687    if (pScrn != NULL) {
688	EntityInfoPtr pEnt;
689	SavagePtr psav;
690
691
692	pScrn->driverVersion = SAVAGE_VERSION;
693	pScrn->driverName = SAVAGE_DRIVER_NAME;
694	pScrn->name = "SAVAGE";
695	pScrn->Probe = NULL;
696	pScrn->PreInit = SavagePreInit;
697	pScrn->ScreenInit = SavageScreenInit;
698	pScrn->SwitchMode = SavageSwitchMode;
699	pScrn->AdjustFrame = SavageAdjustFrame;
700	pScrn->EnterVT = SavageEnterVT;
701	pScrn->LeaveVT = SavageLeaveVT;
702	pScrn->FreeScreen = NULL;
703	pScrn->ValidMode = SavageValidMode;
704
705	if (!SavageGetRec(pScrn))
706	    return FALSE;
707
708	psav = SAVPTR(pScrn);
709
710	psav->PciInfo = dev;
711	psav->Chipset = match_data;
712
713	pEnt = xf86GetEntityInfo(entity_num);
714
715	/* MX, IX, SuperSavage cards support Dual-Head, mark the entity as
716	 * sharable.
717	 */
718	if (pEnt->chipset == S3_SAVAGE_MX || pEnt->chipset == S3_SUPERSAVAGE) {
719	    DevUnion   *pPriv;
720	    SavageEntPtr pSavageEnt;
721
722	    xf86SetEntitySharable(entity_num);
723
724	    if (gSavageEntityIndex == -1)
725	        gSavageEntityIndex = xf86AllocateEntityPrivateIndex();
726
727	    pPriv = xf86GetEntityPrivate(pEnt->index, gSavageEntityIndex);
728	    if (!pPriv->ptr) {
729		int j;
730		int instance = xf86GetNumEntityInstances(pEnt->index);
731
732		for (j = 0; j < instance; j++)
733		    xf86SetEntityInstanceForScreen(pScrn, pEnt->index, j);
734
735		pPriv->ptr = xnfcalloc(sizeof(SavageEntRec), 1);
736		pSavageEnt = pPriv->ptr;
737		pSavageEnt->HasSecondary = FALSE;
738	    } else {
739		pSavageEnt = pPriv->ptr;
740		pSavageEnt->HasSecondary = TRUE;
741	    }
742	}
743    }
744
745    return (pScrn != NULL);
746}
747
748#else
749
750static Bool SavageProbe(DriverPtr drv, int flags)
751{
752    int i;
753    GDevPtr *devSections = NULL;
754    int *usedChips;
755    int numDevSections;
756    int numUsed;
757    Bool foundScreen = FALSE;
758
759    /* sanity checks */
760    if ((numDevSections = xf86MatchDevice("savage", &devSections)) <= 0)
761	return FALSE;
762    if (xf86GetPciVideoInfo() == NULL) {
763        if (devSections)
764	    xfree(devSections);
765        return FALSE;
766    }
767
768    numUsed = xf86MatchPciInstances("SAVAGE", PCI_VENDOR_S3,
769				    SavageChipsets, SavagePciChipsets,
770				    devSections, numDevSections, drv,
771				    &usedChips);
772    if (devSections)
773	xfree(devSections);
774    devSections = NULL;
775    if (numUsed <= 0)
776	return FALSE;
777
778    if (flags & PROBE_DETECT)
779	foundScreen = TRUE;
780    else
781	for (i=0; i<numUsed; i++) {
782            EntityInfoPtr pEnt = xf86GetEntityInfo(usedChips[i]);;
783            ScrnInfoPtr pScrn = xf86ConfigPciEntity(NULL, 0, usedChips[i],
784						    NULL, RES_SHARED_VGA,
785						    NULL, NULL, NULL, NULL);
786
787            if (pScrn != NULL) {
788		SavagePtr psav;
789
790 	        pScrn->driverVersion = SAVAGE_VERSION;
791	        pScrn->driverName = SAVAGE_DRIVER_NAME;
792	        pScrn->name = "SAVAGE";
793	        pScrn->Probe = SavageProbe;
794	        pScrn->PreInit = SavagePreInit;
795	        pScrn->ScreenInit = SavageScreenInit;
796	        pScrn->SwitchMode = SavageSwitchMode;
797	        pScrn->AdjustFrame = SavageAdjustFrame;
798	        pScrn->EnterVT = SavageEnterVT;
799	        pScrn->LeaveVT = SavageLeaveVT;
800	        pScrn->FreeScreen = NULL;
801	        pScrn->ValidMode = SavageValidMode;
802	        foundScreen = TRUE;
803
804		if (!SavageGetRec(pScrn))
805		    return FALSE;
806
807		psav = SAVPTR(pScrn);
808
809		psav->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
810		if (pEnt->device->chipset && *pEnt->device->chipset) {
811		    psav->Chipset = xf86StringToToken(SavageChipsets,
812						      pEnt->device->chipset);
813		} else if (pEnt->device->chipID >= 0) {
814		    psav->Chipset = LookupChipID(SavagePciChipsets,
815						 pEnt->device->chipID);
816		} else {
817		    psav->Chipset = LookupChipID(SavagePciChipsets,
818						 psav->PciInfo->chipType);
819		}
820	    }
821
822            pEnt = xf86GetEntityInfo(usedChips[i]);
823
824            /* MX, IX, SuperSavage cards support Dual-Head, mark the entity as sharable*/
825            if(pEnt->chipset == S3_SAVAGE_MX || pEnt->chipset == S3_SUPERSAVAGE)
826            {
827		DevUnion   *pPriv;
828		SavageEntPtr pSavageEnt;
829
830		xf86SetEntitySharable(usedChips[i]);
831
832		if (gSavageEntityIndex == -1)
833		    gSavageEntityIndex = xf86AllocateEntityPrivateIndex();
834
835		pPriv = xf86GetEntityPrivate(pEnt->index,
836					     gSavageEntityIndex);
837
838		if (!pPriv->ptr) {
839		    int j;
840		    int instance = xf86GetNumEntityInstances(pEnt->index);
841
842		    for (j = 0; j < instance; j++)
843			xf86SetEntityInstanceForScreen(pScrn, pEnt->index, j);
844
845		    pPriv->ptr = xnfcalloc(sizeof(SavageEntRec), 1);
846		    pSavageEnt = pPriv->ptr;
847		    pSavageEnt->HasSecondary = FALSE;
848		} else {
849		    pSavageEnt = pPriv->ptr;
850		    pSavageEnt->HasSecondary = TRUE;
851		}
852	    }
853	    xfree(pEnt);
854	}
855
856
857    xfree(usedChips);
858    return foundScreen;
859}
860
861static int LookupChipID( PciChipsets* pset, int ChipID )
862{
863    /* Is there a function to do this for me? */
864    while( pset->numChipset >= 0 )
865    {
866        if( pset->PCIid == ChipID )
867	    return pset->numChipset;
868	pset++;
869    }
870
871    return -1;
872}
873#endif
874
875static void SavageDoDDC(ScrnInfoPtr pScrn)
876{
877    SavagePtr psav= SAVPTR(pScrn);
878    pointer ddc;
879
880    /* Do the DDC dance. */ /* S3/VIA's DDC code */
881    ddc = xf86LoadSubModule(pScrn, "ddc");
882    if (ddc) {
883        switch( psav->Chipset ) {
884            case S3_SAVAGE3D:
885            case S3_SAVAGE_MX:
886            case S3_SUPERSAVAGE:
887	    case S3_SAVAGE2000:
888		psav->DDCPort = 0xAA;
889                psav->I2CPort = 0xA0;
890                break;
891
892            case S3_SAVAGE4:
893            case S3_PROSAVAGE:
894            case S3_TWISTER:
895            case S3_PROSAVAGEDDR:
896                psav->DDCPort = 0xB1;
897                psav->I2CPort = 0xA0;
898                break;
899        }
900
901        if (!SavageDDC1(pScrn->scrnIndex)) {
902            /* DDC1 failed,switch to DDC2 */
903            if (xf86LoadSubModule(pScrn, "i2c")) {
904                if (SavageI2CInit(pScrn)) {
905                    unsigned char tmp;
906                    xf86MonPtr pMon;
907
908                    InI2CREG(tmp,psav->DDCPort);
909                    OutI2CREG(tmp | 0x13,psav->DDCPort);
910                    pMon = xf86PrintEDID(xf86DoEDID_DDC2(pScrn->scrnIndex,psav->I2C));
911                    if (!psav->IgnoreEDID) xf86SetDDCproperties(pScrn, pMon);
912                    OutI2CREG(tmp,psav->DDCPort);
913                }
914            }
915        }
916    }
917}
918
919/* Copied from ddc/Property.c via nv */
920static DisplayModePtr
921SavageModesAdd(DisplayModePtr Modes, DisplayModePtr Additions)
922{
923    if (!Modes) {
924        if (Additions)
925            return Additions;
926        else
927            return NULL;
928    }
929
930    if (Additions) {
931        DisplayModePtr Mode = Modes;
932
933        while (Mode->next)
934            Mode = Mode->next;
935
936        Mode->next = Additions;
937        Additions->prev = Mode;
938    }
939
940    return Modes;
941}
942
943/* borrowed from nv */
944static void
945SavageAddPanelMode(ScrnInfoPtr pScrn)
946{
947    SavagePtr psav= SAVPTR(pScrn);
948    DisplayModePtr  Mode  = NULL;
949
950    Mode = xf86CVTMode(psav->PanelX, psav->PanelY, 60.00, TRUE, FALSE);
951    Mode->type = M_T_DRIVER | M_T_PREFERRED;
952    pScrn->monitor->Modes = SavageModesAdd(pScrn->monitor->Modes, Mode);
953
954    if ((pScrn->monitor->nHsync == 0) &&
955        (pScrn->monitor->nVrefresh == 0)) {
956	if (!Mode->HSync)
957	    Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal);
958	if (!Mode->VRefresh)
959	    Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) /
960		((float) (Mode->HTotal * Mode->VTotal));
961
962	if (Mode->HSync < pScrn->monitor->hsync[0].lo)
963	    pScrn->monitor->hsync[0].lo = Mode->HSync;
964	if (Mode->HSync > pScrn->monitor->hsync[0].hi)
965	    pScrn->monitor->hsync[0].hi = Mode->HSync;
966	if (Mode->VRefresh < pScrn->monitor->vrefresh[0].lo)
967	    pScrn->monitor->vrefresh[0].lo = Mode->VRefresh;
968	if (Mode->VRefresh > pScrn->monitor->vrefresh[0].hi)
969	    pScrn->monitor->vrefresh[0].hi = Mode->VRefresh;
970
971	pScrn->monitor->nHsync = 1;
972	pScrn->monitor->nVrefresh = 1;
973    }
974}
975
976static void SavageGetPanelInfo(ScrnInfoPtr pScrn)
977{
978    SavagePtr psav= SAVPTR(pScrn);
979    vgaHWPtr hwp;
980    unsigned char cr6b;
981    int panelX, panelY;
982    char * sTechnology = "Unknown";
983    enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
984	ActiveCRT = 0x01,
985	ActiveLCD = 0x02,
986	ActiveTV = 0x04,
987	ActiveCRT2 = 0x20,
988	ActiveDUO = 0x80
989    };
990
991    hwp = VGAHWPTR(pScrn);
992
993    /* Check LCD panel information */
994
995    cr6b = hwp->readCrtc( hwp, 0x6b );
996
997    panelX = (hwp->readSeq(hwp, 0x61) +
998	    ((hwp->readSeq(hwp, 0x66) & 0x02) << 7) + 1) * 8;
999    panelY = hwp->readSeq(hwp, 0x69) +
1000	    ((hwp->readSeq(hwp, 0x6e) & 0x70) << 4) + 1;
1001
1002
1003	/* OK, I admit it.  I don't know how to limit the max dot clock
1004	 * for LCD panels of various sizes.  I thought I copied the formula
1005	 * from the BIOS, but many users have informed me of my folly.
1006	 *
1007	 * Instead, I'll abandon any attempt to automatically limit the
1008	 * clock, and add an LCDClock option to XF86Config.  Some day,
1009	 * I should come back to this.
1010	 */
1011
1012
1013    if( (hwp->readSeq( hwp, 0x39 ) & 0x03) == 0 )
1014    {
1015	sTechnology = "TFT";
1016    }
1017    else if( (hwp->readSeq( hwp, 0x30 ) & 0x01) == 0 )
1018    {
1019	sTechnology = "DSTN";
1020    }
1021    else
1022    {
1023	sTechnology = "STN";
1024    }
1025
1026    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1027		   "%dx%d %s LCD panel detected %s\n",
1028		   panelX, panelY, sTechnology,
1029		   cr6b & ActiveLCD ? "and active" : "but not active");
1030
1031    if( cr6b & ActiveLCD ) {
1032	    /* If the LCD is active and panel expansion is enabled, */
1033	    /* we probably want to kill the HW cursor. */
1034
1035	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1036		       "- Limiting video mode to %dx%d\n",
1037		       panelX, panelY );
1038
1039	psav->PanelX = panelX;
1040	psav->PanelY = panelY;
1041
1042	do {
1043	    DisplayModePtr native = xf86CVTMode(panelX, panelY, 60.0, 0, 0);
1044	    if (!native)
1045		break;
1046
1047	    if (!pScrn->monitor->nHsync) {
1048		pScrn->monitor->nHsync = 1;
1049		pScrn->monitor->hsync[0].lo = 31.5;
1050		pScrn->monitor->hsync[0].hi = (float)native->Clock /
1051					      (float)native->HTotal;
1052	    }
1053	    if (!pScrn->monitor->nVrefresh) {
1054		pScrn->monitor->nVrefresh = 1;
1055		pScrn->monitor->vrefresh[0].lo = 56.0;
1056		pScrn->monitor->vrefresh[0].hi = (float)native->Clock * 1000.0 /
1057						 (float)native->HTotal /
1058						 (float)native->VTotal;
1059	    }
1060	    if (!pScrn->monitor->maxPixClock)
1061		pScrn->monitor->maxPixClock = native->Clock;
1062
1063	    xfree(native);
1064	} while (0);
1065
1066	if( psav->LCDClock > 0.0 )
1067	{
1068	    psav->maxClock = psav->LCDClock * 1000.0;
1069	    xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1070			    "- Limiting dot clock to %1.2f MHz\n",
1071			    psav->LCDClock );
1072	}
1073    } else {
1074        psav->DisplayType = MT_CRT;
1075    }
1076}
1077
1078
1079static Bool SavagePreInit(ScrnInfoPtr pScrn, int flags)
1080{
1081    EntityInfoPtr pEnt;
1082    SavagePtr psav;
1083    MessageType from = X_DEFAULT;
1084    int i;
1085    ClockRangePtr clockRanges;
1086    char *s = NULL;
1087    unsigned char config1, m, n, n1, n2, sr8, cr66 = 0, tmp;
1088    int mclk;
1089    vgaHWPtr hwp;
1090    int vgaCRIndex, vgaCRReg;
1091    Bool dvi;
1092
1093    TRACE(("SavagePreInit(%d)\n", flags));
1094
1095    gpScrn = pScrn;
1096
1097    if (flags & PROBE_DETECT) {
1098	SavageProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
1099	return TRUE;
1100    }
1101
1102    if (!xf86LoadSubModule(pScrn, "vgahw"))
1103	return FALSE;
1104
1105    if (!vgaHWGetHWRec(pScrn))
1106	return FALSE;
1107
1108#if 0
1109    /* Here we can alter the number of registers saved and restored by the
1110     * standard vgaHWSave and Restore routines.
1111     */
1112    vgaHWSetRegCounts( pScrn, VGA_NUM_CRTC, VGA_NUM_SEQ, VGA_NUM_GFX, VGA_NUM_ATTR );
1113#endif
1114
1115    pScrn->monitor = pScrn->confScreen->monitor;
1116
1117    /*
1118     * We support depths of 8, 15, 16 and 24.
1119     * We support bpp of 8, 16, and 32.
1120     */
1121
1122    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb))
1123	return FALSE;
1124    else {
1125        int requiredBpp;
1126	int altBpp = 0;
1127
1128	switch (pScrn->depth) {
1129	case 8:
1130	case 16:
1131	    requiredBpp = pScrn->depth;
1132	    break;
1133	case 15:
1134	    requiredBpp = 16;
1135	    break;
1136	case 24:
1137	    requiredBpp = 32;
1138	    altBpp = 24;
1139	    break;
1140
1141	default:
1142	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1143		       "Given depth (%d) is not supported by this driver\n",
1144			pScrn->depth);
1145	    return FALSE;
1146	}
1147
1148	if(
1149	    (pScrn->bitsPerPixel != requiredBpp) &&
1150	    (pScrn->bitsPerPixel != altBpp)
1151	) {
1152	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1153		       "Depth %d must specify %d bpp; %d was given\n",
1154		       pScrn->depth, requiredBpp, pScrn->bitsPerPixel );
1155	    return FALSE;
1156	}
1157    }
1158
1159    xf86PrintDepthBpp(pScrn);
1160
1161    if (pScrn->depth > 8) {
1162	rgb zeros = {0, 0, 0};
1163
1164	if (!xf86SetWeight(pScrn, zeros, zeros))
1165	    return FALSE;
1166	else {
1167	    /* TODO check weight returned is supported */
1168	    ;
1169	}
1170    }
1171
1172    if (!xf86SetDefaultVisual(pScrn, -1)) {
1173	return FALSE;
1174    } else {
1175	/* We don't currently support DirectColor at 16bpp */
1176	if (pScrn->bitsPerPixel == 16 && pScrn->defaultVisual != TrueColor) {
1177	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
1178		       " (%s) is not supported at depth %d\n",
1179		       xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
1180	    return FALSE;
1181	}
1182    }
1183
1184    pScrn->progClock = TRUE;
1185
1186    if (!SavageGetRec(pScrn))
1187	return FALSE;
1188    psav = SAVPTR(pScrn);
1189
1190    hwp = VGAHWPTR(pScrn);
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 = xalloc(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	xfree(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    xfree(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 XF86DRI
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 XF86DRI
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 XF86DRI
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	    	SavageFreeRec(pScrn);
2167	    	vbeFree(psav->pVbe);
2168	    	psav->pVbe = NULL;
2169	    	return FALSE;
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(int scrnIndex, int flags)
2200{
2201    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2202#ifdef XF86DRI
2203    SavagePtr psav= SAVPTR(pScrn);
2204    ScreenPtr pScreen;
2205    SAVAGESAREAPrivPtr pSAREAPriv;
2206#endif
2207
2208    TRACE(("SavageEnterVT(%d)\n", flags));
2209
2210    gpScrn = pScrn;
2211    SavageEnableMMIO(pScrn);
2212
2213#ifdef XF86DRI
2214    if (psav->directRenderingEnabled) {
2215        pScreen = screenInfo.screens[scrnIndex];
2216	pSAREAPriv = (SAVAGESAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
2217	/* Assume that 3D state was clobbered, invalidate it by
2218	 * changing ctxOwner in the sarea. */
2219	pSAREAPriv->ctxOwner = DRIGetContext(pScreen);
2220        DRIUnlock(pScreen);
2221        psav->LockHeld = 0;
2222    }
2223#endif
2224    if (!SAVPTR(pScrn)->IsSecondary)
2225    	SavageSave(pScrn);
2226    if(SavageModeInit(pScrn, pScrn->currentMode)) {
2227	/* some BIOSes seem to enable HW cursor on PM resume */
2228	if (!SAVPTR(pScrn)->hwc_on)
2229	    SavageHideCursor( pScrn );
2230	return TRUE;
2231    }
2232
2233    return FALSE;
2234}
2235
2236
2237static void SavageLeaveVT(int scrnIndex, int flags)
2238{
2239    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2240    vgaHWPtr hwp = VGAHWPTR(pScrn);
2241    SavagePtr psav = SAVPTR(pScrn);
2242    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
2243    SavageRegPtr SavageSavePtr = &psav->SavedReg;
2244#ifdef XF86DRI
2245    ScreenPtr pScreen;
2246#endif
2247
2248    TRACE(("SavageLeaveVT(%d)\n", flags));
2249    gpScrn = pScrn;
2250
2251#ifdef XF86DRI
2252    if (psav->directRenderingEnabled) {
2253        pScreen = screenInfo.screens[scrnIndex];
2254        DRILock(pScreen, 0);
2255        psav->LockHeld = 1;
2256    }
2257#endif
2258    if (psav->FBStart2nd || (psav->videoFlags & VF_STREAMS_ON))
2259        SavageStreamsOff(pScrn);
2260    SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
2261    SavageResetStreams(pScrn);
2262    SavageDisableMMIO(pScrn);
2263
2264}
2265
2266
2267static void SavageSave(ScrnInfoPtr pScrn)
2268{
2269    unsigned char cr3a, cr53, cr66;
2270    vgaHWPtr hwp = VGAHWPTR(pScrn);
2271    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
2272    SavagePtr psav = SAVPTR(pScrn);
2273    SavageRegPtr save = &psav->SavedReg;
2274    unsigned short vgaCRReg = psav->vgaIOBase + 5;
2275    unsigned short vgaCRIndex = psav->vgaIOBase + 4;
2276
2277    TRACE(("SavageSave()\n"));
2278
2279    VGAOUT16(vgaCRIndex, 0x4838);
2280    VGAOUT16(vgaCRIndex, 0xa039);
2281    VGAOUT16(0x3c4, 0x0608);
2282
2283    VGAOUT8(vgaCRIndex, 0x66);
2284    cr66 = VGAIN8(vgaCRReg);
2285    VGAOUT8(vgaCRReg, cr66 | 0x80);
2286    VGAOUT8(vgaCRIndex, 0x3a);
2287    cr3a = VGAIN8(vgaCRReg);
2288    VGAOUT8(vgaCRReg, cr3a | 0x80);
2289    VGAOUT8(vgaCRIndex, 0x53);
2290    cr53 = VGAIN8(vgaCRReg);
2291    VGAOUT8(vgaCRReg, cr53 & 0x7f);
2292
2293    if (xf86IsPrimaryPci(psav->PciInfo))
2294	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
2295    else
2296	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_MODE);
2297
2298    VGAOUT8(vgaCRIndex, 0x66);
2299    VGAOUT8(vgaCRReg, cr66);
2300    VGAOUT8(vgaCRIndex, 0x3a);
2301    VGAOUT8(vgaCRReg, cr3a);
2302
2303    VGAOUT8(vgaCRIndex, 0x66);
2304    VGAOUT8(vgaCRReg, cr66);
2305    VGAOUT8(vgaCRIndex, 0x3a);
2306    VGAOUT8(vgaCRReg, cr3a);
2307
2308    /* unlock extended seq regs */
2309    VGAOUT8(0x3c4, 0x08);
2310    save->SR08 = VGAIN8(0x3c5);
2311    VGAOUT8(0x3c5, 0x06);
2312
2313    /* now save all the extended regs we need */
2314    VGAOUT8(vgaCRIndex, 0x31);
2315    save->CR31 = VGAIN8(vgaCRReg);
2316    VGAOUT8(vgaCRIndex, 0x32);
2317    save->CR32 = VGAIN8(vgaCRReg);
2318    VGAOUT8(vgaCRIndex, 0x34);
2319    save->CR34 = VGAIN8(vgaCRReg);
2320    VGAOUT8(vgaCRIndex, 0x36);
2321    save->CR36 = VGAIN8(vgaCRReg);
2322    VGAOUT8(vgaCRIndex, 0x3a);
2323    save->CR3A = VGAIN8(vgaCRReg);
2324    VGAOUT8(vgaCRIndex, 0x40);
2325    save->CR40 = VGAIN8(vgaCRReg);
2326    VGAOUT8(vgaCRIndex, 0x42);
2327    save->CR42 = VGAIN8(vgaCRReg);
2328    VGAOUT8(vgaCRIndex, 0x45);
2329    save->CR45 = VGAIN8(vgaCRReg);
2330    VGAOUT8(vgaCRIndex, 0x50);
2331    save->CR50 = VGAIN8(vgaCRReg);
2332    VGAOUT8(vgaCRIndex, 0x51);
2333    save->CR51 = VGAIN8(vgaCRReg);
2334    VGAOUT8(vgaCRIndex, 0x53);
2335    save->CR53 = VGAIN8(vgaCRReg);
2336    VGAOUT8(vgaCRIndex, 0x58);
2337    save->CR58 = VGAIN8(vgaCRReg);
2338    VGAOUT8(vgaCRIndex, 0x60);
2339    save->CR60 = VGAIN8(vgaCRReg);
2340    VGAOUT8(vgaCRIndex, 0x66);
2341    save->CR66 = VGAIN8(vgaCRReg);
2342    VGAOUT8(vgaCRIndex, 0x67);
2343    save->CR67 = VGAIN8(vgaCRReg);
2344    VGAOUT8(vgaCRIndex, 0x68);
2345    save->CR68 = VGAIN8(vgaCRReg);
2346    VGAOUT8(vgaCRIndex, 0x69);
2347    save->CR69 = VGAIN8(vgaCRReg);
2348    VGAOUT8(vgaCRIndex, 0x6f);
2349    save->CR6F = VGAIN8(vgaCRReg);
2350
2351    VGAOUT8(vgaCRIndex, 0x33);
2352    save->CR33 = VGAIN8(vgaCRReg);
2353    VGAOUT8(vgaCRIndex, 0x86);
2354    save->CR86 = VGAIN8(vgaCRReg);
2355    VGAOUT8(vgaCRIndex, 0x88);
2356    save->CR88 = VGAIN8(vgaCRReg);
2357    VGAOUT8(vgaCRIndex, 0x90);
2358    save->CR90 = VGAIN8(vgaCRReg);
2359    VGAOUT8(vgaCRIndex, 0x91);
2360    save->CR91 = VGAIN8(vgaCRReg);
2361    VGAOUT8(vgaCRIndex, 0xb0);
2362    save->CRB0 = VGAIN8(vgaCRReg) | 0x80;
2363
2364    /* extended mode timing regs */
2365    VGAOUT8(vgaCRIndex, 0x3b);
2366    save->CR3B = VGAIN8(vgaCRReg);
2367    VGAOUT8(vgaCRIndex, 0x3c);
2368    save->CR3C = VGAIN8(vgaCRReg);
2369    VGAOUT8(vgaCRIndex, 0x43);
2370    save->CR43 = VGAIN8(vgaCRReg);
2371    VGAOUT8(vgaCRIndex, 0x5d);
2372    save->CR5D = VGAIN8(vgaCRReg);
2373    VGAOUT8(vgaCRIndex, 0x5e);
2374    save->CR5E = VGAIN8(vgaCRReg);
2375    VGAOUT8(vgaCRIndex, 0x65);
2376    save->CR65 = VGAIN8(vgaCRReg);
2377
2378    /* save seq extended regs for DCLK PLL programming */
2379    VGAOUT8(0x3c4, 0x0e);
2380    save->SR0E = VGAIN8(0x3c5);
2381    VGAOUT8(0x3c4, 0x0f);
2382    save->SR0F = VGAIN8(0x3c5);
2383    VGAOUT8(0x3c4, 0x10);
2384    save->SR10 = VGAIN8(0x3c5);
2385    VGAOUT8(0x3c4, 0x11);
2386    save->SR11 = VGAIN8(0x3c5);
2387    VGAOUT8(0x3c4, 0x12);
2388    save->SR12 = VGAIN8(0x3c5);
2389    VGAOUT8(0x3c4, 0x13);
2390    save->SR13 = VGAIN8(0x3c5);
2391    VGAOUT8(0x3c4, 0x29);
2392    save->SR29 = VGAIN8(0x3c5);
2393
2394    VGAOUT8(0x3c4, 0x15);
2395    save->SR15 = VGAIN8(0x3c5);
2396    VGAOUT8(0x3c4, 0x30);
2397    save->SR30 = VGAIN8(0x3c5);
2398    VGAOUT8(0x3c4, 0x18);
2399    save->SR18 = VGAIN8(0x3c5);
2400    VGAOUT8(0x3c4, 0x1b);
2401    save->SR1B = VGAIN8(0x3c5);
2402
2403    /* Save flat panel expansion registers. */
2404
2405    if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
2406	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) {
2407	int i;
2408	for( i = 0; i < 8; i++ ) {
2409	    VGAOUT8(0x3c4, 0x54+i);
2410	    save->SR54[i] = VGAIN8(0x3c5);
2411	}
2412    }
2413
2414    VGAOUT8(vgaCRIndex, 0x66);
2415    cr66 = VGAIN8(vgaCRReg);
2416    VGAOUT8(vgaCRReg, cr66 | 0x80);
2417    VGAOUT8(vgaCRIndex, 0x3a);
2418    cr3a = VGAIN8(vgaCRReg);
2419    VGAOUT8(vgaCRReg, cr3a | 0x80);
2420
2421    /* now save MIU regs */
2422    if( ! S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
2423	save->MMPR0 = INREG(FIFO_CONTROL_REG);
2424	save->MMPR1 = INREG(MIU_CONTROL_REG);
2425	save->MMPR2 = INREG(STREAMS_TIMEOUT_REG);
2426	save->MMPR3 = INREG(MISC_TIMEOUT_REG);
2427    }
2428
2429    VGAOUT8(vgaCRIndex, 0x3a);
2430    VGAOUT8(vgaCRReg, cr3a);
2431    VGAOUT8(vgaCRIndex, 0x66);
2432    VGAOUT8(vgaCRReg, cr66);
2433
2434    if (!psav->ModeStructInit) {
2435	vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr);
2436	memcpy(&psav->ModeReg, save, sizeof(SavageRegRec));
2437	psav->ModeStructInit = TRUE;
2438    }
2439
2440#if 0
2441    if (xf86GetVerbosity() > 1)
2442	SavagePrintRegs(pScrn);
2443#endif
2444
2445    return;
2446}
2447
2448
2449static void SavageWriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr,
2450			    SavageRegPtr restore, Bool Entering)
2451{
2452    unsigned char tmp, cr3a, cr66;
2453    vgaHWPtr hwp = VGAHWPTR(pScrn);
2454    SavagePtr psav = SAVPTR(pScrn);
2455    int vgaCRIndex, vgaCRReg, vgaIOBase;
2456
2457
2458    vgaIOBase = hwp->IOBase;
2459    vgaCRIndex = vgaIOBase + 4;
2460    vgaCRReg = vgaIOBase + 5;
2461
2462    TRACE(("SavageWriteMode(%x)\n", restore->mode));
2463
2464#ifdef XF86DRI
2465    if (psav->directRenderingEnabled) {
2466        DRILock(screenInfo.screens[pScrn->scrnIndex], 0);
2467        psav->LockHeld = 1;
2468    }
2469#endif
2470
2471    if (psav->IsSecondary) {
2472	/* Set up the mode.  Don't clear video RAM. */
2473	SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
2474	SavageSetGBD(pScrn);
2475	return;
2476    }
2477
2478    if( Entering &&
2479	(!S3_SAVAGE_MOBILE_SERIES(psav->Chipset) || (psav->ForceInit))
2480    )
2481	SavageInitialize2DEngine(pScrn);
2482
2483    /*
2484     * If we figured out a VESA mode number for this timing, just use
2485     * the S3 BIOS to do the switching, with a few additional tweaks.
2486     */
2487
2488    if( psav->UseBIOS && restore->mode > 0x13 )
2489    {
2490	int width;
2491	unsigned short cr6d;
2492	unsigned short cr79 = 0;
2493
2494	/* Set up the mode.  Don't clear video RAM. */
2495	SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
2496
2497	/* Restore the DAC. */
2498	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP);
2499
2500	/* Unlock the extended registers. */
2501
2502#if 0
2503	/* Which way is better? */
2504	hwp->writeCrtc( hwp, 0x38, 0x48 );
2505	hwp->writeCrtc( hwp, 0x39, 0xa0 );
2506	hwp->writeSeq( hwp, 0x08, 0x06 );
2507#endif
2508
2509	VGAOUT16(vgaCRIndex, 0x4838);
2510	VGAOUT16(vgaCRIndex, 0xA039);
2511	VGAOUT16(0x3c4, 0x0608);
2512
2513	/* Enable linear addressing. */
2514
2515	VGAOUT16(vgaCRIndex, 0x1358);
2516
2517	/* Disable old MMIO. */
2518
2519	VGAOUT8(vgaCRIndex, 0x53);
2520	VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & ~0x10);
2521
2522	/* Disable HW cursor */
2523
2524	VGAOUT16(vgaCRIndex, 0x0045);
2525
2526	/* Set the color mode. */
2527
2528	VGAOUT8(vgaCRIndex, 0x67);
2529	VGAOUT8(vgaCRReg, restore->CR67);
2530
2531	/* Enable gamma correction, set CLUT to 8 bit */
2532
2533	VGAOUT8(0x3c4, 0x1b);
2534	if( (pScrn->bitsPerPixel == 32) && !psav->DGAactive
2535	    && ! psav->FBStart2nd )
2536		VGAOUT8(0x3c5, 0x18 );
2537	else
2538		VGAOUT8(0x3c5, 0x10 );
2539
2540	/* We may need TV/panel fixups here.  See s3bios.c line 2904. */
2541
2542	/* Set FIFO fetch delay. */
2543	VGAOUT8(vgaCRIndex, 0x85);
2544	VGAOUT8(vgaCRReg, (VGAIN8(vgaCRReg) & 0xf8) | 0x03);
2545
2546	/* Patch CR79.  These values are magical. */
2547
2548	if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
2549	{
2550	    VGAOUT8(vgaCRIndex, 0x6d);
2551	    cr6d = VGAIN8(vgaCRReg);
2552
2553	    cr79 = 0x04;
2554
2555	    if( pScrn->displayWidth >= 1024 )
2556	    {
2557		if(psav->primStreamBpp == 32 )
2558		{
2559		    if( restore->refresh >= 130 )
2560			cr79 = 0x03;
2561		    else if( pScrn->displayWidth >= 1280 )
2562			cr79 = 0x02;
2563		    else if(
2564			(pScrn->displayWidth == 1024) &&
2565			(restore->refresh >= 75)
2566		    )
2567		    {
2568			if( cr6d && LCD_ACTIVE )
2569			    cr79 = 0x05;
2570			else
2571			    cr79 = 0x08;
2572		    }
2573		}
2574		else if( psav->primStreamBpp == 16)
2575		{
2576
2577/* The windows driver uses 0x13 for 16-bit 130Hz, but I see terrible
2578 * screen artifacts with that value.  Let's keep it low for now.
2579 *		if( restore->refresh >= 130 )
2580 *		    cr79 = 0x13;
2581 *		else
2582 */
2583		    if( pScrn->displayWidth == 1024 )
2584		    {
2585			if( cr6d && LCD_ACTIVE )
2586			    cr79 = 0x08;
2587			else
2588			    cr79 = 0x0e;
2589		    }
2590		}
2591	    }
2592	}
2593
2594        if( (psav->Chipset != S3_SAVAGE2000) &&
2595	    !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
2596	    VGAOUT16(vgaCRIndex, (cr79 << 8) | 0x79);
2597
2598	/* Make sure 16-bit memory access is enabled. */
2599
2600	VGAOUT16(vgaCRIndex, 0x0c31);
2601
2602	/* Enable the graphics engine. */
2603
2604	VGAOUT16(vgaCRIndex, 0x0140);
2605
2606	/* Handle the pitch. */
2607
2608        VGAOUT8(vgaCRIndex, 0x50);
2609        VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
2610
2611	width = (pScrn->displayWidth * (psav->primStreamBpp / 8)) >> 3;
2612	VGAOUT16(vgaCRIndex, ((width & 0xff) << 8) | 0x13 );
2613	VGAOUT16(vgaCRIndex, ((width & 0x300) << 4) | 0x51 );
2614
2615	/* Some non-S3 BIOSes enable block write even on non-SGRAM devices. */
2616
2617	switch( psav->Chipset )
2618	{
2619	    case S3_SAVAGE2000:
2620		VGAOUT8(vgaCRIndex, 0x73);
2621		VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & 0xdf );
2622		break;
2623
2624	    case S3_SAVAGE3D:
2625	    case S3_SAVAGE4:
2626		VGAOUT8(vgaCRIndex, 0x68);
2627		if( !(VGAIN8(vgaCRReg) & 0x80) )
2628		{
2629		    /* Not SGRAM; disable block write. */
2630		    VGAOUT8(vgaCRIndex, 0x88);
2631		    VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0x10);
2632		}
2633		break;
2634	}
2635
2636	/* set the correct clock for some BIOSes */
2637	VGAOUT8(VGA_MISC_OUT_W,
2638		VGAIN8(VGA_MISC_OUT_R) | 0x0C);
2639	/* Some BIOSes turn on clock doubling on non-doubled modes */
2640	if (pScrn->bitsPerPixel < 24) {
2641	    VGAOUT8(vgaCRIndex, 0x67);
2642	    if (!(VGAIN8(vgaCRReg) & 0x10)) {
2643		VGAOUT8(0x3c4, 0x15);
2644		VGAOUT8(0x3c5, VGAIN8(0x3C5) & ~0x10);
2645		VGAOUT8(0x3c4, 0x18);
2646		VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x80);
2647	    }
2648	}
2649
2650	SavageInitialize2DEngine(pScrn);
2651
2652	VGAOUT16(vgaCRIndex, 0x0140);
2653
2654	SavageSetGBD(pScrn);
2655
2656
2657#ifdef XF86DRI
2658    	if (psav->directRenderingEnabled)
2659    	    DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
2660    	psav->LockHeld = 0;
2661#endif
2662
2663	return;
2664    }
2665
2666    VGAOUT8(0x3c2, 0x23);
2667    VGAOUT16(vgaCRIndex, 0x4838);
2668    VGAOUT16(vgaCRIndex, 0xa039);
2669    VGAOUT16(0x3c4, 0x0608);
2670
2671    vgaHWProtect(pScrn, TRUE);
2672
2673    /* will we be reenabling STREAMS for the new mode? */
2674    psav->STREAMSRunning = 0;
2675
2676    /* reset GE to make sure nothing is going on */
2677    VGAOUT8(vgaCRIndex, 0x66);
2678    if(VGAIN8(vgaCRReg) & 0x01)
2679	SavageGEReset(pScrn,0,__LINE__,__FILE__);
2680
2681    /*
2682     * Some Savage/MX and /IX systems go nuts when trying to exit the
2683     * server after WindowMaker has displayed a gradient background.  I
2684     * haven't been able to find what causes it, but a non-destructive
2685     * switch to mode 3 here seems to eliminate the issue.
2686     */
2687
2688    if( ((restore->CR31 & 0x0a) == 0) && psav->pVbe ) {
2689	SavageSetTextMode( psav );
2690    }
2691
2692    VGAOUT8(vgaCRIndex, 0x67);
2693    (void) VGAIN8(vgaCRReg);
2694    /*VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c);*/ /* no STREAMS yet */
2695    VGAOUT8(vgaCRReg, restore->CR67 & ~0x0e); /* no STREAMS yet old and new */
2696
2697    /* restore extended regs */
2698    VGAOUT8(vgaCRIndex, 0x66);
2699    VGAOUT8(vgaCRReg, restore->CR66);
2700    VGAOUT8(vgaCRIndex, 0x3a);
2701    VGAOUT8(vgaCRReg, restore->CR3A);
2702    VGAOUT8(vgaCRIndex, 0x31);
2703    VGAOUT8(vgaCRReg, restore->CR31);
2704    VGAOUT8(vgaCRIndex, 0x32);
2705    VGAOUT8(vgaCRReg, restore->CR32);
2706    VGAOUT8(vgaCRIndex, 0x58);
2707    VGAOUT8(vgaCRReg, restore->CR58);
2708    VGAOUT8(vgaCRIndex, 0x53);
2709    VGAOUT8(vgaCRReg, restore->CR53 & 0x7f);
2710
2711    VGAOUT16(0x3c4, 0x0608);
2712
2713    /* Restore DCLK registers. */
2714
2715    VGAOUT8(0x3c4, 0x0e);
2716    VGAOUT8(0x3c5, restore->SR0E);
2717    VGAOUT8(0x3c4, 0x0f);
2718    VGAOUT8(0x3c5, restore->SR0F);
2719    VGAOUT8(0x3c4, 0x29);
2720    VGAOUT8(0x3c5, restore->SR29);
2721    VGAOUT8(0x3c4, 0x15);
2722    VGAOUT8(0x3c5, restore->SR15);
2723
2724    /* Restore flat panel expansion registers. */
2725    if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
2726	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) {
2727	int i;
2728	for( i = 0; i < 8; i++ ) {
2729	    VGAOUT8(0x3c4, 0x54+i);
2730	    VGAOUT8(0x3c5, restore->SR54[i]);
2731	}
2732    }
2733
2734    /* restore the standard vga regs */
2735    if (xf86IsPrimaryPci(psav->PciInfo))
2736	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
2737    else
2738	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE);
2739
2740    /* extended mode timing registers */
2741    VGAOUT8(vgaCRIndex, 0x53);
2742    VGAOUT8(vgaCRReg, restore->CR53);
2743    VGAOUT8(vgaCRIndex, 0x5d);
2744    VGAOUT8(vgaCRReg, restore->CR5D);
2745    VGAOUT8(vgaCRIndex, 0x5e);
2746    VGAOUT8(vgaCRReg, restore->CR5E);
2747    VGAOUT8(vgaCRIndex, 0x3b);
2748    VGAOUT8(vgaCRReg, restore->CR3B);
2749    VGAOUT8(vgaCRIndex, 0x3c);
2750    VGAOUT8(vgaCRReg, restore->CR3C);
2751    VGAOUT8(vgaCRIndex, 0x43);
2752    VGAOUT8(vgaCRReg, restore->CR43);
2753    VGAOUT8(vgaCRIndex, 0x65);
2754    VGAOUT8(vgaCRReg, restore->CR65);
2755
2756    /* restore the desired video mode with cr67 */
2757    VGAOUT8(vgaCRIndex, 0x67);
2758    /*VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c);*/ /* no STREAMS yet */
2759    VGAOUT8(vgaCRReg, restore->CR67 & ~0x0e); /* no streams for new and old streams engines */
2760
2761    /* other mode timing and extended regs */
2762    VGAOUT8(vgaCRIndex, 0x34);
2763    VGAOUT8(vgaCRReg, restore->CR34);
2764    VGAOUT8(vgaCRIndex, 0x40);
2765    VGAOUT8(vgaCRReg, restore->CR40);
2766    VGAOUT8(vgaCRIndex, 0x42);
2767    VGAOUT8(vgaCRReg, restore->CR42);
2768    VGAOUT8(vgaCRIndex, 0x45);
2769    VGAOUT8(vgaCRReg, restore->CR45);
2770    VGAOUT8(vgaCRIndex, 0x50);
2771    VGAOUT8(vgaCRReg, restore->CR50);
2772    VGAOUT8(vgaCRIndex, 0x51);
2773    VGAOUT8(vgaCRReg, restore->CR51);
2774
2775    /* memory timings */
2776    VGAOUT8(vgaCRIndex, 0x36);
2777    VGAOUT8(vgaCRReg, restore->CR36);
2778    VGAOUT8(vgaCRIndex, 0x60);
2779    VGAOUT8(vgaCRReg, restore->CR60);
2780    VGAOUT8(vgaCRIndex, 0x68);
2781    VGAOUT8(vgaCRReg, restore->CR68);
2782    VerticalRetraceWait();
2783    VGAOUT8(vgaCRIndex, 0x69);
2784    VGAOUT8(vgaCRReg, restore->CR69);
2785    VGAOUT8(vgaCRIndex, 0x6f);
2786    VGAOUT8(vgaCRReg, restore->CR6F);
2787
2788    VGAOUT8(vgaCRIndex, 0x33);
2789    VGAOUT8(vgaCRReg, restore->CR33);
2790    VGAOUT8(vgaCRIndex, 0x86);
2791    VGAOUT8(vgaCRReg, restore->CR86);
2792    VGAOUT8(vgaCRIndex, 0x88);
2793    VGAOUT8(vgaCRReg, restore->CR88);
2794    VGAOUT8(vgaCRIndex, 0x90);
2795    VGAOUT8(vgaCRReg, restore->CR90);
2796    VGAOUT8(vgaCRIndex, 0x91);
2797    VGAOUT8(vgaCRReg, restore->CR91);
2798    if( psav->Chipset == S3_SAVAGE4 )
2799    {
2800	VGAOUT8(vgaCRIndex, 0xb0);
2801	VGAOUT8(vgaCRReg, restore->CRB0);
2802    }
2803
2804    VGAOUT8(vgaCRIndex, 0x32);
2805    VGAOUT8(vgaCRReg, restore->CR32);
2806
2807    /* unlock extended seq regs */
2808    VGAOUT8(0x3c4, 0x08);
2809    VGAOUT8(0x3c5, 0x06);
2810
2811    /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates that
2812     * we should leave the default SR10 and SR11 values there.
2813     */
2814    if (restore->SR10 != 255) {
2815	VGAOUT8(0x3c4, 0x10);
2816	VGAOUT8(0x3c5, restore->SR10);
2817	VGAOUT8(0x3c4, 0x11);
2818	VGAOUT8(0x3c5, restore->SR11);
2819    }
2820
2821    /* restore extended seq regs for dclk */
2822    VGAOUT8(0x3c4, 0x0e);
2823    VGAOUT8(0x3c5, restore->SR0E);
2824    VGAOUT8(0x3c4, 0x0f);
2825    VGAOUT8(0x3c5, restore->SR0F);
2826    VGAOUT8(0x3c4, 0x12);
2827    VGAOUT8(0x3c5, restore->SR12);
2828    VGAOUT8(0x3c4, 0x13);
2829    VGAOUT8(0x3c5, restore->SR13);
2830    VGAOUT8(0x3c4, 0x29);
2831    VGAOUT8(0x3c5, restore->SR29);
2832
2833    VGAOUT8(0x3c4, 0x18);
2834    VGAOUT8(0x3c5, restore->SR18);
2835    VGAOUT8(0x3c4, 0x1b);
2836    if( psav->DGAactive )
2837	VGAOUT8(0x3c5, restore->SR1B & ~0x08 );
2838    else
2839	VGAOUT8(0x3c5, restore->SR1B);
2840
2841    /* load new m, n pll values for dclk & mclk */
2842    VGAOUT8(0x3c4, 0x15);
2843    tmp = VGAIN8(0x3c5) & ~0x21;
2844
2845    VGAOUT8(0x3c5, tmp | 0x03);
2846    VGAOUT8(0x3c5, tmp | 0x23);
2847    VGAOUT8(0x3c5, tmp | 0x03);
2848    VGAOUT8(0x3c5, restore->SR15);
2849    usleep( 100 );
2850
2851    VGAOUT8(0x3c4, 0x30);
2852    VGAOUT8(0x3c5, restore->SR30);
2853    VGAOUT8(0x3c4, 0x08);
2854    VGAOUT8(0x3c5, restore->SR08);
2855
2856    /* now write out cr67 in full, possibly starting STREAMS */
2857    VerticalRetraceWait();
2858    VGAOUT8(vgaCRIndex, 0x67);
2859#if 0
2860    VGAOUT8(vgaCRReg, 0x50);
2861    usleep(10000);
2862    VGAOUT8(vgaCRIndex, 0x67);
2863#endif
2864    VGAOUT8(vgaCRReg, restore->CR67);
2865
2866    VGAOUT8(vgaCRIndex, 0x66);
2867    cr66 = VGAIN8(vgaCRReg);
2868    VGAOUT8(vgaCRReg, cr66 | 0x80);
2869    VGAOUT8(vgaCRIndex, 0x3a);
2870    cr3a = VGAIN8(vgaCRReg);
2871    VGAOUT8(vgaCRReg, cr3a | 0x80);
2872
2873    if (Entering)
2874	SavageGEReset(pScrn,0,__LINE__,__FILE__);
2875
2876    if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
2877    {
2878	VerticalRetraceWait();
2879	OUTREG(FIFO_CONTROL_REG, restore->MMPR0);
2880	OUTREG(MIU_CONTROL_REG, restore->MMPR1);
2881	OUTREG(STREAMS_TIMEOUT_REG, restore->MMPR2);
2882	OUTREG(MISC_TIMEOUT_REG, restore->MMPR3);
2883    }
2884
2885    /* If we're going into graphics mode and acceleration was enabled, */
2886    /* go set up the BCI buffer and the global bitmap descriptor. */
2887
2888#if 0
2889    if( Entering && (!psav->NoAccel) )
2890    {
2891	VGAOUT8(vgaCRIndex, 0x50);
2892	VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
2893	SavageInitialize2DEngine(pScrn);
2894    }
2895#endif
2896
2897    VGAOUT8(vgaCRIndex, 0x66);
2898    VGAOUT8(vgaCRReg, cr66);
2899    VGAOUT8(vgaCRIndex, 0x3a);
2900    VGAOUT8(vgaCRReg, cr3a);
2901
2902    if( Entering ) {
2903	SavageInitialize2DEngine(pScrn);
2904
2905	VGAOUT16(vgaCRIndex, 0x0140);
2906
2907	SavageSetGBD(pScrn);
2908    }
2909
2910    vgaHWProtect(pScrn, FALSE);
2911
2912
2913#ifdef XF86DRI
2914    if (psav->directRenderingEnabled)
2915        DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
2916    psav->LockHeld = 0;
2917#endif
2918
2919    return;
2920}
2921
2922
2923static Bool SavageMapMem(ScrnInfoPtr pScrn)
2924{
2925    SavagePtr psav = SAVPTR(pScrn);
2926    int err;
2927
2928    TRACE(("SavageMapMem()\n"));
2929
2930    if( S3_SAVAGE3D_SERIES(psav->Chipset) ) {
2931#ifdef XSERVER_LIBPCIACCESS
2932        psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S3
2933            + psav->PciInfo->regions[0].base_addr;
2934        psav->FbRegion.base = psav->PciInfo->regions[0].base_addr;
2935#else
2936        psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S3
2937            + psav->PciInfo->memBase[0];
2938        psav->FbRegion.base = psav->PciInfo->memBase[0];
2939#endif
2940    } else {
2941#ifdef XSERVER_LIBPCIACCESS
2942        psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S4
2943            + psav->PciInfo->regions[0].base_addr;
2944        psav->FbRegion.base = psav->PciInfo->regions[1].base_addr;
2945#else
2946        psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S4
2947            + psav->PciInfo->memBase[0];
2948        psav->FbRegion.base = psav->PciInfo->memBase[1];
2949#endif
2950    }
2951
2952    psav->MmioRegion.size = SAVAGE_NEWMMIO_REGSIZE;
2953    psav->FbRegion.size = psav->videoRambytes;
2954
2955    /* On Paramount and Savage 2000, aperture 0 is PCI base 2.  On other
2956     * chipsets it's in the same BAR as the framebuffer.
2957     */
2958
2959    psav->ApertureRegion.size = (psav->IsPrimary || psav->IsSecondary)
2960        ? (0x01000000 * 2) : (0x01000000 * 5);
2961
2962    if ((psav->Chipset == S3_SUPERSAVAGE)
2963        || (psav->Chipset == S3_SAVAGE2000)) {
2964#ifdef XSERVER_LIBPCIACCESS
2965        psav->ApertureRegion.base = psav->PciInfo->regions[2].base_addr;
2966        if (psav->ApertureRegion.size > psav->PciInfo->regions[2].size)
2967            psav->ApertureRegion.size = psav->PciInfo->regions[2].size;
2968#else
2969        psav->ApertureRegion.base = psav->PciInfo->memBase[2];
2970#endif
2971    } else {
2972        psav->ApertureRegion.base = psav->FbRegion.base + 0x02000000;
2973    }
2974
2975
2976
2977    if (psav->FbRegion.size != 0) {
2978#ifdef XSERVER_LIBPCIACCESS
2979        err = pci_device_map_range(psav->PciInfo, psav->FbRegion.base,
2980                                   psav->FbRegion.size,
2981                                   (PCI_DEV_MAP_FLAG_WRITABLE
2982                                    | PCI_DEV_MAP_FLAG_WRITE_COMBINE),
2983                                   & psav->FbRegion.memory);
2984#else
2985        psav->FbRegion.memory =
2986            xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2987                          psav->PciTag, psav->FbRegion.base,
2988                          psav->FbRegion.size);
2989        err = (psav->FbRegion.memory == NULL) ? errno : 0;
2990#endif
2991        if (err) {
2992            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2993                       "Internal error: could not map framebuffer range (%d, %s).\n",
2994                       err, strerror(err));
2995            return FALSE;
2996        }
2997
2998        psav->FBBase = psav->FbRegion.memory;
2999        psav->FBStart = (psav->IsSecondary)
3000            ? psav->FBBase + 0x1000000 : psav->FBBase;
3001    }
3002
3003    if (psav->ApertureRegion.memory == NULL) {
3004#ifdef XSERVER_LIBPCIACCESS
3005        err = pci_device_map_range(psav->PciInfo, psav->ApertureRegion.base,
3006                                   psav->ApertureRegion.size,
3007                                   (PCI_DEV_MAP_FLAG_WRITABLE
3008                                    | PCI_DEV_MAP_FLAG_WRITE_COMBINE),
3009                                   & psav->ApertureRegion.memory);
3010#else
3011        psav->ApertureRegion.memory =
3012            xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
3013                          psav->PciTag, psav->ApertureRegion.base,
3014                          psav->ApertureRegion.size);
3015        err = (psav->ApertureRegion.memory == NULL) ? errno : 0;
3016#endif
3017        if (err) {
3018            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3019                       "Internal error: could not map aperture range (%d, %s).\n",
3020                       err, strerror(err));
3021            return FALSE;
3022        }
3023
3024        psav->ApertureMap = (psav->IsSecondary)
3025            ? psav->ApertureRegion.memory + 0x1000000
3026            : psav->ApertureRegion.memory;
3027    }
3028
3029    if (psav->MmioRegion.memory == NULL) {
3030#ifdef XSERVER_LIBPCIACCESS
3031        err = pci_device_map_range(psav->PciInfo, psav->MmioRegion.base,
3032                                   psav->MmioRegion.size,
3033                                   (PCI_DEV_MAP_FLAG_WRITABLE),
3034                                   & psav->MmioRegion.memory);
3035#else
3036        psav->MmioRegion.memory =
3037            xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
3038                          psav->PciTag, psav->MmioRegion.base,
3039                          psav->MmioRegion.size);
3040        err = (psav->MmioRegion.memory == NULL) ? errno : 0;
3041#endif
3042        if (err) {
3043            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3044                       "Internal error: could not map MMIO range (%d, %s).\n",
3045                       err, strerror(err));
3046            return FALSE;
3047        }
3048
3049        psav->MapBase = psav->MmioRegion.memory;
3050        psav->BciMem = psav->MapBase + 0x10000;
3051
3052        SavageEnableMMIO(pScrn);
3053    }
3054
3055    pScrn->memPhysBase = psav->FbRegion.base;
3056    return TRUE;
3057}
3058
3059
3060static void SavageUnmapMem(ScrnInfoPtr pScrn, int All)
3061{
3062    SavagePtr psav = SAVPTR(pScrn);
3063
3064    TRACE(("SavageUnmapMem(%x,%x)\n", psav->MapBase, psav->FBBase));
3065
3066    if (psav->PrimaryVidMapped) {
3067        vgaHWUnmapMem(pScrn);
3068        psav->PrimaryVidMapped = FALSE;
3069    }
3070
3071    SavageDisableMMIO(pScrn);
3072
3073    if (All && (psav->MmioRegion.memory != NULL)) {
3074#ifdef XSERVER_LIBPCIACCESS
3075        pci_device_unmap_range(psav->PciInfo,
3076                               psav->MmioRegion.memory,
3077                               psav->MmioRegion.size);
3078#else
3079        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->MapBase,
3080                        SAVAGE_NEWMMIO_REGSIZE);
3081#endif
3082
3083        psav->MmioRegion.memory = NULL;
3084        psav->MapBase = 0;
3085        psav->BciMem = 0;
3086    }
3087
3088    if (psav->FbRegion.memory != NULL) {
3089#ifdef XSERVER_LIBPCIACCESS
3090        pci_device_unmap_range(psav->PciInfo,
3091                               psav->FbRegion.memory,
3092                               psav->FbRegion.size);
3093#else
3094        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->FbRegion.base,
3095                        psav->FbRegion.size);
3096#endif
3097    }
3098
3099    if (psav->ApertureRegion.memory != NULL) {
3100#ifdef XSERVER_LIBPCIACCESS
3101        pci_device_unmap_range(psav->PciInfo,
3102                               psav->ApertureRegion.memory,
3103                               psav->ApertureRegion.size);
3104#else
3105        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->ApertureRegion.base,
3106                        psav->ApertureRegion.size);
3107#endif
3108    }
3109
3110    psav->FbRegion.memory = NULL;
3111    psav->ApertureRegion.memory = NULL;
3112    psav->FBBase = 0;
3113    psav->FBStart = 0;
3114    psav->ApertureMap = 0;
3115
3116    return;
3117}
3118
3119#ifdef XF86DRI
3120static Bool SavageCheckAvailableRamFor3D(ScrnInfoPtr pScrn)
3121{
3122    SavagePtr psav = SAVPTR(pScrn);
3123    int cpp = pScrn->bitsPerPixel / 8;
3124    int tiledBufferSize, RamNeededFor3D;
3125
3126    if (cpp == 2) {
3127        tiledBufferSize = ((pScrn->virtualX+63)/64)*((pScrn->virtualY+15)/16) * 2048;
3128    } else {
3129        tiledBufferSize = ((pScrn->virtualX+31)/32)*((pScrn->virtualY+15)/16) * 2048;
3130    }
3131
3132    RamNeededFor3D = 4096 + /* hw cursor*/
3133                     psav->cobSize + /*COB*/
3134                     tiledBufferSize + /* front buffer */
3135                     tiledBufferSize + /* back buffer */
3136                     tiledBufferSize; /* depth buffer */
3137
3138    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
3139		"%d kB of Videoram needed for 3D; %d kB of Videoram available\n",
3140		RamNeededFor3D/1024, psav->videoRambytes/1024);
3141
3142    if (RamNeededFor3D <= psav->videoRambytes) {
3143        xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Sufficient Videoram available for 3D\n");
3144	return TRUE;
3145    } else {
3146        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Insufficient Videoram available for 3D -- "
3147					"Try a lower color depth or smaller desktop.  "
3148			"For integrated savages try increasing the videoram in the BIOS.\n");
3149	return FALSE;
3150    }
3151}
3152#endif
3153
3154static void SavageInitStatus(ScrnInfoPtr pScrn)
3155{
3156    SavagePtr psav = SAVPTR(pScrn);
3157
3158    switch( psav->Chipset ) {
3159	case S3_SAVAGE3D:
3160	case S3_SAVAGE_MX:
3161	    psav->WaitQueue	= WaitQueue3D;
3162	    psav->WaitIdle	= WaitIdle3D;
3163	    psav->WaitIdleEmpty	= WaitIdleEmpty3D;
3164	    psav->bciUsedMask   = 0x1ffff;
3165	    psav->eventStatusReg= 1;
3166	    break;
3167
3168	case S3_SAVAGE4:
3169	case S3_PROSAVAGE:
3170	case S3_SUPERSAVAGE:
3171	case S3_PROSAVAGEDDR:
3172	case S3_TWISTER:
3173	    psav->WaitQueue	= WaitQueue4;
3174	    psav->WaitIdle	= WaitIdle4;
3175	    psav->WaitIdleEmpty	= WaitIdleEmpty4;
3176	    psav->bciUsedMask   = 0x1fffff;
3177	    psav->eventStatusReg= 1;
3178	    break;
3179
3180	case S3_SAVAGE2000:
3181	    psav->WaitQueue	= WaitQueue2K;
3182	    psav->WaitIdle	= WaitIdle2K;
3183	    psav->WaitIdleEmpty	= WaitIdleEmpty2K;
3184	    psav->bciUsedMask   = 0xfffff;
3185	    psav->eventStatusReg= 2;
3186	    break;
3187    }
3188}
3189
3190static void SavageInitShadowStatus(ScrnInfoPtr pScrn)
3191{
3192    SavagePtr psav = SAVPTR(pScrn);
3193
3194    psav->ShadowStatus = psav->ConfigShadowStatus;
3195
3196    SavageInitStatus(pScrn);
3197
3198    if( psav->ShadowStatus ) {
3199	psav->ShadowPhysical =
3200	    psav->FbRegion.base + psav->CursorKByte*1024 + 4096 - 32;
3201
3202	psav->ShadowVirtual = (CARD32 *)
3203	    (psav->FBBase + psav->CursorKByte*1024 + 4096 - 32);
3204
3205	xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
3206		    "Shadow area physical %08lx, linear %p\n",
3207		    psav->ShadowPhysical, (void *)psav->ShadowVirtual );
3208
3209	psav->WaitQueue = ShadowWaitQueue;
3210	psav->WaitIdle = ShadowWait;
3211	psav->WaitIdleEmpty = ShadowWait;
3212    }
3213
3214    if( psav->Chipset == S3_SAVAGE2000 )
3215	psav->dwBCIWait2DIdle = 0xc0040000;
3216    else
3217	psav->dwBCIWait2DIdle = 0xc0020000;
3218}
3219
3220static Bool SavageScreenInit(int scrnIndex, ScreenPtr pScreen,
3221			     int argc, char **argv)
3222{
3223    ScrnInfoPtr pScrn;
3224    SavagePtr psav;
3225    EntityInfoPtr pEnt;
3226    int ret;
3227    int colormapFlags;
3228
3229    TRACE(("SavageScreenInit()\n"));
3230
3231    pScrn = xf86Screens[pScreen->myNum];
3232    psav = SAVPTR(pScrn);
3233
3234    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
3235    if (!psav->pVbe)
3236	psav->pVbe = VBEInit(NULL, pEnt->index);
3237
3238    SavageEnableMMIO(pScrn);
3239
3240    if (!SavageMapMem(pScrn))
3241	return FALSE;
3242
3243    psav->FBStart2nd = 0;
3244
3245    if (psav->overlayDepth) {
3246	if ((pScrn->virtualX * pScrn->virtualY *
3247	     (DEPTH_BPP(DEPTH_2ND(pScrn))) >> 3)
3248	     > (psav->CursorKByte * 1024))
3249	    xf86DrvMsg(pScrn->scrnIndex,X_WARNING,
3250		       "Not enough memory for overlay mode: disabling\n");
3251	else psav->FBStart2nd  = psav->FBStart
3252		 + ((pScrn->virtualX * pScrn->virtualY + 0xff) & ~0xff);
3253
3254    }
3255
3256    SavageInitShadowStatus(pScrn);
3257    psav->ShadowCounter = 0;
3258
3259    SavageSave(pScrn);
3260
3261    vgaHWBlankScreen(pScrn, TRUE);
3262
3263#ifdef XF86DRI
3264    if (!xf86ReturnOptValBool(psav->Options, OPTION_DRI, TRUE)) {
3265	psav->directRenderingEnabled = FALSE;
3266	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3267		   "Direct rendering forced off\n");
3268    } else if (psav->IsSecondary) {
3269	psav->directRenderingEnabled = FALSE;
3270    } else if (xf86IsEntityShared(psav->pEnt->index)) {
3271	    /* Xinerama has sync problem with DRI, disable it for now */
3272	    psav->directRenderingEnabled = FALSE;
3273	    xf86DrvMsg(scrnIndex, X_WARNING,
3274			"Direct Rendering Disabled -- "
3275			"Dual-head configuration is not working with "
3276			"DRI at present.\n");
3277    } else if (/*!psav->bTiled*/psav->bDisableTile) {
3278            xf86DrvMsg(scrnIndex, X_WARNING,
3279	    		"Direct Rendering requires a tiled framebuffer -- "
3280			"Set Option \"DisableTile\" \"false\"\n");
3281    } else if (psav->cobSize == 0) {
3282            xf86DrvMsg(scrnIndex, X_WARNING,
3283	    		"Direct Rendering requires the COB -- "
3284			"Set Option \"DisableCOB\" \"false\"\n");
3285    } else if (((psav->Chipset == S3_TWISTER)
3286        || (psav->Chipset == S3_PROSAVAGE)
3287        || (psav->Chipset == S3_SAVAGE4)
3288        || (psav->Chipset == S3_SAVAGE_MX)
3289	|| (psav->Chipset == S3_SAVAGE3D)
3290	|| (psav->Chipset == S3_SUPERSAVAGE)
3291        || (psav->Chipset == S3_PROSAVAGEDDR))
3292	&& (!psav->NoAccel)
3293	&& (SavageCheckAvailableRamFor3D(pScrn))) {
3294        /* Setup DRI after visuals have been established */
3295        psav->directRenderingEnabled = SAVAGEDRIScreenInit(pScreen);
3296	/* If DRI init failed, reset shadow status. */
3297	if (!psav->directRenderingEnabled &&
3298	    psav->ShadowStatus != psav->ConfigShadowStatus) {
3299	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Resetting ShadowStatus.\n");
3300	    SavageInitShadowStatus(pScrn);
3301	}
3302	/* If shadow status was enabled for DRI, hook up the shadow
3303	 * waiting functions now. */
3304	else if (psav->ShadowStatus && !psav->ConfigShadowStatus) {
3305	    psav->WaitQueue = ShadowWaitQueue;
3306	    psav->WaitIdle = ShadowWait;
3307	    psav->WaitIdleEmpty = ShadowWait;
3308	}
3309    } else
3310        psav->directRenderingEnabled = FALSE;
3311
3312    if(psav->directRenderingEnabled) {
3313        xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"DRI is enabled\n");
3314    }
3315    else {
3316        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DRI isn't enabled\n");
3317    }
3318#endif
3319
3320    if (!SavageModeInit(pScrn, pScrn->currentMode))
3321	return FALSE;
3322
3323    miClearVisualTypes();
3324
3325    {
3326 	int visual;
3327
3328 	visual = ((psav->FBStart2nd && pScrn->bitsPerPixel > 8)
3329		   || pScrn->bitsPerPixel == 16) ? TrueColorMask
3330	    : miGetDefaultVisualMask(DEPTH_BPP(pScrn->depth));
3331 	if (!miSetVisualTypes(pScrn->depth, visual,
3332  			      pScrn->rgbBits, pScrn->defaultVisual))
3333  	    return FALSE;
3334
3335 	if (psav->FBStart2nd) {/* we have overlay */
3336 	    visual = psav->overlayDepth > 8 ? TrueColorMask :
3337 		miGetDefaultVisualMask(DEPTH_BPP(psav->overlayDepth));
3338 	    if (!miSetVisualTypes(psav->overlayDepth, visual,
3339 				  psav->overlayDepth > 8 ? 8 : 6,
3340 				  pScrn->defaultVisual))
3341 		return FALSE;
3342 	}
3343     }
3344     if (!miSetPixmapDepths ())
3345	 return FALSE;
3346
3347    ret = SavageInternalScreenInit(scrnIndex, pScreen);
3348    if (!ret)
3349	return FALSE;
3350
3351    xf86SetBlackWhitePixels(pScreen);
3352
3353    {
3354	VisualPtr visual;
3355	visual = pScreen->visuals + pScreen->numVisuals;
3356	while (--visual >= pScreen->visuals) {
3357	    if ((visual->class | DynamicClass) == DirectColor
3358		&& visual->nplanes > MAX_PSEUDO_DEPTH) {
3359		if (visual->nplanes == pScrn->depth) {
3360		    visual->offsetRed = pScrn->offset.red;
3361		    visual->offsetGreen = pScrn->offset.green;
3362		    visual->offsetBlue = pScrn->offset.blue;
3363		    visual->redMask = pScrn->mask.red;
3364		    visual->greenMask = pScrn->mask.green;
3365		    visual->blueMask = pScrn->mask.blue;
3366		} else if (visual->offsetRed > 8
3367			   || visual->offsetGreen > 8
3368			   || visual->offsetBlue > 8) {
3369	/*
3370	 * mi has set these wrong. fix it here -- we cannot use pScrn
3371	 * as this is set up for the default depth 8.
3372	 */
3373		    int tmp;
3374		    int c_s = 0;
3375
3376		    tmp = visual->offsetBlue;
3377		    visual->offsetBlue = visual->offsetRed;
3378		    visual->offsetRed = tmp;
3379		    tmp = visual->blueMask;
3380		    visual->blueMask = visual->redMask;
3381		    visual->redMask = tmp;
3382		    switch (DEPTH_2ND(pScrn)) {
3383			case 16:
3384			    visual->offsetRed = 11;
3385			    visual->offsetGreen = 5;
3386			    visual->offsetBlue = 0;
3387			    visual->redMask = 0xF800;
3388			    visual->greenMask = 0x7E0;
3389			    visual->blueMask = 0x1F;
3390			    break;
3391			case 24:
3392			    visual->offsetRed = 16;
3393			    visual->offsetGreen = 8;
3394			    visual->offsetBlue = 0;
3395			    visual->redMask = 0xFF0000;
3396			    visual->greenMask = 0xFF00;
3397			    visual->blueMask = 0xFF;
3398			    c_s = 2;
3399			    break;
3400		    }
3401		    psav->overlay.redMask = visual->redMask;
3402		    psav->overlay.greenMask = visual->greenMask;
3403		    psav->overlay.blueMask = visual->blueMask;
3404		    psav->overlay.redShift = visual->offsetRed + c_s;
3405		    psav->overlay.greenShift = visual->offsetGreen + c_s;
3406		    psav->overlay.blueShift = visual->offsetBlue + c_s;
3407		}
3408	    }
3409	}
3410    }
3411
3412    /* must be after RGB ordering fixed */
3413    fbPictureInit (pScreen, 0, 0);
3414
3415    if( !psav->NoAccel ) {
3416	SavageInitAccel(pScreen);
3417    }
3418
3419    miInitializeBackingStore(pScreen);
3420    xf86SetBackingStore(pScreen);
3421
3422    if( !psav->shadowFB && !psav->useEXA )
3423	SavageDGAInit(pScreen);
3424
3425    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
3426
3427    if (psav->hwcursor)
3428	if (!SavageHWCursorInit(pScreen))
3429	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3430	       "Hardware cursor initialization failed\n");
3431
3432    if (psav->shadowFB) {
3433	RefreshAreaFuncPtr refreshArea = SavageRefreshArea;
3434
3435	if(psav->rotate) {
3436	    if (!psav->PointerMoved) {
3437		psav->PointerMoved = pScrn->PointerMoved;
3438		pScrn->PointerMoved = SavagePointerMoved;
3439	    }
3440
3441	    switch(pScrn->bitsPerPixel) {
3442	    case 8:	refreshArea = SavageRefreshArea8;	break;
3443	    case 16:	refreshArea = SavageRefreshArea16;	break;
3444	    case 24:	refreshArea = SavageRefreshArea24;	break;
3445	    case 32:	refreshArea = SavageRefreshArea32;	break;
3446	    }
3447	}
3448
3449	ShadowFBInit(pScreen, refreshArea);
3450    }
3451
3452    if (!miCreateDefColormap(pScreen))
3453	    return FALSE;
3454
3455    colormapFlags =  CMAP_RELOAD_ON_MODE_SWITCH
3456	| ((psav->FBStart2nd) ? 0 : CMAP_PALETTED_TRUECOLOR);
3457
3458    if (psav->Chipset == S3_SAVAGE4) {
3459        if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SavageLoadPaletteSavage4,
3460				 NULL, colormapFlags ))
3461	    return FALSE;
3462    } else {
3463        if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SavageLoadPalette, NULL,
3464				 colormapFlags ))
3465 	    return FALSE;
3466    }
3467
3468    vgaHWBlankScreen(pScrn, FALSE);
3469
3470    psav->CloseScreen = pScreen->CloseScreen;
3471    pScreen->SaveScreen = SavageSaveScreen;
3472    pScreen->CloseScreen = SavageCloseScreen;
3473
3474    if (xf86DPMSInit(pScreen, SavageDPMS, 0) == FALSE)
3475	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed\n");
3476
3477#ifdef XF86DRI
3478    if (psav->directRenderingEnabled) {
3479        /* complete the DRI setup.*/
3480        psav->directRenderingEnabled = SAVAGEDRIFinishScreenInit(pScreen);
3481	/* If DRI initialization failed, reset shadow status and
3482	 * reinitialize 2D engine. */
3483	if (!psav->directRenderingEnabled &&
3484	    psav->ShadowStatus != psav->ConfigShadowStatus) {
3485	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Resetting ShadowStatus.\n");
3486	    SavageInitShadowStatus(pScrn);
3487	    SavageInitialize2DEngine(pScrn);
3488	}
3489    }
3490    if (psav->directRenderingEnabled) {
3491        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n");
3492    } else {
3493        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct rendering disabled\n");
3494    }
3495#endif
3496
3497    SavagePanningCheck(pScrn, pScrn->currentMode);
3498#ifdef XvExtension
3499    if( !psav->FBStart2nd && !psav->NoAccel  /*&& !SavagePanningCheck(pScrn)*/ ) {
3500	if (psav->IsSecondary)
3501            /* Xv should work on crtc2, but I haven't gotten there yet.  -- AGD */
3502	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv currently disabled for crtc2.\n");
3503	else
3504	    SavageInitVideo( pScreen );
3505    }
3506#endif
3507
3508#ifdef XF86DRI
3509    if ((psav->directRenderingEnabled) && (!psav->bDisableXvMC)) {
3510        if (SAVAGEInitMC(pScreen))
3511            xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"XvMC is enabled\n");
3512        else
3513            xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"XvMC is not enabled\n");
3514    }
3515
3516    if (!psav->directRenderingEnabled && psav->AGPforXv) {
3517        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"AGPforXV requires DRI to be enabled.\n");
3518	psav->AGPforXv = FALSE;
3519    }
3520#endif
3521
3522    if (serverGeneration == 1)
3523	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
3524
3525    return TRUE;
3526}
3527
3528
3529static int SavageInternalScreenInit(int scrnIndex, ScreenPtr pScreen)
3530{
3531    int ret = TRUE;
3532    ScrnInfoPtr pScrn;
3533    SavagePtr psav;
3534    int width, height, displayWidth;
3535    unsigned char *FBStart;
3536
3537    TRACE(("SavageInternalScreenInit()\n"));
3538
3539    pScrn = xf86Screens[pScreen->myNum];
3540    psav = SAVPTR(pScrn);
3541
3542    displayWidth = pScrn->displayWidth;
3543
3544    if (psav->rotate) {
3545	height = pScrn->virtualX;
3546	width = pScrn->virtualY;
3547    } else {
3548	width = pScrn->virtualX;
3549	height = pScrn->virtualY;
3550    }
3551
3552
3553    if(psav->shadowFB) {
3554	psav->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
3555	psav->ShadowPtr = xalloc(psav->ShadowPitch * height);
3556	displayWidth = psav->ShadowPitch / (pScrn->bitsPerPixel >> 3);
3557	FBStart = psav->ShadowPtr;
3558    } else {
3559	psav->ShadowPtr = NULL;
3560	FBStart = psav->FBStart;
3561    }
3562
3563    if (!psav->FBStart2nd) {
3564
3565        ret = fbScreenInit(pScreen, FBStart, width, height,
3566                           pScrn->xDpi, pScrn->yDpi,
3567                           psav->ulAperturePitch / (pScrn->bitsPerPixel >> 3), /*displayWidth,*/
3568                           pScrn->bitsPerPixel);
3569
3570    } else {
3571	FbOverlayScrPrivPtr pScrPriv;
3572	int Depth2nd = DEPTH_2ND(pScrn);
3573	if (!fbSetupScreen (pScreen, FBStart, width, height,
3574			    pScrn->xDpi, pScrn->yDpi, displayWidth, 8))
3575	    return FALSE;
3576	if (pScrn->depth == 8) {
3577	    ret = fbOverlayFinishScreenInit (pScreen, FBStart,
3578					     psav->FBStart2nd, width,
3579					     height,pScrn->xDpi, pScrn->yDpi,
3580					     displayWidth,displayWidth,
3581					     8, DEPTH_BPP(Depth2nd),
3582					     8, Depth2nd);
3583	    pScrPriv = fbOverlayGetScrPriv(pScreen);
3584	    pScrPriv->layer[0].key = pScrn->colorKey;
3585	} else {
3586	    ret = fbOverlayFinishScreenInit (pScreen, psav->FBStart2nd,
3587					     FBStart,
3588					     width, height,pScrn->xDpi,
3589					     pScrn->yDpi,
3590					     displayWidth,displayWidth,
3591					     DEPTH_BPP(Depth2nd), 8,
3592					     Depth2nd, 8);
3593	    pScrPriv = fbOverlayGetScrPriv(pScreen);
3594	    pScrPriv->layer[1].key = pScrn->colorKey;
3595	}
3596    }
3597    return ret;
3598}
3599
3600
3601static int SavageGetRefresh(DisplayModePtr mode)
3602{
3603    int refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
3604    if (mode->Flags & V_INTERLACE)
3605	refresh *= 2.0;
3606    if (mode->Flags & V_DBLSCAN)
3607	refresh /= 2.0;
3608    if (mode->VScan > 1)
3609	refresh /= mode->VScan;
3610    return refresh;
3611}
3612
3613
3614static ModeStatus SavageValidMode(int index, DisplayModePtr pMode,
3615				  Bool verbose, int flags)
3616{
3617    ScrnInfoPtr pScrn = xf86Screens[index];
3618    SavagePtr psav = SAVPTR(pScrn);
3619    int refresh;
3620
3621    TRACE(("SavageValidMode\n"));
3622
3623    /* We prohibit modes bigger than the LCD panel. */
3624    /* TODO We should do this only if the panel is active. */
3625
3626    if( psav->TvOn )
3627    {
3628	if( pMode->HDisplay > psav->TVSizeX )
3629	    return MODE_VIRTUAL_X;
3630
3631	if( pMode->VDisplay > psav->TVSizeY )
3632	    return MODE_VIRTUAL_Y;
3633
3634    }
3635
3636    if((psav->DisplayType == MT_LCD) &&
3637      ((pMode->HDisplay > psav->PanelX) ||
3638       (pMode->VDisplay > psav->PanelY)))
3639	    return MODE_PANEL;
3640
3641    if (psav->UseBIOS) {
3642	refresh = SavageGetRefresh(pMode);
3643        return (SavageMatchBiosMode(pScrn,pMode->HDisplay,
3644                                   pMode->VDisplay,
3645                                   refresh,NULL,NULL));
3646    }
3647
3648    return MODE_OK;
3649}
3650
3651static Bool SavageModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
3652{
3653    vgaHWPtr hwp = VGAHWPTR(pScrn);
3654    SavagePtr psav = SAVPTR(pScrn);
3655    int width, dclk, i, j; /*, refresh; */
3656    unsigned int m, n, r;
3657    unsigned char tmp = 0;
3658    SavageRegPtr new = &psav->ModeReg;
3659    vgaRegPtr vganew = &hwp->ModeReg;
3660    int vgaCRIndex, vgaCRReg, vgaIOBase;
3661    int refresh;
3662    unsigned int newmode=0, newrefresh=0;
3663
3664    vgaIOBase = hwp->IOBase;
3665    vgaCRIndex = vgaIOBase + 4;
3666    vgaCRReg = vgaIOBase + 5;
3667
3668    TRACE(("SavageModeInit(%dx%d, %dHz)\n",
3669	mode->HDisplay, mode->VDisplay, mode->Clock));
3670
3671#if 0
3672    ErrorF("Clock = %d, HDisplay = %d, HSStart = %d\n",
3673	    mode->Clock, mode->HDisplay, mode->HSyncStart);
3674    ErrorF("HSEnd = %d, HSkew = %d\n",
3675	    mode->HSyncEnd, mode->HSkew);
3676    ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
3677	    mode->VDisplay, mode->VSyncStart, mode->VSyncEnd);
3678    ErrorF("VTotal = %d\n",
3679	    mode->VTotal);
3680    ErrorF("HDisplay = %d, HSStart = %d\n",
3681	    mode->CrtcHDisplay, mode->CrtcHSyncStart);
3682    ErrorF("HSEnd = %d, HSkey = %d\n",
3683	    mode->CrtcHSyncEnd, mode->CrtcHSkew);
3684    ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
3685	    mode->CrtcVDisplay, mode->CrtcVSyncStart, mode->CrtcVSyncEnd);
3686    ErrorF("VTotal = %d\n",
3687	    mode->CrtcVTotal);
3688#endif
3689
3690    if (psav->IsSecondary) {
3691	refresh = SavageGetRefresh(mode);
3692
3693        SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
3694                            &newmode,&newrefresh);
3695	new->mode = newmode;
3696	new->refresh = newrefresh;
3697
3698        /* do it! */
3699        SavageWriteMode(pScrn, vganew, new, TRUE);
3700
3701        if (psav->FBStart2nd) {
3702	    SavageStreamsOn(pScrn);
3703	    SavageInitSecondaryStream(pScrn);
3704        }
3705
3706        SavageAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
3707	return TRUE;
3708    }
3709
3710
3711    if (pScrn->bitsPerPixel == 8)
3712	psav->HorizScaleFactor = 1;
3713    else if (pScrn->bitsPerPixel == 16)
3714	psav->HorizScaleFactor = 1;	/* I don't think we ever want 2 */
3715    else
3716	psav->HorizScaleFactor = 1;
3717
3718    if (psav->HorizScaleFactor == 2)
3719	if (!mode->CrtcHAdjusted) {
3720	    mode->CrtcHDisplay *= 2;
3721	    mode->CrtcHSyncStart *= 2;
3722	    mode->CrtcHSyncEnd *= 2;
3723	    mode->CrtcHBlankStart *= 2;
3724	    mode->CrtcHBlankEnd *= 2;
3725	    mode->CrtcHTotal *= 2;
3726	    mode->CrtcHSkew *= 2;
3727	    mode->CrtcHAdjusted = TRUE;
3728	}
3729
3730    if (!vgaHWInit(pScrn, mode))
3731	return FALSE;
3732
3733    new->mode = 0;
3734
3735    /* We need to set CR67 whether or not we use the BIOS. */
3736
3737    dclk = mode->Clock;
3738    new->CR67 = 0x00;
3739
3740    switch( pScrn->depth ) {
3741    case 8:
3742	if( (psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000) )
3743	    new->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */
3744	else
3745	    new->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */
3746	break;
3747    case 15:
3748	if(
3749	    S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
3750	    ((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
3751	)
3752	    new->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */
3753	else
3754	    new->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */
3755	break;
3756    case 16:
3757	if(
3758	    S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
3759	    ((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
3760	)
3761	    new->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */
3762	else
3763	    new->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */
3764	break;
3765    case 24:
3766	if (psav->primStreamBpp == 24 )
3767	    new->CR67 = 0x70;
3768	else
3769	    new->CR67 = 0xd0;
3770	break;
3771    }
3772
3773
3774    if( psav->UseBIOS ) {
3775	int refresh;
3776	unsigned int newmode=0, newrefresh=0;
3777
3778	refresh = SavageGetRefresh(mode);
3779
3780        SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
3781                            &newmode,&newrefresh);
3782	new->mode = newmode;
3783	new->refresh = newrefresh;
3784    }
3785
3786    if( !new->mode ) {
3787	/*
3788	 * Either BIOS use is disabled, or we failed to find a suitable
3789	 * match.  Fall back to traditional register-crunching.
3790	 */
3791
3792	VGAOUT8(vgaCRIndex, 0x3a);
3793	tmp = VGAIN8(vgaCRReg);
3794	if (psav->pci_burst)
3795	    new->CR3A = (tmp & 0x7f) | 0x15;
3796	else
3797	    new->CR3A = tmp | 0x95;
3798
3799	new->CR53 = 0x00;
3800	new->CR31 = 0x8c;
3801	new->CR66 = 0x89;
3802
3803	VGAOUT8(vgaCRIndex, 0x58);
3804	new->CR58 = VGAIN8(vgaCRReg) & 0x80;
3805	new->CR58 |= 0x13;
3806
3807#if 0
3808	VGAOUT8(vgaCRIndex, 0x55);
3809	new->CR55 = VGAIN8(vgaCRReg);
3810	if (psav->hwcursor)
3811		new->CR55 |= 0x10;
3812#endif
3813
3814	new->SR15 = 0x03 | 0x80;
3815	new->SR18 = 0x00;
3816
3817
3818	/* enable gamma correction */
3819	if( pScrn->depth == 24 )
3820	    new->SR1B = 0x18;
3821	else
3822	    new->SR1B = 0x00;
3823
3824	/* set 8-bit CLUT */
3825	new->SR1B |= 0x10;
3826
3827	new->CR43 = new->CR45 = new->CR65 = 0x00;
3828
3829	VGAOUT8(vgaCRIndex, 0x40);
3830	new->CR40 = VGAIN8(vgaCRReg) & ~0x01;
3831
3832	new->MMPR0 = 0x010400;
3833	new->MMPR1 = 0x00;
3834	new->MMPR2 = 0x0808;
3835	new->MMPR3 = 0x08080810;
3836
3837	if (psav->fifo_aggressive || psav->fifo_moderate ||
3838	    psav->fifo_conservative) {
3839		new->MMPR1 = 0x0200;
3840		new->MMPR2 = 0x1808;
3841		new->MMPR3 = 0x08081810;
3842	}
3843
3844	if (psav->MCLK <= 0) {
3845		new->SR10 = 255;
3846		new->SR11 = 255;
3847	}
3848
3849	psav->NeedSTREAMS = FALSE;
3850
3851	SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000,
3852			&m, &n, &r);
3853	new->SR12 = (r << 6) | (n & 0x3f);
3854	new->SR13 = m & 0xff;
3855	new->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
3856
3857	if (psav->fifo_moderate) {
3858	    if (psav->primStreamBpp < 24)
3859		new->MMPR0 -= 0x8000;
3860	    else
3861		new->MMPR0 -= 0x4000;
3862	} else if (psav->fifo_aggressive) {
3863	    if (psav->primStreamBpp < 24)
3864		new->MMPR0 -= 0xc000;
3865	    else
3866		new->MMPR0 -= 0x6000;
3867	}
3868
3869	if (mode->Flags & V_INTERLACE)
3870	    new->CR42 = 0x20;
3871	else
3872	    new->CR42 = 0x00;
3873
3874	new->CR34 = 0x10;
3875
3876	i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) |
3877	    ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) |
3878	    ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) |
3879	    ((mode->CrtcHSyncStart & 0x800) >> 7);
3880
3881	if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64)
3882	    i |= 0x08;
3883	if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32)
3884	    i |= 0x20;
3885	j = (vganew->CRTC[0] + ((i & 0x01) << 8) +
3886	     vganew->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
3887	if (j - (vganew->CRTC[4] + ((i & 0x10) << 4)) < 4) {
3888	    if (vganew->CRTC[4] + ((i & 0x10) << 4) + 4 <=
3889	        vganew->CRTC[0] + ((i & 0x01) << 8))
3890		j = vganew->CRTC[4] + ((i & 0x10) << 4) + 4;
3891	    else
3892		j = vganew->CRTC[0] + ((i & 0x01) << 8) + 1;
3893	}
3894
3895	new->CR3B = j & 0xff;
3896	i |= (j & 0x100) >> 2;
3897	new->CR3C = (vganew->CRTC[0] + ((i & 0x01) << 8))  / 2 ;
3898	new->CR5D = i;
3899	new->CR5E = (((mode->CrtcVTotal - 2) & 0x400) >> 10) |
3900		    (((mode->CrtcVDisplay - 1) & 0x400) >> 9) |
3901		    (((mode->CrtcVSyncStart) & 0x400) >> 8) |
3902		    (((mode->CrtcVSyncStart) & 0x400) >> 6) | 0x40;
3903	width = (pScrn->displayWidth * (psav->primStreamBpp / 8)) >> 3;
3904	new->CR91 = vganew->CRTC[19] = 0xff & width;
3905	new->CR51 = (0x300 & width) >> 4;
3906	new->CR90 = 0x80 | (width >> 8);
3907	vganew->MiscOutReg |= 0x0c;
3908
3909	/* Set frame buffer description. */
3910
3911	if (psav->primStreamBpp <= 8)
3912	    new->CR50 = 0;
3913	else if (psav->primStreamBpp <= 16)
3914	    new->CR50 = 0x10;
3915	else
3916	    new->CR50 = 0x30;
3917
3918	if (pScrn->displayWidth == 640)
3919	    new->CR50 |= 0x40;
3920	else if (pScrn->displayWidth == 800)
3921	    new->CR50 |= 0x80;
3922	else if (pScrn->displayWidth == 1024)
3923	    new->CR50 |= 0x00;
3924	else if (pScrn->displayWidth == 1152)
3925	    new->CR50 |= 0x01;
3926	else if (pScrn->displayWidth == 1280)
3927	    new->CR50 |= 0xc0;
3928	else if (pScrn->displayWidth == 1600)
3929	    new->CR50 |= 0x81;
3930	else
3931	    new->CR50 |= 0xc1;	/* Use GBD */
3932
3933	if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
3934	    new->CR33 = 0x00;
3935	else
3936	    new->CR33 = 0x08;
3937
3938	vganew->CRTC[0x17] = 0xeb;
3939
3940	new->CR67 |= 1;
3941
3942	VGAOUT8(vgaCRIndex, 0x36);
3943	new->CR36 = VGAIN8(vgaCRReg);
3944	VGAOUT8(vgaCRIndex, 0x68);
3945	new->CR68 = VGAIN8(vgaCRReg);
3946
3947	new->CR69 = 0;
3948	VGAOUT8(vgaCRIndex, 0x6f);
3949	new->CR6F = VGAIN8(vgaCRReg);
3950	VGAOUT8(vgaCRIndex, 0x86);
3951	new->CR86 = VGAIN8(vgaCRReg) | 0x08;
3952	VGAOUT8(vgaCRIndex, 0x88);
3953	new->CR88 = VGAIN8(vgaCRReg) | DISABLE_BLOCK_WRITE_2D;
3954	VGAOUT8(vgaCRIndex, 0xb0);
3955	new->CRB0 = VGAIN8(vgaCRReg) | 0x80;
3956    }
3957
3958    pScrn->vtSema = TRUE;
3959
3960    /* do it! */
3961    SavageWriteMode(pScrn, vganew, new, TRUE);
3962
3963    if (psav->FBStart2nd) {
3964        SavageStreamsOn(pScrn);
3965	SavageInitSecondaryStream(pScrn);
3966    }
3967
3968    SavageAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
3969
3970    return TRUE;
3971}
3972
3973
3974static Bool SavageCloseScreen(int scrnIndex, ScreenPtr pScreen)
3975{
3976    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
3977    vgaHWPtr hwp = VGAHWPTR(pScrn);
3978    SavagePtr psav = SAVPTR(pScrn);
3979    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
3980    SavageRegPtr SavageSavePtr = &psav->SavedReg;
3981
3982    TRACE(("SavageCloseScreen\n"));
3983
3984#ifdef XF86DRI
3985    if (psav->directRenderingEnabled) {
3986        SAVAGEDRICloseScreen(pScreen);
3987	/* reset shadow values */
3988	SavageInitShadowStatus(pScrn);
3989        psav->directRenderingEnabled=FALSE;
3990    }
3991#endif
3992
3993    if (psav->EXADriverPtr) {
3994	exaDriverFini(pScreen);
3995	psav->EXADriverPtr = NULL;
3996    }
3997
3998    if( psav->AccelInfoRec ) {
3999        XAADestroyInfoRec( psav->AccelInfoRec );
4000	psav->AccelInfoRec = NULL;
4001    }
4002
4003    if( psav->DGAModes ) {
4004	xfree( psav->DGAModes );
4005	psav->DGAModes = NULL;
4006	psav->numDGAModes = 0;
4007    }
4008
4009    if (pScrn->vtSema) {
4010        if (psav->FBStart2nd)
4011	    SavageStreamsOff(pScrn);
4012	SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
4013        SavageResetStreams(pScrn);
4014	vgaHWLock(hwp);
4015	SavageUnmapMem(pScrn, 0);
4016    }
4017
4018    if (psav->pVbe)
4019      vbeFree(psav->pVbe);
4020    psav->pVbe = NULL;
4021
4022    pScrn->vtSema = FALSE;
4023    pScreen->CloseScreen = psav->CloseScreen;
4024
4025    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
4026}
4027
4028
4029static Bool SavageSaveScreen(ScreenPtr pScreen, int mode)
4030{
4031    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
4032
4033    TRACE(("SavageSaveScreen(0x%x)\n", mode));
4034
4035    if( pScrn->vtSema && SAVPTR(pScrn)->hwcursor && SAVPTR(pScrn)->hwc_on )
4036    {
4037	if( xf86IsUnblank(mode) )
4038	    SavageShowCursor( pScrn );
4039	else
4040	    SavageHideCursor( pScrn );
4041	SAVPTR(pScrn)->hwc_on = TRUE; /*restore */
4042    }
4043
4044    return vgaHWSaveScreen(pScreen, mode);
4045}
4046
4047void SavageAdjustFrame(int scrnIndex, int x, int y, int flags)
4048{
4049    ScrnInfoPtr    pScrn      = xf86Screens[scrnIndex];
4050    SavagePtr psav = SAVPTR(pScrn);
4051
4052    if (psav->IsSecondary) {
4053	SavageDoAdjustFrame(pScrn, x, y, TRUE);
4054    } else {
4055	SavageDoAdjustFrame(pScrn, x, y, FALSE);
4056    }
4057
4058}
4059
4060void
4061SavageDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int crtc2)
4062{
4063    SavagePtr psav = SAVPTR(pScrn);
4064    int address=0,top=0,left=0,tile_height,tile_size;
4065
4066    TRACE(("SavageDoAdjustFrame(%d,%d,%x)\n", x, y, flags));
4067
4068    if (psav->Chipset == S3_SAVAGE2000) {
4069        tile_height = TILEHEIGHT_2000; /* 32 */
4070        tile_size = TILE_SIZE_BYTE_2000; /* 4096 */
4071    } else {
4072        tile_height = TILEHEIGHT; /* 16 */
4073        tile_size = TILE_SIZE_BYTE; /* 2048 */
4074    }
4075
4076    if (!psav->bTiled) {
4077        left = x - x % 64;
4078        top = y;
4079        address = (top * psav->lDelta) + left * (pScrn->bitsPerPixel >> 3);
4080        address = (address >> 5) << 5;
4081    } else {
4082        top = y - y % tile_height;
4083        if (pScrn->bitsPerPixel == 16) {
4084            left = x - x % TILEWIDTH_16BPP;
4085            address = top * psav->lDelta + left * tile_size / TILEWIDTH_16BPP;
4086        } else if (pScrn->bitsPerPixel == 32) {
4087            left = x - x % TILEWIDTH_32BPP;
4088            address = top * psav->lDelta + left * tile_size / TILEWIDTH_32BPP;
4089        }
4090    }
4091
4092    address += pScrn->fbOffset;
4093
4094    if (psav->Chipset == S3_SAVAGE_MX) {
4095	if (!crtc2) {
4096            OUTREG32(PRI_STREAM_FBUF_ADDR0, address & 0xFFFFFFFC);
4097            OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFFC);/* IGA1 */
4098        } else {
4099            OUTREG32(PRI_STREAM2_FBUF_ADDR0, address & 0xFFFFFFFC);/* IGA2 */
4100            OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFFC);
4101	}
4102    } else if (psav->Chipset == S3_SUPERSAVAGE) {
4103	if (!crtc2) {
4104            /* IGA1 */
4105            OUTREG32(PRI_STREAM_FBUF_ADDR0, 0x80000000);
4106            OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFF8);
4107        } else {
4108            /* IGA2 */
4109            OUTREG32(PRI_STREAM2_FBUF_ADDR0, ((address & 0xFFFFFFF8) | 0x80000000));
4110            OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFF8);
4111	}
4112    } else if (psav->Chipset == S3_SAVAGE2000) {
4113        /*  certain Y values seems to cause havoc, not sure why */
4114        OUTREG32(PRI_STREAM_FBUF_ADDR0, (address & 0xFFFFFFF8));
4115        OUTREG32(PRI_STREAM2_FBUF_ADDR0, (address & 0xFFFFFFF8));
4116    } else {
4117        OUTREG32(PRI_STREAM_FBUF_ADDR0,address |  0xFFFFFFFC);
4118        OUTREG32(PRI_STREAM_FBUF_ADDR1,address |  0x80000000);
4119    }
4120
4121    return;
4122}
4123
4124Bool SavageSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
4125{
4126    ScrnInfoPtr    pScrn      = xf86Screens[scrnIndex];
4127    SavagePtr psav = SAVPTR(pScrn);
4128    Bool success;
4129
4130    TRACE(("SavageSwitchMode\n"));
4131
4132    if (psav->FBStart2nd || (psav->videoFlags & VF_STREAMS_ON))
4133        SavageStreamsOff(xf86Screens[scrnIndex]);
4134
4135    success = SavageModeInit(xf86Screens[scrnIndex], mode);
4136
4137    /* switching mode on primary will reset secondary.  it needs to be reset as well*/
4138    if (psav->IsPrimary) {
4139        DevUnion* pPriv;
4140        SavageEntPtr pSavEnt;
4141        pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
4142              gSavageEntityIndex);
4143        pSavEnt = pPriv->ptr;
4144        SavageModeInit(pSavEnt->pSecondaryScrn, pSavEnt->pSecondaryScrn->currentMode);
4145    }
4146    SavagePanningCheck(pScrn, mode);
4147
4148    return success;
4149}
4150
4151
4152void SavageEnableMMIO(ScrnInfoPtr pScrn)
4153{
4154    vgaHWPtr hwp = VGAHWPTR(pScrn);
4155    SavagePtr psav = SAVPTR(pScrn);
4156    int vgaCRIndex, vgaCRReg;
4157    unsigned char val;
4158
4159    TRACE(("SavageEnableMMIO\n"));
4160
4161    vgaHWSetStdFuncs(hwp);
4162    vgaHWSetMmioFuncs(hwp, psav->MapBase, 0x8000);
4163    val = VGAIN8(0x3c3);
4164    VGAOUT8(0x3c3, val | 0x01);
4165    val = VGAIN8(VGA_MISC_OUT_R);
4166    VGAOUT8(VGA_MISC_OUT_W, val | 0x01);
4167    vgaCRIndex = psav->vgaIOBase + 4;
4168    vgaCRReg = psav->vgaIOBase + 5;
4169
4170    if( psav->Chipset >= S3_SAVAGE4 )
4171    {
4172	VGAOUT8(vgaCRIndex, 0x40);
4173	val = VGAIN8(vgaCRReg);
4174	VGAOUT8(vgaCRReg, val | 1);
4175    }
4176
4177    return;
4178}
4179
4180
4181void SavageDisableMMIO(ScrnInfoPtr pScrn)
4182{
4183    vgaHWPtr hwp = VGAHWPTR(pScrn);
4184    SavagePtr psav = SAVPTR(pScrn);
4185    int vgaCRIndex, vgaCRReg;
4186    unsigned char val;
4187
4188    TRACE(("SavageDisableMMIO\n"));
4189
4190    vgaCRIndex = psav->vgaIOBase + 4;
4191    vgaCRReg = psav->vgaIOBase + 5;
4192
4193    if( psav->Chipset >= S3_SAVAGE4 )
4194    {
4195	VGAOUT8(vgaCRIndex, 0x40);
4196	val = VGAIN8(vgaCRReg);
4197	VGAOUT8(vgaCRReg, val | 1);
4198    }
4199
4200    vgaHWSetStdFuncs(hwp);
4201
4202    return;
4203}
4204
4205void SavageLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
4206		       LOCO *colors, VisualPtr pVisual)
4207{
4208    SavagePtr psav = SAVPTR(pScrn);
4209    int i, index;
4210    int updateKey = -1;
4211    unsigned char byte = 0;
4212
4213    /* choose CLUT */
4214    if (psav->IsPrimary) {
4215	/* enable CLUT 1 */
4216        VGAOUT8(0x3c4, 0x21);
4217        byte = VGAIN8(0x3c5);
4218        VGAOUT8(0x3c5, (byte & ~0x01));
4219	/* select CLUT 1 */
4220        VGAOUT8(0x3c4, 0x47);
4221        byte = VGAIN8(0x3c5);
4222        VGAOUT8(0x3c5, (byte & ~0x03) | 0x01); /* CLUT 1 */
4223    } else if (psav->IsSecondary) {
4224	/* enable CLUT 2 */
4225        VGAOUT8(0x3c4, 0x21);
4226        byte = VGAIN8(0x3c5);
4227        VGAOUT8(0x3c5, (byte & ~0x10));
4228	/* select CLUT 2 */
4229        VGAOUT8(0x3c4, 0x47);
4230        byte = VGAIN8(0x3c5);
4231        VGAOUT8(0x3c5, (byte & ~0x03) | 0x02); /* CLUT 2 */
4232    }
4233
4234    for (i=0; i<numColors; i++) {
4235	index = indicies[i];
4236	if (index == pScrn->colorKey) updateKey = index;
4237	VGAOUT8(0x3c8, index);
4238	VGAOUT8(0x3c9, colors[index].red);
4239	VGAOUT8(0x3c9, colors[index].green);
4240	VGAOUT8(0x3c9, colors[index].blue);
4241    }
4242
4243    /* restore saved CLUT index value */
4244    if (psav->IsPrimary || psav->IsSecondary) {
4245        VGAOUT8(0x3c4, 0x47);
4246        VGAOUT8(0x3c5, byte);
4247    }
4248
4249    if (updateKey != -1)
4250	SavageUpdateKey(pScrn, colors[updateKey].red, colors[updateKey].green,
4251			colors[updateKey].blue);
4252}
4253
4254#define Shift(v,d)  ((d) < 0 ? ((v) >> (-d)) : ((v) << (d)))
4255
4256static void
4257SavageUpdateKey(ScrnInfoPtr pScrn, int r, int g, int b)
4258{
4259    ScreenPtr pScreen;
4260    SavagePtr psav = SAVPTR(pScrn);
4261    FbOverlayScrPrivPtr pScrOvlPriv;
4262    CARD32 key;
4263    int ul = 0, ol = 1;
4264
4265    if (pScrn->depth != 8) {
4266	ul = 1;
4267	ol = 0;
4268    }
4269    if (!(pScreen = pScrn->pScreen)
4270	|| !psav->FBStart2nd
4271	|| !(pScrOvlPriv = fbOverlayGetScrPriv(pScreen)))
4272	return;
4273    key = ((Shift(r,psav->overlay.redShift) & psav->overlay.redMask)
4274	   | (Shift(g,psav->overlay.greenShift) & psav->overlay.greenMask)
4275	   | (Shift(b,psav->overlay.blueShift) & psav->overlay.blueMask));
4276    if (pScrOvlPriv->layer[ol].key != key) {
4277	pScrOvlPriv->layer[ol].key = key;
4278	(*pScrOvlPriv->PaintKey) (&pScrOvlPriv->layer[ol].u.run.pixmap->drawable,
4279				  &pScrOvlPriv->layer[ul].u.run.region,
4280				  pScrOvlPriv->layer[ol].key, ol);
4281    }
4282}
4283
4284#if 0
4285#define inStatus1() (hwp->readST01( hwp ))
4286#endif
4287
4288void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors, int *indicies,
4289		       LOCO *colors, VisualPtr pVisual)
4290{
4291    SavagePtr psav = SAVPTR(pScrn);
4292    int i, index;
4293    int updateKey = -1;
4294
4295    VerticalRetraceWait();
4296
4297    for (i=0; i<numColors; i++) {
4298          if (!(inStatus1()) & 0x08)
4299  	    VerticalRetraceWait();
4300	index = indicies[i];
4301	VGAOUT8(0x3c8, index);
4302	VGAOUT8(0x3c9, colors[index].red);
4303	VGAOUT8(0x3c9, colors[index].green);
4304	VGAOUT8(0x3c9, colors[index].blue);
4305	if (index == pScrn->colorKey) updateKey = index;
4306    }
4307    if (updateKey != -1)
4308	SavageUpdateKey(pScrn, colors[updateKey].red, colors[updateKey].green,
4309			colors[updateKey].blue);
4310}
4311
4312static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
4313			   int min_n2, int max_n2, long freq_min,
4314			   long freq_max, unsigned int *mdiv,
4315			   unsigned int *ndiv, unsigned int *r)
4316{
4317    double ffreq, ffreq_min, ffreq_max;
4318    double div, diff, best_diff;
4319    unsigned int m;
4320    unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
4321
4322    ffreq = freq / 1000.0 / BASE_FREQ;
4323    ffreq_max = freq_max / 1000.0 / BASE_FREQ;
4324    ffreq_min = freq_min / 1000.0 / BASE_FREQ;
4325
4326    if (ffreq < ffreq_min / (1 << max_n2)) {
4327	    ErrorF("invalid frequency %1.3f Mhz\n",
4328		   ffreq*BASE_FREQ);
4329	    ffreq = ffreq_min / (1 << max_n2);
4330    }
4331    if (ffreq > ffreq_max / (1 << min_n2)) {
4332	    ErrorF("invalid frequency %1.3f Mhz\n",
4333		   ffreq*BASE_FREQ);
4334	    ffreq = ffreq_max / (1 << min_n2);
4335    }
4336
4337    /* work out suitable timings */
4338
4339    best_diff = ffreq;
4340
4341    for (n2=min_n2; n2<=max_n2; n2++) {
4342	for (n1=min_n1+2; n1<=max_n1+2; n1++) {
4343	    m = (int)(ffreq * n1 * (1 << n2) + 0.5);
4344	    if (m < min_m+2 || m > 127+2)
4345		continue;
4346	    div = (double)(m) / (double)(n1);
4347	    if ((div >= ffreq_min) &&
4348		(div <= ffreq_max)) {
4349		diff = ffreq - div / (1 << n2);
4350		if (diff < 0.0)
4351			diff = -diff;
4352		if (diff < best_diff) {
4353		    best_diff = diff;
4354		    best_m = m;
4355		    best_n1 = n1;
4356		    best_n2 = n2;
4357		}
4358	    }
4359	}
4360    }
4361
4362    *ndiv = best_n1 - 2;
4363    *r = best_n2;
4364    *mdiv = best_m - 2;
4365}
4366
4367
4368void SavageGEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file)
4369{
4370    unsigned char cr66;
4371    int r, success = 0;
4372    CARD32 fifo_control = 0, miu_control = 0;
4373    CARD32 streams_timeout = 0, misc_timeout = 0;
4374    vgaHWPtr hwp = VGAHWPTR(pScrn);
4375    SavagePtr psav = SAVPTR(pScrn);
4376    int vgaCRIndex, vgaCRReg, vgaIOBase;
4377
4378    TRACE(("SavageGEReset(%d,%s)\n", line, file));
4379
4380    vgaIOBase = hwp->IOBase;
4381    vgaCRIndex = vgaIOBase + 4;
4382    vgaCRReg = vgaIOBase + 5;
4383
4384    if (from_timeout) {
4385	if (psav->GEResetCnt++ < 10 || xf86GetVerbosity() > 1)
4386	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4387		       "SavageGEReset called from %s line %d\n", file, line);
4388    } else
4389	psav->WaitIdleEmpty(psav);
4390
4391    if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
4392	fifo_control = INREG(FIFO_CONTROL_REG);
4393	miu_control = INREG(MIU_CONTROL_REG);
4394	streams_timeout = INREG(STREAMS_TIMEOUT_REG);
4395	misc_timeout = INREG(MISC_TIMEOUT_REG);
4396    }
4397
4398    VGAOUT8(vgaCRIndex, 0x66);
4399    cr66 = VGAIN8(vgaCRReg);
4400
4401    usleep(10000);
4402    for (r=1; r<10; r++) {
4403	VGAOUT8(vgaCRReg, cr66 | 0x02);
4404	usleep(10000);
4405	VGAOUT8(vgaCRReg, cr66 & ~0x02);
4406	usleep(10000);
4407
4408	if (!from_timeout)
4409	    psav->WaitIdleEmpty(psav);
4410	OUTREG(DEST_SRC_STR, psav->Bpl << 16 | psav->Bpl);
4411
4412	usleep(10000);
4413	switch(psav->Chipset) {
4414	    case S3_SAVAGE3D:
4415	    case S3_SAVAGE_MX:
4416	      success = (STATUS_WORD0 & 0x0008ffff) == 0x00080000;
4417	      break;
4418	    case S3_SAVAGE4:
4419	    case S3_PROSAVAGE:
4420	    case S3_PROSAVAGEDDR:
4421	    case S3_TWISTER:
4422	    case S3_SUPERSAVAGE:
4423	      success = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000;
4424	      break;
4425	    case S3_SAVAGE2000:
4426	      success = (ALT_STATUS_WORD0 & 0x008fffff) == 0;
4427	      break;
4428	}
4429	if(!success) {
4430	    usleep(10000);
4431	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4432		"restarting S3 graphics engine reset %2d ...\n", r);
4433	}
4434	else
4435	    break;
4436    }
4437
4438    /* At this point, the FIFO is empty and the engine is idle. */
4439
4440    if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
4441	OUTREG(FIFO_CONTROL_REG, fifo_control);
4442	OUTREG(MIU_CONTROL_REG, miu_control);
4443	OUTREG(STREAMS_TIMEOUT_REG, streams_timeout);
4444	OUTREG(MISC_TIMEOUT_REG, misc_timeout);
4445    }
4446
4447    OUTREG(SRC_BASE, 0);
4448    OUTREG(DEST_BASE, 0);
4449    OUTREG(CLIP_L_R, ((0) << 16) | pScrn->displayWidth);
4450    OUTREG(CLIP_T_B, ((0) << 16) | psav->ScissB);
4451    OUTREG(MONO_PAT_0, ~0);
4452    OUTREG(MONO_PAT_1, ~0);
4453
4454    SavageSetGBD(pScrn);
4455
4456}
4457
4458
4459
4460/* This function is used to debug, it prints out the contents of s3 regs */
4461
4462void
4463SavagePrintRegs(ScrnInfoPtr pScrn)
4464{
4465    SavagePtr psav = SAVPTR(pScrn);
4466    unsigned char i;
4467    int vgaCRIndex = 0x3d4;
4468    int vgaCRReg = 0x3d5;
4469
4470    ErrorF( "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
4471
4472    for( i = 0; i < 0x70; i++ ) {
4473	if( !(i % 16) )
4474	    ErrorF( "\nSR%xx ", i >> 4 );
4475	VGAOUT8( 0x3c4, i );
4476	ErrorF( " %02x", VGAIN8(0x3c5) );
4477    }
4478
4479    ErrorF( "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
4480
4481    for( i = 0; i < 0xB7; i++ ) {
4482	if( !(i % 16) )
4483	    ErrorF( "\nCR%xx ", i >> 4 );
4484	VGAOUT8( vgaCRIndex, i );
4485	ErrorF( " %02x", VGAIN8(vgaCRReg) );
4486    }
4487
4488    ErrorF("\n\n");
4489}
4490
4491static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags)
4492{
4493    SavagePtr psav = SAVPTR(pScrn);
4494    unsigned char sr8 = 0x00, srd = 0x00;
4495
4496    TRACE(("SavageDPMS(%d,%x)\n", mode, flags));
4497
4498    if (psav->DisplayType == MT_CRT) {
4499    	VGAOUT8(0x3c4, 0x08);
4500    	sr8 = VGAIN8(0x3c5);
4501    	sr8 |= 0x06;
4502    	VGAOUT8(0x3c5, sr8);
4503
4504    	VGAOUT8(0x3c4, 0x0d);
4505    	srd = VGAIN8(0x3c5);
4506
4507    	srd &= 0x03;
4508
4509    	switch (mode) {
4510	    case DPMSModeOn:
4511	    	break;
4512	    case DPMSModeStandby:
4513	    	srd |= 0x10;
4514	    	break;
4515	    case DPMSModeSuspend:
4516	    	srd |= 0x40;
4517	    	break;
4518	    case DPMSModeOff:
4519	    	srd |= 0x50;
4520	    	break;
4521	    default:
4522	    	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
4523	    	break;
4524    	}
4525
4526    	VGAOUT8(0x3c4, 0x0d);
4527    	VGAOUT8(0x3c5, srd);
4528    }
4529
4530    if (psav->DisplayType == MT_LCD || psav->DisplayType == MT_DFP) {
4531	if (S3_MOBILE_TWISTER_SERIES(psav->Chipset) && psav->UseBIOS) {
4532	    SavageSetPanelEnabled(psav, (mode == DPMSModeOn));
4533	} else {
4534    	    switch (mode) {
4535	        case DPMSModeOn:
4536		    VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
4537		    VGAOUT8(0x3c5, VGAIN8(0x3c5) | 0x10);
4538	            break;
4539	        case DPMSModeStandby:
4540	        case DPMSModeSuspend:
4541	        case DPMSModeOff:
4542		    VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
4543		    VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x10);
4544	            break;
4545	        default:
4546	            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
4547	            break;
4548	    }
4549        }
4550    }
4551
4552    return;
4553}
4554
4555static void
4556SavageProbeDDC(ScrnInfoPtr pScrn, int index)
4557{
4558    vbeInfoPtr pVbe;
4559
4560    if (xf86LoadSubModule(pScrn, "vbe")) {
4561	pVbe = VBEInit(NULL, index);
4562	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
4563	vbeFree(pVbe);
4564    }
4565}
4566
4567static unsigned int
4568SavageDDC1Read(ScrnInfoPtr pScrn)
4569{
4570    register unsigned char tmp;
4571    SavagePtr psav = SAVPTR(pScrn);
4572
4573    UnLockExtRegs();
4574
4575    VerticalRetraceWait();
4576
4577    InI2CREG(tmp,psav->I2CPort);
4578
4579    return ((unsigned int) (tmp & 0x08));
4580}
4581
4582static Bool
4583SavageDDC1(int scrnIndex)
4584{
4585    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
4586    SavagePtr psav = SAVPTR(pScrn);
4587    unsigned char byte;
4588    xf86MonPtr pMon;
4589
4590    UnLockExtRegs();
4591
4592    /* initialize chipset */
4593    InI2CREG(byte,psav->I2CPort);
4594    OutI2CREG(byte | 0x12,psav->I2CPort);
4595
4596    pMon = xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(),SavageDDC1Read);
4597    if (!pMon)
4598        return FALSE;
4599
4600    xf86PrintEDID(pMon);
4601
4602    if (!psav->IgnoreEDID)
4603        xf86SetDDCproperties(pScrn,pMon);
4604
4605    /* undo initialization */
4606    OutI2CREG(byte,psav->I2CPort);
4607
4608    return TRUE;
4609}
4610
4611static void
4612SavageGetTvMaxSize(SavagePtr psav)
4613{
4614    if( psav->PAL ) {
4615	psav->TVSizeX = 800;
4616	psav->TVSizeY = 600;
4617    }
4618    else {
4619	psav->TVSizeX = 640;
4620	psav->TVSizeY = 480;
4621    }
4622}
4623
4624
4625static Bool
4626SavagePanningCheck(ScrnInfoPtr pScrn, DisplayModePtr pMode)
4627{
4628    SavagePtr psav = SAVPTR(pScrn);
4629    psav->iResX = pMode->CrtcHDisplay;
4630    psav->iResY = pMode->CrtcVDisplay;
4631
4632    if ((psav->iResX < psav->PanelX || psav->iResY < psav->PanelY))
4633        psav->FPExpansion = TRUE;
4634    else
4635        psav->FPExpansion = FALSE;
4636
4637    if( psav->iResX < pScrn->virtualX || psav->iResY < pScrn->virtualY )
4638	return TRUE;
4639    else
4640	return FALSE;
4641}
4642
4643static void
4644SavageResetStreams(ScrnInfoPtr pScrn)
4645{
4646    SavagePtr psav = SAVPTR(pScrn);
4647    unsigned char cr67;
4648    unsigned char cr69;
4649
4650    /* disable streams */
4651    switch (psav->Chipset) {
4652        case S3_SAVAGE_MX:
4653        case S3_SUPERSAVAGE:
4654            OUTREG32(PRI_STREAM_STRIDE,0);
4655            OUTREG32(PRI_STREAM2_STRIDE, 0);
4656            OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
4657            OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
4658            OUTREG32(PRI_STREAM2_FBUF_ADDR0,0x00000000);
4659            OUTREG32(PRI_STREAM2_FBUF_ADDR1,0x00000000);
4660	    OUTREG8(CRT_ADDRESS_REG, 0x67);
4661            cr67 = INREG8(CRT_DATA_REG);
4662	    cr67 &= ~0x08; /* CR67[3] = 1 : Mem-mapped regs */
4663	    cr67 &= ~0x04; /* CR67[2] = 1 : enable stream 1 */
4664	    cr67 &= ~0x02; /* CR67[1] = 1 : enable stream 2 */
4665            OUTREG8(CRT_DATA_REG, cr67);
4666            break;
4667	case S3_SAVAGE3D:
4668        case S3_SAVAGE4:
4669        case S3_TWISTER:
4670        case S3_PROSAVAGE:
4671        case S3_PROSAVAGEDDR:
4672            OUTREG32(PRI_STREAM_STRIDE,0);
4673            OUTREG32(PRI_STREAM_FBUF_ADDR0,0);
4674            OUTREG32(PRI_STREAM_FBUF_ADDR1,0);
4675	    OUTREG8(CRT_ADDRESS_REG, 0x67);
4676            cr67 = INREG8(CRT_DATA_REG);
4677	    cr67 &= ~0x0c; /* CR67[2] = 1 : enable stream 1 */
4678            OUTREG8(CRT_DATA_REG, cr67);
4679	    OUTREG8(CRT_ADDRESS_REG, 0x69);
4680            cr69 = INREG8(CRT_DATA_REG);
4681	    cr69 &= ~0x80; /* CR69[0] = 1 : Mem-mapped regs */
4682            OUTREG8(CRT_DATA_REG, cr69);
4683            break;
4684        case S3_SAVAGE2000:
4685            OUTREG32(PRI_STREAM_STRIDE,0);
4686            OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
4687            OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
4688	    OUTREG8(CRT_ADDRESS_REG, 0x67);
4689            cr67 = INREG8(CRT_DATA_REG);
4690	    cr67 &= ~0x08; /* CR67[3] = 1 : Mem-mapped regs */
4691	    cr67 &= ~0x04; /* CR67[2] = 1 : enable stream 1 */
4692	    cr67 &= ~0x02; /* CR67[1] = 1 : enable stream 2 */
4693            OUTREG8(CRT_DATA_REG, cr67);
4694            break;
4695        default:
4696            break;
4697    }
4698
4699}
4700