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