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