s3v_driver.c revision ba85709e
1
2/*
3Copyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
4
5Permission is hereby granted, free of charge, to any person obtaining a copy of
6this software and associated documentation files (the "Software"), to deal in
7the Software without restriction, including without limitation the rights to
8use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9of the Software, and to permit persons to whom the Software is furnished to do
10so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
17NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of the XFree86 Project shall not
23be used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from the XFree86 Project.
25*/
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <unistd.h>
32#include "xf86Resources.h"
33/* Needed by Resources Access Control (RAC) */
34#include "xf86RAC.h"
35
36#include "xf86DDC.h"
37#include "vbe.h"
38
39/* Needed by the Shadow Framebuffer */
40#include "shadowfb.h"
41
42/*
43 * s3v_driver.c
44 * Port to 4.0 design level
45 *
46 * S3 ViRGE driver
47 *
48 * 10/98 - 3/99 Kevin Brosius
49 * based largely on the SVGA ViRGE driver from 3.3.3x,
50 * Started 09/03/97 by S. Marineau
51 *
52 *
53 */
54
55
56	/* Most xf86 commons are already in s3v.h */
57#include	"s3v.h"
58
59
60#include "globals.h"
61#define DPMS_SERVER
62#include <X11/extensions/dpms.h>
63
64#ifndef USE_INT10
65#define USE_INT10 0
66#endif
67
68/*
69 * Internals
70 */
71static void S3VEnableMmio(ScrnInfoPtr pScrn);
72static void S3VDisableMmio(ScrnInfoPtr pScrn);
73
74/*
75 * Forward definitions for the functions that make up the driver.
76 */
77
78/* Mandatory functions */
79static const OptionInfoRec * S3VAvailableOptions(int chipid, int busid);
80static void S3VIdentify(int flags);
81static Bool S3VProbe(DriverPtr drv, int flags);
82static Bool S3VPreInit(ScrnInfoPtr pScrn, int flags);
83
84static Bool S3VEnterVT(int scrnIndex, int flags);
85static void S3VLeaveVT(int scrnIndex, int flags);
86static void S3VSave (ScrnInfoPtr pScrn);
87static void S3VWriteMode (ScrnInfoPtr pScrn, vgaRegPtr, S3VRegPtr);
88
89static void S3VSaveSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams);
90static void S3VRestoreSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams);
91static void S3VDisableSTREAMS(ScrnInfoPtr pScrn);
92static Bool S3VScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv);
93static int S3VInternalScreenInit( int scrnIndex, ScreenPtr pScreen);
94static void S3VPrintRegs(ScrnInfoPtr);
95static ModeStatus S3VValidMode(int index, DisplayModePtr mode, Bool verbose, int flags);
96
97static Bool S3VMapMem(ScrnInfoPtr pScrn);
98static void S3VUnmapMem(ScrnInfoPtr pScrn);
99static Bool S3VModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
100static Bool S3VCloseScreen(int scrnIndex, ScreenPtr pScreen);
101static Bool S3VSaveScreen(ScreenPtr pScreen, int mode);
102static void S3VInitSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams, DisplayModePtr mode);
103/* s3v.h - static void S3VAdjustFrame(int scrnIndex, int x, int y, int flags); */
104/* s3v.h - static Bool S3VSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); */
105static void S3VLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, LOCO *colors, VisualPtr pVisual);
106
107static void S3VDisplayPowerManagementSet(ScrnInfoPtr pScrn,
108					 int PowerManagementMode,
109					 int flags);
110static Bool S3Vddc1(int scrnIndex);
111static Bool S3Vddc2(int scrnIndex);
112
113static unsigned int S3Vddc1Read(ScrnInfoPtr pScrn);
114static void S3VProbeDDC(ScrnInfoPtr pScrn, int index);
115
116/*
117 * This is intentionally screen-independent.  It indicates the binding
118 * choice made in the first PreInit.
119 */
120static int pix24bpp = 0;
121
122#define S3VIRGE_NAME "S3VIRGE"
123#define S3VIRGE_DRIVER_NAME "s3virge"
124#define S3VIRGE_VERSION_NAME PACKAGE_VERSION
125#define S3VIRGE_VERSION_MAJOR   PACKAGE_VERSION_MAJOR
126#define S3VIRGE_VERSION_MINOR   PACKAGE_VERSION_MINOR
127#define S3VIRGE_PATCHLEVEL      PACKAGE_VERSION_PATCHLEVEL
128#define S3VIRGE_DRIVER_VERSION ((S3VIRGE_VERSION_MAJOR << 24) | \
129				(S3VIRGE_VERSION_MINOR << 16) | \
130				S3VIRGE_PATCHLEVEL)
131
132/*
133 * This contains the functions needed by the server after loading the
134 * driver module.  It must be supplied, and gets added the driver list by
135 * the Module Setup funtion in the dynamic case.  In the static case a
136 * reference to this is compiled in, and this requires that the name of
137 * this DriverRec be an upper-case version of the driver name.
138 */
139
140_X_EXPORT DriverRec S3VIRGE =
141{
142    S3VIRGE_DRIVER_VERSION,
143    S3VIRGE_DRIVER_NAME,
144    S3VIdentify,
145    S3VProbe,
146    S3VAvailableOptions,
147    NULL,
148    0
149};
150
151
152/* Supported chipsets */
153static SymTabRec S3VChipsets[] = {
154				  	/* base (86C325) */
155  { PCI_CHIP_VIRGE,			"virge" },
156  { PCI_CHIP_VIRGE,			"86C325" },
157  					/* VX (86C988) */
158  { PCI_CHIP_VIRGE_VX,		"virge vx" },
159  { PCI_CHIP_VIRGE_VX,		"86C988" },
160  					/* DX (86C375) GX (86C385) */
161  { PCI_CHIP_VIRGE_DXGX,	"virge dx" },
162  { PCI_CHIP_VIRGE_DXGX,	"virge gx" },
163  { PCI_CHIP_VIRGE_DXGX,	"86C375" },
164  { PCI_CHIP_VIRGE_DXGX,	"86C385" },
165                                        /* GX2 (86C357) */
166  { PCI_CHIP_VIRGE_GX2,		"virge gx2" },
167  { PCI_CHIP_VIRGE_GX2,		"86C357" },
168  					/* MX (86C260) */
169  { PCI_CHIP_VIRGE_MX,		"virge mx" },
170  { PCI_CHIP_VIRGE_MX,		"86C260" },
171  					/* MX+ (86C280) */
172  { PCI_CHIP_VIRGE_MXP,		"virge mx+" },
173  { PCI_CHIP_VIRGE_MXP,		"86C280" },
174  					/* Trio3D (86C365) */
175  { PCI_CHIP_Trio3D,		"trio 3d" },
176  { PCI_CHIP_Trio3D,		"86C365" },
177  					/* Trio3D/2x (86C362/86C368) */
178  { PCI_CHIP_Trio3D_2X,		"trio 3d/2x" },
179  { PCI_CHIP_Trio3D_2X,		"86C362" },
180  { PCI_CHIP_Trio3D_2X,		"86C368" },
181  {-1,			NULL }
182};
183
184static PciChipsets S3VPciChipsets[] = {
185  /* numChipset,		PciID,			Resource */
186  { PCI_CHIP_VIRGE,      PCI_CHIP_VIRGE,     	RES_SHARED_VGA },
187  { PCI_CHIP_VIRGE_VX,   PCI_CHIP_VIRGE_VX,     RES_SHARED_VGA },
188  { PCI_CHIP_VIRGE_DXGX, PCI_CHIP_VIRGE_DXGX,	RES_SHARED_VGA },
189  { PCI_CHIP_VIRGE_GX2,  PCI_CHIP_VIRGE_GX2,  	RES_SHARED_VGA },
190  { PCI_CHIP_VIRGE_MX,   PCI_CHIP_VIRGE_MX,   	RES_SHARED_VGA },
191  { PCI_CHIP_VIRGE_MXP,  PCI_CHIP_VIRGE_MXP,  	RES_SHARED_VGA },
192  { PCI_CHIP_Trio3D,     PCI_CHIP_Trio3D,  	RES_SHARED_VGA },
193  { PCI_CHIP_Trio3D_2X,  PCI_CHIP_Trio3D_2X,  	RES_SHARED_VGA },
194  { -1,                       -1,   		RES_UNDEFINED }
195};
196
197typedef enum {
198   OPTION_SLOW_EDODRAM,
199   OPTION_SLOW_DRAM,
200   OPTION_FAST_DRAM,
201   OPTION_FPM_VRAM,
202   OPTION_PCI_BURST,
203   OPTION_FIFO_CONSERV,
204   OPTION_FIFO_MODERATE,
205   OPTION_FIFO_AGGRESSIVE,
206   OPTION_PCI_RETRY,
207   OPTION_NOACCEL,
208   OPTION_EARLY_RAS_PRECHARGE,
209   OPTION_LATE_RAS_PRECHARGE,
210   OPTION_LCD_CENTER,
211   OPTION_LCDCLOCK,
212   OPTION_MCLK,
213   OPTION_REFCLK,
214   OPTION_SHOWCACHE,
215   OPTION_SWCURSOR,
216   OPTION_HWCURSOR,
217   OPTION_SHADOW_FB,
218   OPTION_ROTATE,
219   OPTION_FB_DRAW,
220   OPTION_MX_CR3A_FIX,
221   OPTION_XVIDEO
222} S3VOpts;
223
224static const OptionInfoRec S3VOptions[] =
225{
226  /*    int token, const char* name, OptionValueType type,
227	ValueUnion value, Bool found.
228  */
229   { OPTION_SLOW_EDODRAM, 	"slow_edodram",	OPTV_BOOLEAN,	{0}, FALSE },
230   { OPTION_SLOW_DRAM, 		"slow_dram",	OPTV_BOOLEAN,	{0}, FALSE },
231   { OPTION_FAST_DRAM, 		"fast_dram",	OPTV_BOOLEAN,	{0}, FALSE },
232   { OPTION_FPM_VRAM, 		"fpm_vram",	OPTV_BOOLEAN,	{0}, FALSE },
233   { OPTION_PCI_BURST, 		"pci_burst",	OPTV_BOOLEAN,	{0}, FALSE },
234   { OPTION_FIFO_CONSERV, 	"fifo_conservative", OPTV_BOOLEAN, {0}, FALSE },
235   { OPTION_FIFO_MODERATE, 	"fifo_moderate", OPTV_BOOLEAN, 	{0}, FALSE },
236   { OPTION_FIFO_AGGRESSIVE, 	"fifo_aggressive", OPTV_BOOLEAN, {0}, FALSE },
237   { OPTION_PCI_RETRY, 		"pci_retry",	OPTV_BOOLEAN,	{0}, FALSE  },
238   { OPTION_NOACCEL, 		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE  },
239   { OPTION_EARLY_RAS_PRECHARGE, "early_ras_precharge",	OPTV_BOOLEAN, {0}, FALSE },
240   { OPTION_LATE_RAS_PRECHARGE, "late_ras_precharge", OPTV_BOOLEAN, {0}, FALSE },
241   { OPTION_LCD_CENTER, 	"lcd_center", 	OPTV_BOOLEAN, 	{0}, FALSE },
242   { OPTION_LCDCLOCK, 		"set_lcdclk", 	OPTV_INTEGER, 	{0}, FALSE },
243   { OPTION_MCLK, 		"set_mclk", 	OPTV_FREQ, 	{0}, FALSE },
244   { OPTION_REFCLK, 		"set_refclk", 	OPTV_FREQ, 	{0}, FALSE },
245   { OPTION_SHOWCACHE,		"show_cache",   OPTV_BOOLEAN,	{0}, FALSE },
246   { OPTION_HWCURSOR,		"HWCursor",     OPTV_BOOLEAN,	{0}, FALSE },
247   { OPTION_SWCURSOR,		"SWCursor",     OPTV_BOOLEAN,	{0}, FALSE },
248   { OPTION_SHADOW_FB,          "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
249   { OPTION_ROTATE, 	        "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
250   { OPTION_MX_CR3A_FIX,        "mxcr3afix",	OPTV_BOOLEAN,	{0}, FALSE },
251   { OPTION_XVIDEO,             "XVideo",	OPTV_BOOLEAN,	{0}, FALSE },
252   {-1, NULL, OPTV_NONE,	{0}, FALSE}
253};
254
255
256/*
257 * Lists of symbols that may/may not be required by this driver.
258 * This allows the loader to know which ones to issue warnings for.
259 *
260 * Note that vgahwSymbols and xaaSymbols are referenced outside the
261 * XFree86LOADER define in later code, so are defined outside of that
262 * define here also.
263 */
264
265static const char *vgahwSymbols[] = {
266    "vgaHWBlankScreen",
267    "vgaHWCopyReg",
268    "vgaHWGetHWRec",
269    "vgaHWGetIOBase",
270    "vgaHWGetIndex",
271    "vgaHWInit",
272    "vgaHWLock",
273    "vgaHWMapMem",
274    "vgaHWProtect",
275    "vgaHWRestore",
276    "vgaHWSave",
277    "vgaHWSaveScreen",
278    "vgaHWSetMmioFuncs",
279    "vgaHWSetStdFuncs",
280    "vgaHWUnmapMem",
281    "vgaHWddc1SetSpeedWeak",
282   /* not used by ViRGE (at the moment :( ) */
283   /*
284    "vgaHWUnlock",
285    "vgaHWFreeHWRec",
286    */
287    NULL
288};
289
290static const char *xaaSymbols[] = {
291    "XAAGetCopyROP",
292    "XAAGetCopyROP_PM",
293    "XAADestroyInfoRec",
294    "XAACreateInfoRec",
295    "XAAHelpPatternROP",
296    "XAAHelpSolidROP",
297    "XAAInit",
298    NULL
299};
300
301static const char *ramdacSymbols[] = {
302    "xf86CreateCursorInfoRec",
303    "xf86InitCursor",
304#if 0
305    "xf86DestroyCursorInfoRec",
306#endif
307    NULL
308};
309
310static const char *ddcSymbols[] = {
311    "xf86PrintEDID",
312    "xf86DoEDID_DDC1",
313    "xf86DoEDID_DDC2",
314    "xf86SetDDCproperties",
315    NULL
316};
317
318static const char *i2cSymbols[] = {
319    "xf86CreateI2CBusRec",
320    "xf86I2CBusInit",
321    NULL
322};
323
324static const char *shadowSymbols[] = {
325    "ShadowFBInit",
326    NULL
327};
328
329static const char *vbeSymbols[] = {
330    "VBEInit",
331    "vbeDoEDID",
332    "vbeFree",
333    NULL
334};
335
336static const char *fbSymbols[] = {
337  "fbPictureInit",
338  "fbScreenInit",
339  NULL
340};
341
342#if USE_INT10
343static const char *int10Symbols[] = {
344    "xf86InitInt10",
345    "xf86FreeInt10",
346    NULL
347};
348#endif
349
350#ifdef XFree86LOADER
351
352static MODULESETUPPROTO(s3virgeSetup);
353
354static XF86ModuleVersionInfo S3VVersRec =
355{
356    "s3virge",
357    MODULEVENDORSTRING,
358    MODINFOSTRING1,
359    MODINFOSTRING2,
360    XORG_VERSION_CURRENT,
361    S3VIRGE_VERSION_MAJOR, S3VIRGE_VERSION_MINOR, S3VIRGE_PATCHLEVEL,
362    ABI_CLASS_VIDEODRV,		       /* This is a video driver */
363    ABI_VIDEODRV_VERSION,
364    MOD_CLASS_VIDEODRV,
365    {0, 0, 0, 0}
366};
367
368
369/*
370 * This is the module init data for XFree86 modules.
371 *
372 * Its name has to be the driver name followed by ModuleData.
373 */
374_X_EXPORT XF86ModuleData s3virgeModuleData = {
375    &S3VVersRec,
376    s3virgeSetup,
377    NULL
378};
379
380static pointer
381s3virgeSetup(pointer module, pointer opts, int *errmaj, int *errmin)
382{
383    static Bool setupDone = FALSE;
384
385    if (!setupDone) {
386	setupDone = TRUE;
387	xf86AddDriver(&S3VIRGE, module, 0);
388
389	/*
390	 * Modules that this driver always requires can be loaded here
391	 * by calling LoadSubModule().
392	 */
393
394	/*
395	 * Tell the loader about symbols from other modules that this module
396	 * might refer to.
397	 */
398	LoaderRefSymLists(vgahwSymbols, xaaSymbols, ramdacSymbols,
399			  ddcSymbols, i2cSymbols,
400#if USE_INT10
401			  int10Symbols,
402#endif
403			  vbeSymbols, shadowSymbols, fbSymbols, NULL);
404
405	/*
406	 * The return value must be non-NULL on success even though there
407	 * is no TearDownProc.
408	 */
409	return (pointer) 1;
410    } else {
411	if (errmaj)
412	    *errmaj = LDR_ONCEONLY;
413	return NULL;
414    }
415}
416
417#endif /* XFree86LOADER */
418
419
420static unsigned char *find_bios_string(S3VPtr ps3v, int BIOSbase, char *match1, char *match2)
421{
422#define BIOS_BSIZE 1024
423#define BIOS_BASE  0xc0000
424
425   static unsigned char bios[BIOS_BSIZE];
426   static int init=0;
427   int i,j,l1,l2;
428
429   if (!init) {
430      init = 1;
431#ifndef XSERVER_LIBPCIACCESS
432      if (xf86ReadDomainMemory(ps3v->PciTag, BIOSbase, BIOS_BSIZE, bios) != BIOS_BSIZE)
433	 return NULL;
434#else
435      if (pci_device_read_rom(ps3v->PciInfo, bios))
436	return NULL;
437#endif
438      if ((bios[0] != 0x55) || (bios[1] != 0xaa))
439	 return NULL;
440   }
441   if (match1 == NULL)
442      return NULL;
443
444   l1 = strlen(match1);
445   if (match2 != NULL)
446      l2 = strlen(match2);
447   else	/* for compiler-warnings */
448      l2 = 0;
449
450   for (i=0; i<BIOS_BSIZE-l1; i++)
451       if (bios[i] == match1[0] && !memcmp(&bios[i],match1,l1)) {
452	 if (match2 == NULL)
453	    return &bios[i+l1];
454	 else
455	    for(j=i+l1; (j<BIOS_BSIZE-l2) && bios[j]; j++)
456	       if (bios[j] == match2[0] && !memcmp(&bios[j],match2,l2))
457		   return &bios[j+l2];
458       }
459
460   return NULL;
461}
462
463
464static Bool
465S3VGetRec(ScrnInfoPtr pScrn)
466{
467    PVERB5("	S3VGetRec\n");
468    /*
469     * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate.
470     * pScrn->driverPrivate is initialised to NULL, so we can check if
471     * the allocation has already been done.
472     */
473    if (pScrn->driverPrivate != NULL)
474	return TRUE;
475
476    pScrn->driverPrivate = xnfcalloc(sizeof(S3VRec), 1);
477    /* Initialise it here when needed (or possible) */
478
479    return TRUE;
480}
481
482static void
483S3VFreeRec(ScrnInfoPtr pScrn)
484{
485    PVERB5("	S3VFreeRec\n");
486    if (pScrn->driverPrivate == NULL)
487	return;
488    xfree(pScrn->driverPrivate);
489    pScrn->driverPrivate = NULL;
490}
491
492static const OptionInfoRec *
493S3VAvailableOptions(int chipid, int busid)
494{
495    return S3VOptions;
496}
497
498static void
499S3VIdentify(int flags)
500{
501    PVERB5("	S3VIdentify\n");
502    xf86PrintChipsets(S3VIRGE_NAME,
503	"driver (version " S3VIRGE_VERSION_NAME ") for S3 ViRGE chipsets",
504	S3VChipsets);
505}
506
507
508static Bool
509S3VProbe(DriverPtr drv, int flags)
510{
511    int i;
512    GDevPtr *devSections;
513    int *usedChips;
514    int numDevSections;
515    int numUsed;
516    Bool foundScreen = FALSE;
517
518    PVERB5("	S3VProbe begin\n");
519
520    if ((numDevSections = xf86MatchDevice(S3VIRGE_DRIVER_NAME,
521					  &devSections)) <= 0) {
522	/*
523	 * There's no matching device section in the config file, so quit
524	 * now.
525	 */
526	return FALSE;
527    }
528
529#ifndef XSERVER_LIBPCIACCESS
530    if (xf86GetPciVideoInfo() == NULL) {
531	return FALSE;
532    }
533#endif
534
535    numUsed = xf86MatchPciInstances(S3VIRGE_NAME, PCI_S3_VENDOR_ID,
536				    S3VChipsets, S3VPciChipsets, devSections,
537				    numDevSections, drv, &usedChips);
538
539    /* Free it since we don't need that list after this */
540    xfree(devSections);
541    if (numUsed <= 0)
542	return FALSE;
543
544    if (flags & PROBE_DETECT)
545	foundScreen = TRUE;
546    else for (i = 0; i < numUsed; i++) {
547	/* Allocate a ScrnInfoRec and claim the slot */
548	ScrnInfoPtr pScrn = NULL;
549	if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
550					       S3VPciChipsets,NULL,NULL, NULL,
551					       NULL,NULL))) {
552	    /* Fill in what we can of the ScrnInfoRec */
553	    pScrn->driverVersion = S3VIRGE_DRIVER_VERSION;
554	    pScrn->driverName	 = S3VIRGE_DRIVER_NAME;
555	    pScrn->name		 = S3VIRGE_NAME;
556	    pScrn->Probe	 = S3VProbe;
557	    pScrn->PreInit	 = S3VPreInit;
558	    pScrn->ScreenInit	 = S3VScreenInit;
559	    pScrn->SwitchMode	 = S3VSwitchMode;
560	    pScrn->AdjustFrame	 = S3VAdjustFrame;
561	    pScrn->EnterVT	 = S3VEnterVT;
562	    pScrn->LeaveVT	 = S3VLeaveVT;
563	    pScrn->FreeScreen	 = NULL; /*S3VFreeScreen;*/
564	    pScrn->ValidMode	 = S3VValidMode;
565	    foundScreen = TRUE;
566	}
567    }
568    xfree(usedChips);
569    PVERB5("	S3VProbe end\n");
570    return foundScreen;
571}
572
573
574/* Mandatory */
575static Bool
576S3VPreInit(ScrnInfoPtr pScrn, int flags)
577{
578    EntityInfoPtr pEnt;
579    S3VPtr ps3v;
580    MessageType from;
581    int i;
582    double real;
583    ClockRangePtr clockRanges;
584    char *mod = NULL;
585    const char *reqSym = NULL;
586    char *s;
587
588    unsigned char config1, config2, m, n, n1, n2, cr66 = 0;
589    int mclk;
590
591    vgaHWPtr hwp;
592    int vgaCRIndex, vgaCRReg, vgaIOBase;
593
594    PVERB5("	S3VPreInit 1\n");
595
596    if (flags & PROBE_DETECT) {
597	  S3VProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
598      return TRUE;
599      }
600
601    /*
602     * Note: This function is only called once at server startup, and
603     * not at the start of each server generation.  This means that
604     * only things that are persistent across server generations can
605     * be initialised here.  xf86Screens[] is (pScrn is a pointer to one
606     * of these).  Privates allocated using xf86AllocateScrnInfoPrivateIndex()
607     * are too, and should be used for data that must persist across
608     * server generations.
609     *
610     * Per-generation data should be allocated with
611     * AllocateScreenPrivateIndex() from the ScreenInit() function.
612     */
613
614    /* The vgahw module should be loaded here when needed */
615
616    if (!xf86LoadSubModule(pScrn, "vgahw"))
617	return FALSE;
618
619    xf86LoaderReqSymLists(vgahwSymbols, NULL);
620
621    /*
622     * Allocate a vgaHWRec
623     */
624    if (!vgaHWGetHWRec(pScrn))
625	return FALSE;
626
627
628    /* Set pScrn->monitor */
629    pScrn->monitor = pScrn->confScreen->monitor;
630
631    /*
632     * The first thing we should figure out is the depth, bpp, etc.
633     * We support both 24bpp and 32bpp layouts, so indicate that.
634     */
635    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb |
636				SupportConvert32to24 | PreferConvert32to24)) {
637	return FALSE;
638    } else {
639	/* Check that the returned depth is one we support */
640	switch (pScrn->depth) {
641	case 8:
642	case 15:
643	case 16:
644	case 24:
645	    /* OK */
646	    break;
647	default:
648	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
649		       "Given depth (%d) is not supported by this driver\n",
650		       pScrn->depth);
651	    return FALSE;
652	}
653    }
654    xf86PrintDepthBpp(pScrn);
655
656    /* Get the depth24 pixmap format */
657    if (pScrn->depth == 24 && pix24bpp == 0)
658	pix24bpp = xf86GetBppFromDepth(pScrn, 24);
659
660    /*
661     * This must happen after pScrn->display has been set because
662     * xf86SetWeight references it.
663     */
664    if (pScrn->depth > 8) {
665	/* The defaults are OK for us */
666	rgb zeros = {0, 0, 0};
667
668	if (!xf86SetWeight(pScrn, zeros, zeros)) {
669	    return FALSE;
670	} else {
671	    /* XXX check that weight returned is supported */
672            ;
673        }
674    }
675
676    if (!xf86SetDefaultVisual(pScrn, -1)) {
677	return FALSE;
678    } else {		/* editme - from MGA, does ViRGE? */
679	/* We don't currently support DirectColor at > 8bpp */
680	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
681	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
682		       " (%s) is not supported at depth %d\n",
683		       xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
684	    return FALSE;
685	}
686    }
687
688    /* We use a programmable clock */
689    pScrn->progClock = TRUE;
690
691    /* Allocate the S3VRec driverPrivate */
692    if (!S3VGetRec(pScrn)) {
693	return FALSE;
694    }
695    ps3v = S3VPTR(pScrn);
696
697    /* Collect all of the relevant option flags (fill in pScrn->options) */
698    xf86CollectOptions(pScrn, NULL);
699
700    /* Set the bits per RGB for 8bpp mode */
701    if (pScrn->depth == 8) {
702    				/* ViRGE supports 6 RGB bits in depth 8 */
703				/* modes (with 256 entry LUT) */
704      pScrn->rgbBits = 6;
705    }
706
707    /* Process the options */
708    if (!(ps3v->Options = xalloc(sizeof(S3VOptions))))
709	return FALSE;
710    memcpy(ps3v->Options, S3VOptions, sizeof(S3VOptions));
711    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ps3v->Options);
712
713
714    if (xf86ReturnOptValBool(ps3v->Options, OPTION_PCI_BURST, FALSE)) {
715	ps3v->pci_burst = TRUE;
716	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_burst - PCI burst read enabled\n");
717    } else
718   	ps3v->pci_burst = FALSE;
719					/* default */
720    ps3v->NoPCIRetry = 1;
721   					/* Set option */
722    if (xf86ReturnOptValBool(ps3v->Options, OPTION_PCI_RETRY, FALSE)) {
723      if (xf86ReturnOptValBool(ps3v->Options, OPTION_PCI_BURST, FALSE)) {
724      	ps3v->NoPCIRetry = 0;
725	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n");
726	}
727      else {
728	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
729		"\"pci_retry\" option requires \"pci_burst\".\n");
730	}
731    }
732    if (xf86IsOptionSet(ps3v->Options, OPTION_FIFO_CONSERV)) {
733	ps3v->fifo_conservative = TRUE;
734	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_conservative set\n");
735    } else
736   	ps3v->fifo_conservative = FALSE;
737
738    if (xf86IsOptionSet(ps3v->Options, OPTION_FIFO_MODERATE)) {
739	ps3v->fifo_moderate = TRUE;
740	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_moderate set\n");
741    } else
742   	ps3v->fifo_moderate = FALSE;
743
744    if (xf86IsOptionSet(ps3v->Options, OPTION_FIFO_AGGRESSIVE)) {
745	ps3v->fifo_aggressive = TRUE;
746	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_aggressive set\n");
747    } else
748   	ps3v->fifo_aggressive = FALSE;
749
750    if (xf86IsOptionSet(ps3v->Options, OPTION_SLOW_EDODRAM)) {
751	ps3v->slow_edodram = TRUE;
752	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: slow_edodram set\n");
753    } else
754   	ps3v->slow_edodram = FALSE;
755
756    if (xf86IsOptionSet(ps3v->Options, OPTION_SLOW_DRAM)) {
757	ps3v->slow_dram = TRUE;
758	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: slow_dram set\n");
759    } else
760   	ps3v->slow_dram = FALSE;
761
762    if (xf86IsOptionSet(ps3v->Options, OPTION_FAST_DRAM)) {
763	ps3v->fast_dram = TRUE;
764	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fast_dram set\n");
765    } else
766   	ps3v->fast_dram = FALSE;
767
768    if (xf86IsOptionSet(ps3v->Options, OPTION_FPM_VRAM)) {
769	ps3v->fpm_vram = TRUE;
770	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fpm_vram set\n");
771    } else
772   	ps3v->fpm_vram = FALSE;
773
774    if (xf86ReturnOptValBool(ps3v->Options, OPTION_NOACCEL, FALSE)) {
775	ps3v->NoAccel = TRUE;
776	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: NoAccel - Acceleration disabled\n");
777    } else
778   	ps3v->NoAccel = FALSE;
779
780    if (xf86ReturnOptValBool(ps3v->Options, OPTION_EARLY_RAS_PRECHARGE, FALSE)) {
781	ps3v->early_ras_precharge = TRUE;
782	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: early_ras_precharge set\n");
783    } else
784   	ps3v->early_ras_precharge = FALSE;
785
786    if (xf86ReturnOptValBool(ps3v->Options, OPTION_LATE_RAS_PRECHARGE, FALSE)) {
787	ps3v->late_ras_precharge = TRUE;
788	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: late_ras_precharge set\n");
789    } else
790   	ps3v->late_ras_precharge = FALSE;
791
792    if (xf86ReturnOptValBool(ps3v->Options, OPTION_LCD_CENTER, FALSE)) {
793	ps3v->lcd_center = TRUE;
794	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: lcd_center set\n");
795    } else
796   	ps3v->lcd_center = FALSE;
797
798    if (xf86ReturnOptValBool(ps3v->Options, OPTION_SHOWCACHE, FALSE)) {
799	ps3v->ShowCache = TRUE;
800	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: show_cache set\n");
801    } else
802   	ps3v->ShowCache = FALSE;
803
804    if (xf86GetOptValInteger(ps3v->Options, OPTION_LCDCLOCK, &ps3v->LCDClk)) {
805	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: lcd_setclk set to %1.3f Mhz\n",
806		ps3v->LCDClk / 1000.0 );
807    } else
808   	ps3v->LCDClk = 0;
809
810    if (xf86GetOptValFreq(ps3v->Options, OPTION_MCLK, OPTUNITS_MHZ, &real)) {
811	ps3v->MCLK = (int)(real * 1000.0);
812    	if (ps3v->MCLK <= 100000) {
813	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_mclk set to %1.3f Mhz\n",
814		ps3v->MCLK / 1000.0 );
815	} else {
816	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING
817	  	, "Memory Clock value of %1.3f MHz is larger than limit of 100 MHz\n"
818		, ps3v->MCLK/1000.0);
819	  ps3v->MCLK = 0;
820	}
821    } else
822   	ps3v->MCLK = 0;
823
824    if (xf86GetOptValFreq(ps3v->Options, OPTION_REFCLK, OPTUNITS_MHZ, &real)) {
825	ps3v->REFCLK = (int)(real * 1000.0);
826	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_refclk set to %1.3f Mhz\n",
827		   ps3v->REFCLK / 1000.0 );
828    } else
829   	ps3v->REFCLK = 0;
830
831    from = X_DEFAULT;
832    ps3v->hwcursor = TRUE;
833    if (xf86GetOptValBool(ps3v->Options, OPTION_HWCURSOR, &ps3v->hwcursor))
834	  from = X_CONFIG;
835    if (xf86ReturnOptValBool(ps3v->Options, OPTION_SWCURSOR, FALSE)) {
836	  ps3v->hwcursor = FALSE;
837	  from = X_CONFIG;
838    }
839    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s Cursor\n",
840		ps3v->hwcursor ? "HW" : "SW");
841
842    if (xf86GetOptValBool(ps3v->Options, OPTION_SHADOW_FB,&ps3v->shadowFB))
843	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n",
844		   ps3v->shadowFB ? "enabled" : "disabled");
845
846    if ((s = xf86GetOptValString(ps3v->Options, OPTION_ROTATE))) {
847	if(!xf86NameCmp(s, "CW")) {
848	    /* accel is disabled below for shadowFB */
849	    ps3v->shadowFB = TRUE;
850	    ps3v->rotate = 1;
851	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
852		       "Rotating screen clockwise - acceleration disabled\n");
853	} else if(!xf86NameCmp(s, "CCW")) {
854	    ps3v->shadowFB = TRUE;
855	    ps3v->rotate = -1;
856	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
857		       "counter clockwise - acceleration disabled\n");
858	} else {
859	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
860		       "value for Option \"Rotate\"\n", s);
861	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
862		       "Valid options are \"CW\" or \"CCW\"\n");
863	}
864    }
865
866    if (ps3v->shadowFB && !ps3v->NoAccel) {
867	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
868		   "HW acceleration not supported with \"shadowFB\".\n");
869	ps3v->NoAccel = TRUE;
870    }
871
872    if (ps3v->rotate && ps3v->hwcursor) {
873	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
874		   "HW cursor not supported with \"rotate\".\n");
875	ps3v->hwcursor = FALSE;
876    }
877
878    if (xf86IsOptionSet(ps3v->Options, OPTION_MX_CR3A_FIX))
879      {
880	if (xf86GetOptValBool(ps3v->Options, OPTION_MX_CR3A_FIX ,&ps3v->mx_cr3a_fix))
881	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "%s mx_cr3a_fix.\n",
882		     ps3v->mx_cr3a_fix ? "Enabling (default)" : "Disabling");
883      }
884    else
885      {
886	ps3v->mx_cr3a_fix = TRUE;
887	xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "mx_cr3a_fix.\n");
888      }
889
890    /* Find the PCI slot for this screen */
891    /*
892     * XXX Ignoring the Type list for now.  It might be needed when
893     * multiple cards are supported.
894     */
895    if (pScrn->numEntities > 1) {
896	S3VFreeRec(pScrn);
897	return FALSE;
898    }
899
900    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
901
902    if (pEnt->resources) {
903	xfree(pEnt);
904	S3VFreeRec(pScrn);
905	return FALSE;
906    }
907
908#if USE_INT10
909    if (xf86LoadSubModule(pScrn, "int10")) {
910 	xf86Int10InfoPtr pInt;
911 	xf86LoaderReqSymLists(int10Symbols, NULL);
912#if 1
913	xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
914	pInt = xf86InitInt10(pEnt->index);
915	xf86FreeInt10(pInt);
916#endif
917    }
918#endif
919    if (xf86LoadSubModule(pScrn, "vbe")) {
920	xf86LoaderReqSymLists(vbeSymbols, NULL);
921	ps3v->pVbe =  VBEInit(NULL,pEnt->index);
922    }
923
924    ps3v->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
925    xf86RegisterResources(pEnt->index,NULL,ResNone);
926    xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr);
927    xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr);
928
929    /*
930     * Set the Chipset and ChipRev, allowing config file entries to
931     * override.
932     */
933    if (pEnt->device->chipset && *pEnt->device->chipset) {
934	pScrn->chipset = pEnt->device->chipset;
935        ps3v->Chipset = xf86StringToToken(S3VChipsets, pScrn->chipset);
936        from = X_CONFIG;
937    } else if (pEnt->device->chipID >= 0) {
938	ps3v->Chipset = pEnt->device->chipID;
939	pScrn->chipset = (char *)xf86TokenToString(S3VChipsets, ps3v->Chipset);
940	from = X_CONFIG;
941  	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
942		   ps3v->Chipset);
943    } else {
944	from = X_PROBED;
945	ps3v->Chipset = PCI_DEV_DEVICE_ID(ps3v->PciInfo);
946	pScrn->chipset = (char *)xf86TokenToString(S3VChipsets, ps3v->Chipset);
947    }
948
949    if (pEnt->device->chipRev >= 0) {
950	ps3v->ChipRev = pEnt->device->chipRev;
951	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
952		   ps3v->ChipRev);
953    } else {
954        ps3v->ChipRev = PCI_DEV_REVISION(ps3v->PciInfo);
955    }
956    xfree(pEnt);
957
958    /*
959     * This shouldn't happen because such problems should be caught in
960     * S3VProbe(), but check it just in case.
961     */
962    if (pScrn->chipset == NULL) {
963	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
964		   "ChipID 0x%04X is not recognised\n", ps3v->Chipset);
965	vbeFree(ps3v->pVbe);
966	ps3v->pVbe = NULL;
967	return FALSE;
968    }
969    if (ps3v->Chipset < 0) {
970	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
971		   "Chipset \"%s\" is not recognised\n", pScrn->chipset);
972	vbeFree(ps3v->pVbe);
973	ps3v->pVbe = NULL;
974	return FALSE;
975    }
976
977    xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
978
979#ifndef XSERVER_LIBPCIACCESS
980    ps3v->PciTag = pciTag(ps3v->PciInfo->bus, ps3v->PciInfo->device,
981			  ps3v->PciInfo->func);
982#endif
983
984    /* Handle XVideo after we know chipset, so we can give an */
985    /* intelligent comment about support */
986    if (xf86IsOptionSet(ps3v->Options, OPTION_XVIDEO))
987      {
988	if(S3VQueryXvCapable(pScrn))
989	  {
990	    if (xf86GetOptValBool(ps3v->Options, OPTION_XVIDEO ,&ps3v->XVideo))
991	      xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "%s XVideo.\n",
992			 ps3v->XVideo ? "Enabling (default)" : "Disabling");
993	  }
994	else
995	  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "XVideo not supported.\n");
996      }
997    else
998      {
999	ps3v->XVideo = S3VQueryXvCapable(pScrn);
1000	if(ps3v->XVideo)
1001	  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "XVideo supported.\n");
1002	else
1003	  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "XVideo not supported.\n");
1004      }
1005
1006
1007  S3VMapMem(pScrn);
1008  hwp = VGAHWPTR(pScrn);
1009  vgaIOBase = hwp->IOBase;
1010  vgaCRIndex = vgaIOBase + 4;
1011  vgaCRReg = vgaIOBase + 5;
1012
1013    xf86ErrorFVerb(VERBLEV,
1014	"	S3VPreInit vgaCRIndex=%x, vgaIOBase=%x, MMIOBase=%p\n",
1015	vgaCRIndex, vgaIOBase, hwp->MMIOBase );
1016
1017
1018#if 0	/* Not needed in 4.0 flavors */
1019   /* Unlock sys regs */
1020   VGAOUT8(vgaCRIndex, 0x38);
1021   VGAOUT8(vgaCRReg, 0x48);
1022#endif
1023
1024   /* Next go on to detect amount of installed ram */
1025
1026   VGAOUT8(vgaCRIndex, 0x36);           /* for register CR36 (CONFG_REG1),*/
1027   config1 = VGAIN8(vgaCRReg);          /* get amount of vram installed   */
1028
1029   VGAOUT8(vgaCRIndex, 0x37);           /* for register CR37 (CONFG_REG2),*/
1030   config2 = VGAIN8(vgaCRReg);          /* get amount of off-screen ram   */
1031
1032   if (xf86LoadSubModule(pScrn, "ddc")) {
1033       xf86MonPtr pMon = NULL;
1034
1035       xf86LoaderReqSymLists(ddcSymbols, NULL);
1036       if ((ps3v->pVbe)
1037	   && ((pMon = xf86PrintEDID(vbeDoEDID(ps3v->pVbe, NULL))) != NULL))
1038	   xf86SetDDCproperties(pScrn,pMon);
1039       else if (!S3Vddc1(pScrn->scrnIndex)) {
1040	   S3Vddc2(pScrn->scrnIndex);
1041       }
1042   }
1043   if (ps3v->pVbe) {
1044       vbeFree(ps3v->pVbe);
1045       ps3v->pVbe = NULL;
1046   }
1047
1048   /*
1049    * If the driver can do gamma correction, it should call xf86SetGamma()
1050    * here. (from MGA, no ViRGE gamma support yet, but needed for
1051    * xf86HandleColormaps support.)
1052    */
1053   {
1054       Gamma zeros = {0.0, 0.0, 0.0};
1055
1056       if (!xf86SetGamma(pScrn, zeros)) {
1057	   return FALSE;
1058       }
1059   }
1060
1061   /* And compute the amount of video memory and offscreen memory */
1062   ps3v->MemOffScreen = 0;
1063
1064   if (!pScrn->videoRam) {
1065      if (ps3v->Chipset == S3_ViRGE_VX) {
1066	  switch((config2 & 0x60) >> 5) {
1067         case 1:
1068            ps3v->MemOffScreen = 4 * 1024;
1069            break;
1070         case 2:
1071            ps3v->MemOffScreen = 2 * 1024;
1072            break;
1073         }
1074         switch ((config1 & 0x60) >> 5) {
1075         case 0:
1076            ps3v->videoRamKbytes = 2 * 1024;
1077            break;
1078         case 1:
1079            ps3v->videoRamKbytes = 4 * 1024;
1080            break;
1081         case 2:
1082            ps3v->videoRamKbytes = 6 * 1024;
1083            break;
1084         case 3:
1085            ps3v->videoRamKbytes = 8 * 1024;
1086            break;
1087         }
1088         ps3v->videoRamKbytes -= ps3v->MemOffScreen;
1089      }
1090      else if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset)) {
1091         switch((config1 & 0xE0) >> 5) {
1092         case 0:  /* 8MB -- only 4MB usable for display/cursor */
1093            ps3v->videoRamKbytes = 4 * 1024;
1094            ps3v->MemOffScreen   = 4 * 1024;
1095            break;
1096         case 1:    /* 32 bit interface -- yuck */
1097	   xf86ErrorFVerb(VERBLEV,
1098			  "	found 32 bit interface for video memory -- yuck:(\n");
1099         case 2:
1100            ps3v->videoRamKbytes = 4 * 1024;
1101            break;
1102         case 6:
1103            ps3v->videoRamKbytes = 2 * 1024;
1104            break;
1105         }
1106      }
1107      else if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
1108        switch((config1 & 0xE0) >> 5) {
1109        case 0:
1110        case 2:
1111           ps3v->videoRamKbytes = 4 * 1024;
1112           break;
1113        case 4:
1114           ps3v->videoRamKbytes = 2 * 1024;
1115           break;
1116        }
1117      }
1118      else if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
1119	  switch((config1 & 0xC0) >> 6) {
1120	  case 1:
1121            ps3v->videoRamKbytes = 4 * 1024;
1122            break;
1123         case 3:
1124            ps3v->videoRamKbytes = 2 * 1024;
1125            break;
1126         }
1127      }
1128      else {
1129         switch((config1 & 0xE0) >> 5) {
1130         case 0:
1131            ps3v->videoRamKbytes = 4 * 1024;
1132            break;
1133         case 4:
1134            ps3v->videoRamKbytes = 2 * 1024;
1135            break;
1136         case 6:
1137            ps3v->videoRamKbytes = 1 * 1024;
1138            break;
1139         }
1140      }
1141      					/* And save a byte value also */
1142      ps3v->videoRambytes = ps3v->videoRamKbytes * 1024;
1143      				       	/* Make sure the screen also */
1144					/* has correct videoRam setting */
1145      pScrn->videoRam = ps3v->videoRamKbytes;
1146
1147      if (ps3v->MemOffScreen)
1148	 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1149	    	"videoram:  %dk (plus %dk off-screen)\n",
1150                ps3v->videoRamKbytes, ps3v->MemOffScreen);
1151      else
1152	 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "videoram:  %dk\n",
1153                ps3v->videoRamKbytes);
1154   } else {
1155   					/* Note: if ram is not probed then */
1156					/* ps3v->videoRamKbytes will not be init'd */
1157					/* should we? can do it here... */
1158
1159
1160      xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "videoram:  %dk\n",
1161              	ps3v->videoRamKbytes);
1162   }
1163
1164   /* reset S3 graphics engine to avoid memory corruption */
1165   if (ps3v->Chipset != S3_ViRGE_VX) {
1166      VGAOUT8(vgaCRIndex, 0x66);
1167      cr66 = VGAIN8(vgaCRReg);
1168      VGAOUT8(vgaCRReg, cr66 | 0x02);
1169      usleep(10000);  /* wait a little bit... */
1170   }
1171
1172   /*
1173    * There was a lot of plainly wrong code here. pScrn->clock is just a list
1174    * of supported _dotclocks_ used when you don't have a programmable clock.
1175    *
1176    * S3V and Savage seem to think that this is the max ramdac speed. This
1177    * driver just ignores the whole mess done before and sets
1178    * clockRange->maxClock differently slightly later.
1179    *
1180    * In order to not ditch information, here is a table of what the dacspeeds
1181    * "were" before the cleanup.
1182    *
1183    * Chipset              ### >= 24bpp ### lower
1184    *
1185    *  S3_ViRGE_VX               135000     220000
1186    *  S3_TRIO_3D_2X_SERIES      135000     230000
1187    *  S3_ViRGE_DXGX             135000     170000
1188    *  S3_ViRGE_GX2_SERIES       135000     170000
1189    *  S3_ViRGE_MX_SERIES        100000     135000
1190    *
1191    * Others devices get:
1192    *      > 24bpp:  57000
1193    *      = 24bpp:  95000
1194    *      < 24bpp: 135000
1195    *
1196    * Special case is the MELCO BIOS:
1197    *      > 24bpp:  83500
1198    *      = 24bpp: 111500
1199    *      >  8bpp: 162500
1200    *      <= 8bpp: 191500
1201    */
1202
1203   if (find_bios_string(ps3v, BIOS_BASE, "S3 86C325",
1204			"MELCO WGP-VG VIDEO BIOS") != NULL) {
1205      if (xf86GetVerbosity())
1206	 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MELCO BIOS found\n");
1207      if (ps3v->MCLK <= 0)
1208          ps3v->MCLK = 74000;
1209   }
1210
1211   if (ps3v->Chipset != S3_ViRGE_VX) {
1212      VGAOUT8(vgaCRIndex, 0x66);
1213      VGAOUT8(vgaCRReg, cr66 & ~0x02);  /* clear reset flag */
1214      usleep(10000);  /* wait a little bit... */
1215   }
1216
1217   /* Detect current MCLK and print it for user */
1218   VGAOUT8(0x3c4, 0x08);
1219   VGAOUT8(0x3c5, 0x06);
1220   VGAOUT8(0x3c4, 0x10);
1221   n = VGAIN8(0x3c5);
1222   VGAOUT8(0x3c4, 0x11);
1223   m = VGAIN8(0x3c5);
1224   m &= 0x7f;
1225   n1 = n & 0x1f;
1226   n2 = (n>>5) & 0x03;
1227   mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
1228   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
1229      MessageType is_probed = X_PROBED;
1230      /*
1231       * try to figure out which reference clock is used:
1232       * Toshiba Tecra 5x0/7x0 seems to use 28.636 MHz
1233       * Compaq Armada 7x00 uses 14.318 MHz
1234       */
1235      if (find_bios_string(ps3v, BIOS_BASE, "COMPAQ M5 BIOS", NULL) != NULL) {
1236	 if (xf86GetVerbosity())
1237	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "COMPAQ M5 BIOS found\n");
1238	 /* ps3v->refclk_fact = 1.0; */
1239      }
1240      else if (find_bios_string(ps3v, BIOS_BASE, "TOSHIBA Video BIOS", NULL) != NULL) {
1241	 if (xf86GetVerbosity())
1242	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "TOSHIBA Video BIOS found\n");
1243	 /* ps3v->refclk_fact = 2.0; */
1244      }
1245      /* else */ {  /* always use guessed value... */
1246	 if (mclk > 60000)
1247	    ps3v->refclk_fact = 1.0;
1248	 else
1249	    ps3v->refclk_fact = 2.0;  /* don't know why ??? */
1250      }
1251      if (ps3v->REFCLK != 0) {
1252	 ps3v->refclk_fact = ps3v->REFCLK / 14318.0;
1253	 is_probed = X_CONFIG;
1254      }
1255      else
1256	 ps3v->REFCLK = (int)(14318.18 * ps3v->refclk_fact);
1257
1258      mclk = (int)(mclk * ps3v->refclk_fact);
1259      xf86DrvMsg(pScrn->scrnIndex, is_probed, "assuming RefCLK value of %1.3f MHz\n",
1260		 ps3v->REFCLK / 1000.0);
1261   }
1262   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of %1.3f MHz\n",
1263	     mclk / 1000.0);
1264
1265   if (S3_ViRGE_MX_SERIES(ps3v->Chipset) && xf86GetVerbosity()) {
1266       int lcdclk, h_lcd, v_lcd;
1267       if (ps3v->LCDClk) {
1268	  lcdclk = ps3v->LCDClk;
1269       } else {
1270	  unsigned char sr12, sr13, sr29;
1271          VGAOUT8(0x3c4, 0x12);
1272          sr12 = VGAIN8(0x3c5);
1273          VGAOUT8(0x3c4, 0x13);
1274          sr13 = VGAIN8(0x3c5) & 0x7f;
1275          VGAOUT8(0x3c4, 0x29);
1276          sr29 = VGAIN8(0x3c5);
1277    	  n1 = sr12 & 0x1f;
1278    	  n2 = ((sr12>>6) & 0x03) | ((sr29 & 0x01) << 2);
1279          lcdclk = ((int)(ps3v->refclk_fact * 1431818 * (sr13+2)) / (n1+2) / (1 << n2) + 50) / 100;
1280       }
1281       VGAOUT8(0x3c4, 0x61);
1282       h_lcd = VGAIN8(0x3c5);
1283       VGAOUT8(0x3c4, 0x66);
1284       h_lcd |= ((VGAIN8(0x3c5) & 0x02) << 7);
1285       h_lcd = (h_lcd+1) * 8;
1286       VGAOUT8(0x3c4, 0x69);
1287       v_lcd = VGAIN8(0x3c5);
1288       VGAOUT8(0x3c4, 0x6e);
1289       v_lcd |= ((VGAIN8(0x3c5) & 0x70) << 4);
1290       v_lcd++;
1291       xf86DrvMsg(pScrn->scrnIndex
1292	      , ps3v->LCDClk ? X_CONFIG : X_PROBED
1293       	      , "LCD size %dx%d, clock %1.3f MHz\n"
1294	      , h_lcd, v_lcd
1295	      , lcdclk / 1000.0);
1296   }
1297
1298   S3VDisableMmio(pScrn);
1299   S3VUnmapMem(pScrn);
1300
1301   /* And finally set various possible option flags */
1302
1303   ps3v->bankedMono = FALSE;
1304
1305
1306#if 0
1307   vga256InfoRec.directMode = XF86DGADirectPresent;
1308#endif
1309
1310    /*
1311     * xf86ValidateModes will check that the mode HTotal and VTotal values
1312     * don't exceed the chipset's limit if pScrn->maxHValue and
1313     * pScrn->maxVValue are set.
1314     */
1315
1316    /* todo -  The virge limit is 2048 vertical & horizontal */
1317    /* pixels, not clock register settings. */
1318			 	/* true for all ViRGE? */
1319  pScrn->maxHValue = 2048;
1320  pScrn->maxVValue = 2048;
1321
1322    				/* Lower depths default to config file */
1323  pScrn->virtualX = pScrn->display->virtualX;
1324				/* Adjust the virtualX to meet ViRGE hardware */
1325				/* limits for depth 24, bpp 24 & 32.  This is */
1326				/* mostly for 32 bpp as 1024x768 is one pixel */
1327				/* larger than supported. */
1328  if (pScrn->depth == 24)
1329      if ( ((pScrn->bitsPerPixel/8) * pScrn->display->virtualX) > 4095 ) {
1330        pScrn->virtualX = 4095 / (pScrn->bitsPerPixel / 8);
1331        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1332	   "Virtual width adjusted, max for this depth & bpp is %d.\n",
1333	   pScrn->virtualX );
1334      }
1335
1336    /*
1337     * Setup the ClockRanges, which describe what clock ranges are available,
1338     * and what sort of modes they can be used for.
1339     */
1340    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
1341    clockRanges->next = NULL;
1342    clockRanges->minClock = 10000;
1343    if (ps3v->Chipset == S3_ViRGE_VX )
1344        clockRanges->maxClock = 440000;
1345    else
1346        clockRanges->maxClock = 270000;
1347    clockRanges->clockIndex = -1;		/* programmable */
1348    clockRanges->interlaceAllowed = TRUE;	/* yes, S3V SVGA 3.3.2 */
1349    clockRanges->doubleScanAllowed = TRUE;
1350
1351  					/* Screen pointer 		*/
1352    i = xf86ValidateModes(pScrn,
1353  					/* Available monitor modes 	*/
1354					/* (DisplayModePtr availModes)  */
1355		pScrn->monitor->Modes,
1356					/* req mode names for screen 	*/
1357					/* (char **modesNames)  	*/
1358		pScrn->display->modes,
1359					/* list of clock ranges allowed */
1360					/* (ClockRangePtr clockRanges) 	*/
1361		clockRanges,
1362					/* list of driver line pitches, */
1363					/* supply or NULL and use min/	*/
1364					/* max below			*/
1365					/* (int *linePitches)		*/
1366		NULL,
1367					/* min lin pitch (width)	*/
1368					/* (int minPitch)		*/
1369		256,
1370					/* max line pitch (width)	*/
1371					/* (int maxPitch)		*/
1372		2048,
1373					/* bits of granularity for line	*/
1374					/* pitch (width) above, reguired*/
1375					/* (int pitchInc)		*/
1376		pScrn->bitsPerPixel,
1377					/* min virt height, 0 no limit	*/
1378					/* (int minHeight)		*/
1379		128,
1380					/* max virt height, 0 no limit	*/
1381					/* (int maxHeight)		*/
1382		2048,
1383					/* force virtX, 0 for auto 	*/
1384					/* (int VirtualX) 		*/
1385					/* value is adjusted above for  */
1386					/* hardware limits */
1387		pScrn->virtualX,
1388					/* force virtY, 0 for auto	*/
1389					/* (int VirtualY)		*/
1390		pScrn->display->virtualY,
1391					/* size (bytes) of aper used to	*/
1392					/* access video memory		*/
1393					/* (unsigned long apertureSize)	*/
1394		ps3v->videoRambytes,
1395					/* how to pick mode */
1396					/* (LookupModeFlags strategy)	*/
1397		LOOKUP_BEST_REFRESH);
1398
1399    if (i == -1) {
1400	S3VFreeRec(pScrn);
1401	return FALSE;
1402    }
1403    /* Prune the modes marked as invalid */
1404    xf86PruneDriverModes(pScrn);
1405
1406    if (i == 0 || pScrn->modes == NULL) {
1407	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1408	S3VFreeRec(pScrn);
1409	return FALSE;
1410    }
1411
1412    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
1413    /*xf86SetCrtcForModes(pScrn, 0);*/
1414
1415    /* Set the current mode to the first in the list */
1416    pScrn->currentMode = pScrn->modes;
1417
1418    /* Print the list of modes being used */
1419    xf86PrintModes(pScrn);
1420
1421    /* Set display resolution */
1422    xf86SetDpi(pScrn, 0, 0);
1423
1424    /* Load bpp-specific modules */
1425    if( xf86LoadSubModule(pScrn, "fb") == NULL )
1426    {
1427	S3VFreeRec(pScrn);
1428	return FALSE;
1429    }
1430    xf86LoaderReqSymLists(fbSymbols, NULL);
1431
1432    /* Load XAA if needed */
1433    if (!ps3v->NoAccel || ps3v->hwcursor ) {
1434	if (!xf86LoadSubModule(pScrn, "xaa")) {
1435	    S3VFreeRec(pScrn);
1436	    return FALSE;
1437	}
1438	xf86LoaderReqSymLists(xaaSymbols, NULL);
1439    }
1440
1441    /* Load ramdac if needed */
1442    if (ps3v->hwcursor) {
1443	if (!xf86LoadSubModule(pScrn, "ramdac")) {
1444	    S3VFreeRec(pScrn);
1445	    return FALSE;
1446	}
1447	xf86LoaderReqSymLists(ramdacSymbols, NULL);
1448    }
1449
1450    if (ps3v->shadowFB) {
1451	if (!xf86LoadSubModule(pScrn, "shadowfb")) {
1452	    S3VFreeRec(pScrn);
1453	    return FALSE;
1454	}
1455	xf86LoaderReqSymLists(shadowSymbols, NULL);
1456    }
1457
1458    /* Setup WAITFIFO() for accel and ModeInit() */
1459    /* Needs to be done prior to first ModeInit call */
1460    /* and any accel activity. */
1461    switch(ps3v->Chipset)
1462      {
1463	/* GX2_SERIES chips, GX2 & TRIO_3D_2X */
1464      case S3_ViRGE_GX2:
1465      case S3_TRIO_3D_2X:
1466	ps3v->pWaitFifo = S3VWaitFifoGX2;
1467	ps3v->pWaitCmd = S3VWaitCmdGX2;
1468	break;
1469      case S3_ViRGE:
1470      case S3_ViRGE_VX:
1471      default:
1472	ps3v->pWaitFifo = S3VWaitFifoMain;
1473	/* Do nothing... */
1474	ps3v->pWaitCmd = S3VWaitDummy;
1475	break;
1476      }
1477
1478    return TRUE;
1479}
1480
1481
1482/*
1483 * This is called when VT switching back to the X server.  Its job is
1484 * to reinitialise the video mode.
1485 *
1486 * We may wish to unmap video/MMIO memory too.
1487 */
1488
1489
1490/* Mandatory */
1491static Bool
1492S3VEnterVT(int scrnIndex, int flags)
1493{
1494    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1495/*      ScreenPtr pScreen = xf86Screens[scrnIndex]->pScreen; */
1496    /*vgaHWPtr hwp = VGAHWPTR(pScrn);*/
1497
1498    PVERB5("	S3VEnterVT\n");
1499    /*vgaHWUnlockMMIO(hwp);*/
1500    				/* Enable MMIO and map memory */
1501#ifdef unmap_always
1502    S3VMapMem(pScrn);
1503#endif
1504    S3VEnableMmio(pScrn);
1505
1506    S3VSave(pScrn);
1507    return S3VModeInit(pScrn, pScrn->currentMode);
1508}
1509
1510
1511/*
1512 * This is called when VT switching away from the X server.  Its job is
1513 * to restore the previous (text) mode.
1514 *
1515 * We may wish to remap video/MMIO memory too.
1516 *
1517 */
1518
1519/* Mandatory */
1520static void
1521S3VLeaveVT(int scrnIndex, int flags)
1522{
1523    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1524    vgaHWPtr hwp = VGAHWPTR(pScrn);
1525    S3VPtr ps3v = S3VPTR(pScrn);
1526    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
1527    S3VRegPtr S3VSavePtr = &ps3v->SavedReg;
1528
1529    PVERB5("	S3VLeaveVT\n");
1530    					/* Like S3VRestore, but uses passed */
1531					/* mode registers.		    */
1532    S3VWriteMode(pScrn, vgaSavePtr, S3VSavePtr);
1533    					/* Restore standard register access */
1534					/* and unmap memory.		    */
1535    S3VDisableMmio(pScrn);
1536#ifdef unmap_always
1537    S3VUnmapMem(pScrn);
1538#endif
1539    /*vgaHWLockMMIO(hwp);*/
1540
1541}
1542
1543
1544/*
1545 * This function performs the inverse of the restore function: It saves all
1546 * the standard and extended registers that we are going to modify to set
1547 * up a video mode. Again, we also save the STREAMS context if it is needed.
1548 *
1549 * prototype
1550 *   void ChipSave(ScrnInfoPtr pScrn)
1551 *
1552 */
1553
1554static void
1555S3VSave (ScrnInfoPtr pScrn)
1556{
1557  unsigned char cr3a, cr66;
1558  vgaHWPtr hwp = VGAHWPTR(pScrn);
1559  vgaRegPtr vgaSavePtr = &hwp->SavedReg;
1560  S3VPtr ps3v = S3VPTR(pScrn);
1561  S3VRegPtr save = &ps3v->SavedReg;
1562  int vgaCRIndex, vgaCRReg, vgaIOBase;
1563  vgaIOBase = hwp->IOBase;
1564  vgaCRIndex = 0;
1565
1566  vgaCRReg = 0;
1567
1568  vgaCRReg = vgaIOBase + 5;
1569  vgaCRIndex = vgaIOBase + 4;
1570
1571    PVERB5("	S3VSave\n");
1572
1573   /*
1574    * This function will handle creating the data structure and filling
1575    * in the generic VGA portion.
1576    */
1577
1578   VGAOUT8(vgaCRIndex, 0x66);
1579   cr66 = VGAIN8(vgaCRReg);
1580   VGAOUT8(vgaCRReg, cr66 | 0x80);
1581   VGAOUT8(vgaCRIndex, 0x3a);
1582   cr3a = VGAIN8(vgaCRReg);
1583   save->CR3A = cr3a;
1584
1585   VGAOUT8(vgaCRReg, cr3a | 0x80);
1586
1587   /* VGA_SR_MODE saves mode info only, no fonts, no colormap */
1588					/* Save all for primary, anything */
1589					/* for secondary cards?, do MODE */
1590					/* for the moment. */
1591   if (xf86IsPrimaryPci(ps3v->PciInfo))
1592   	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
1593   else
1594   	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_MODE);
1595
1596   VGAOUT8(vgaCRIndex, 0x66);
1597   VGAOUT8(vgaCRReg, cr66);
1598   VGAOUT8(vgaCRIndex, 0x3a);
1599   VGAOUT8(vgaCRReg, cr3a);
1600
1601   /* First unlock extended sequencer regs */
1602   VGAOUT8(0x3c4, 0x08);
1603   save->SR08 = VGAIN8(0x3c5);
1604   VGAOUT8(0x3c5, 0x06);
1605
1606   /* Now we save all the s3 extended regs we need */
1607   VGAOUT8(vgaCRIndex, 0x31);
1608   save->CR31 = VGAIN8(vgaCRReg);
1609   VGAOUT8(vgaCRIndex, 0x34);
1610   save->CR34 = VGAIN8(vgaCRReg);
1611   VGAOUT8(vgaCRIndex, 0x36);
1612   save->CR36 = VGAIN8(vgaCRReg);
1613
1614   /* workaround cr3a corruption */
1615   if( !(ps3v->mx_cr3a_fix))
1616     {
1617       VGAOUT8(vgaCRIndex, 0x3a);
1618       save->CR3A = VGAIN8(vgaCRReg);
1619     }
1620
1621   if (!S3_TRIO_3D_SERIES(ps3v->Chipset)) {
1622     VGAOUT8(vgaCRIndex, 0x40);
1623     save->CR40 = VGAIN8(vgaCRReg);
1624   }
1625   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
1626     VGAOUT8(vgaCRIndex, 0x41);
1627     save->CR41 = VGAIN8(vgaCRReg);
1628   }
1629   VGAOUT8(vgaCRIndex, 0x42);
1630   save->CR42 = VGAIN8(vgaCRReg);
1631   VGAOUT8(vgaCRIndex, 0x45);
1632   save->CR45 = VGAIN8(vgaCRReg);
1633   VGAOUT8(vgaCRIndex, 0x51);
1634   save->CR51 = VGAIN8(vgaCRReg);
1635   VGAOUT8(vgaCRIndex, 0x53);
1636   save->CR53 = VGAIN8(vgaCRReg);
1637   VGAOUT8(vgaCRIndex, 0x54);
1638   save->CR54 = VGAIN8(vgaCRReg);
1639   VGAOUT8(vgaCRIndex, 0x55);
1640   save->CR55 = VGAIN8(vgaCRReg);
1641   VGAOUT8(vgaCRIndex, 0x58);
1642   save->CR58 = VGAIN8(vgaCRReg);
1643   VGAOUT8(vgaCRIndex, 0x63);
1644   save->CR63 = VGAIN8(vgaCRReg);
1645   VGAOUT8(vgaCRIndex, 0x66);
1646   save->CR66 = VGAIN8(vgaCRReg);
1647   VGAOUT8(vgaCRIndex, 0x67);
1648   save->CR67 = VGAIN8(vgaCRReg);
1649   VGAOUT8(vgaCRIndex, 0x68);
1650   save->CR68 = VGAIN8(vgaCRReg);
1651   VGAOUT8(vgaCRIndex, 0x69);
1652   save->CR69 = VGAIN8(vgaCRReg);
1653
1654   VGAOUT8(vgaCRIndex, 0x33);
1655   save->CR33 = VGAIN8(vgaCRReg);
1656   if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) || S3_ViRGE_GX2_SERIES(ps3v->Chipset)
1657       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
1658   {
1659      VGAOUT8(vgaCRIndex, 0x85);
1660      save->CR85 = VGAIN8(vgaCRReg);
1661   }
1662   if (ps3v->Chipset == S3_ViRGE_DXGX) {
1663      VGAOUT8(vgaCRIndex, 0x86);
1664      save->CR86 = VGAIN8(vgaCRReg);
1665   }
1666   if ((ps3v->Chipset == S3_ViRGE_GX2) ||
1667       S3_ViRGE_MX_SERIES(ps3v->Chipset) ) {
1668      VGAOUT8(vgaCRIndex, 0x7B);
1669      save->CR7B = VGAIN8(vgaCRReg);
1670      VGAOUT8(vgaCRIndex, 0x7D);
1671      save->CR7D = VGAIN8(vgaCRReg);
1672      VGAOUT8(vgaCRIndex, 0x87);
1673      save->CR87 = VGAIN8(vgaCRReg);
1674      VGAOUT8(vgaCRIndex, 0x92);
1675      save->CR92 = VGAIN8(vgaCRReg);
1676      VGAOUT8(vgaCRIndex, 0x93);
1677      save->CR93 = VGAIN8(vgaCRReg);
1678   }
1679   if (ps3v->Chipset == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
1680       S3_ViRGE_MX_SERIES(ps3v->Chipset) || S3_TRIO_3D_SERIES(ps3v->Chipset)) {
1681      VGAOUT8(vgaCRIndex, 0x90);
1682      save->CR90 = VGAIN8(vgaCRReg);
1683      VGAOUT8(vgaCRIndex, 0x91);
1684      save->CR91 = VGAIN8(vgaCRReg);
1685   }
1686
1687   /* Extended mode timings regs */
1688
1689   VGAOUT8(vgaCRIndex, 0x3b);
1690   save->CR3B = VGAIN8(vgaCRReg);
1691   VGAOUT8(vgaCRIndex, 0x3c);
1692   save->CR3C = VGAIN8(vgaCRReg);
1693   VGAOUT8(vgaCRIndex, 0x43);
1694   save->CR43 = VGAIN8(vgaCRReg);
1695   VGAOUT8(vgaCRIndex, 0x5d);
1696   save->CR5D = VGAIN8(vgaCRReg);
1697   VGAOUT8(vgaCRIndex, 0x5e);
1698   save->CR5E = VGAIN8(vgaCRReg);
1699   VGAOUT8(vgaCRIndex, 0x65);
1700   save->CR65 = VGAIN8(vgaCRReg);
1701   VGAOUT8(vgaCRIndex, 0x6d);
1702   save->CR6D = VGAIN8(vgaCRReg);
1703
1704
1705   /* Save sequencer extended regs for DCLK PLL programming */
1706
1707   VGAOUT8(0x3c4, 0x10);
1708   save->SR10 = VGAIN8(0x3c5);
1709   VGAOUT8(0x3c4, 0x11);
1710   save->SR11 = VGAIN8(0x3c5);
1711
1712   VGAOUT8(0x3c4, 0x12);
1713   save->SR12 = VGAIN8(0x3c5);
1714   VGAOUT8(0x3c4, 0x13);
1715   save->SR13 = VGAIN8(0x3c5);
1716   if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
1717     VGAOUT8(0x3c4, 0x29);
1718     save->SR29 = VGAIN8(0x3c5);
1719   }
1720        /* SR 54,55,56,57 undocumented for GX2.  Was this supposed to be CR? */
1721        /* (These used to be part of the above if() */
1722   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
1723     VGAOUT8(0x3c4, 0x54);
1724     save->SR54 = VGAIN8(0x3c5);
1725     VGAOUT8(0x3c4, 0x55);
1726     save->SR55 = VGAIN8(0x3c5);
1727     VGAOUT8(0x3c4, 0x56);
1728     save->SR56 = VGAIN8(0x3c5);
1729     VGAOUT8(0x3c4, 0x57);
1730     save->SR57 = VGAIN8(0x3c5);
1731   }
1732
1733   VGAOUT8(0x3c4, 0x15);
1734   save->SR15 = VGAIN8(0x3c5);
1735   VGAOUT8(0x3c4, 0x18);
1736   save->SR18 = VGAIN8(0x3c5);
1737   if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
1738     VGAOUT8(0x3c4, 0x0a);
1739     save->SR0A = VGAIN8(0x3c5);
1740     VGAOUT8(0x3c4, 0x0F);
1741     save->SR0F = VGAIN8(0x3c5);
1742   }
1743
1744   VGAOUT8(vgaCRIndex, 0x66);
1745   cr66 = VGAIN8(vgaCRReg);
1746   VGAOUT8(vgaCRReg, cr66 | 0x80);
1747   VGAOUT8(vgaCRIndex, 0x3a);
1748   cr3a = VGAIN8(vgaCRReg);
1749   VGAOUT8(vgaCRReg, cr3a | 0x80);
1750
1751   /* And if streams is to be used, save that as well */
1752
1753   if(ps3v->NeedSTREAMS) {
1754      S3VSaveSTREAMS(pScrn, save->STREAMS);
1755      }
1756
1757   /* Now save Memory Interface Unit registers */
1758   if( S3_ViRGE_GX2_SERIES(ps3v->Chipset)
1759      /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
1760     {
1761     /* No MMPR regs on MX & GX2 */
1762     }
1763   else
1764     {
1765     save->MMPR0 = INREG(FIFO_CONTROL_REG);
1766     save->MMPR1 = INREG(MIU_CONTROL_REG);
1767     save->MMPR2 = INREG(STREAMS_TIMEOUT_REG);
1768     save->MMPR3 = INREG(MISC_TIMEOUT_REG);
1769     }
1770
1771   if (xf86GetVerbosity() > 1) {
1772      /* Debug */
1773     /* Which chipsets? */
1774     if (
1775	 /* virge */
1776	 ps3v->Chipset == S3_ViRGE ||
1777	 /* VX */
1778	 S3_ViRGE_VX_SERIES(ps3v->Chipset) ||
1779	 /* DX & GX */
1780	 ps3v->Chipset == S3_ViRGE_DXGX ||
1781	 /* GX2 & Trio3D_2X */
1782	 /* S3_ViRGE_GX2_SERIES(ps3v->Chipset) || */
1783	 /* Trio3D_2X */
1784	 /* S3_TRIO_3D_2X_SERIES(ps3v->Chipset) */
1785	 /* MX & MX+ */
1786	 /* S3_ViRGE_MX_SERIES(ps3v->Chipset) || */
1787	 /* MX+ only */
1788	 /* S3_ViRGE_MXP_SERIES(ps3v->Chipset) || */
1789	 /* Trio3D */
1790	 ps3v->Chipset == S3_TRIO_3D
1791         )
1792       {
1793
1794      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1795         "MMPR regs: %08lx %08lx %08lx %08lx\n",
1796	     (unsigned long)INREG(FIFO_CONTROL_REG),
1797	     (unsigned long)INREG(MIU_CONTROL_REG),
1798	     (unsigned long)INREG(STREAMS_TIMEOUT_REG),
1799	     (unsigned long)INREG(MISC_TIMEOUT_REG));
1800       }
1801
1802      PVERB5("\n\nViRGE driver: saved current video mode. Register dump:\n\n");
1803   }
1804
1805   VGAOUT8(vgaCRIndex, 0x3a);
1806   VGAOUT8(vgaCRReg, cr3a);
1807   VGAOUT8(vgaCRIndex, 0x66);
1808   VGAOUT8(vgaCRReg, cr66);
1809   				/* Dup the VGA & S3V state to the */
1810				/* new mode state, but only first time. */
1811   if( !ps3v->ModeStructInit ) {
1812     /* XXX Should check the return value of vgaHWCopyReg() */
1813     vgaHWCopyReg( &hwp->ModeReg, vgaSavePtr );
1814     memcpy( &ps3v->ModeReg, save, sizeof(S3VRegRec) );
1815     ps3v->ModeStructInit = TRUE;
1816   }
1817
1818   if (xf86GetVerbosity() > 1) S3VPrintRegs(pScrn);
1819
1820   return;
1821}
1822
1823
1824/* This function saves the STREAMS registers to our private structure */
1825
1826static void
1827S3VSaveSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams)
1828{
1829  S3VPtr ps3v = S3VPTR(pScrn);
1830
1831   streams[0] = INREG(PSTREAM_CONTROL_REG);
1832   streams[1] = INREG(COL_CHROMA_KEY_CONTROL_REG);
1833   streams[2] = INREG(SSTREAM_CONTROL_REG);
1834   streams[3] = INREG(CHROMA_KEY_UPPER_BOUND_REG);
1835   streams[4] = INREG(SSTREAM_STRETCH_REG);
1836   streams[5] = INREG(BLEND_CONTROL_REG);
1837   streams[6] = INREG(PSTREAM_FBADDR0_REG);
1838   streams[7] = INREG(PSTREAM_FBADDR1_REG);
1839   streams[8] = INREG(PSTREAM_STRIDE_REG);
1840   streams[9] = INREG(DOUBLE_BUFFER_REG);
1841   streams[10] = INREG(SSTREAM_FBADDR0_REG);
1842   streams[11] = INREG(SSTREAM_FBADDR1_REG);
1843   streams[12] = INREG(SSTREAM_STRIDE_REG);
1844   streams[13] = INREG(OPAQUE_OVERLAY_CONTROL_REG);
1845   streams[14] = INREG(K1_VSCALE_REG);
1846   streams[15] = INREG(K2_VSCALE_REG);
1847   streams[16] = INREG(DDA_VERT_REG);
1848   streams[17] = INREG(STREAMS_FIFO_REG);
1849   streams[18] = INREG(PSTREAM_START_REG);
1850   streams[19] = INREG(PSTREAM_WINDOW_SIZE_REG);
1851   streams[20] = INREG(SSTREAM_START_REG);
1852   streams[21] = INREG(SSTREAM_WINDOW_SIZE_REG);
1853
1854}
1855
1856
1857/*
1858 * This function is used to restore a video mode. It writes out all
1859 * of the standard VGA and extended S3 registers needed to setup a
1860 * video mode.
1861 *
1862 * Note that our life is made more difficult because of the STREAMS
1863 * processor which must be used for 24bpp. We need to disable STREAMS
1864 * before we switch video modes, or we risk locking up the machine.
1865 * We also have to follow a certain order when reenabling it.
1866 */
1867/* let's try restoring in the same order as in the 3.3.2.3 driver */
1868static void
1869S3VWriteMode (ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr, S3VRegPtr restore)
1870{
1871  unsigned char tmp, cr3a=0, cr66, cr67;
1872
1873  vgaHWPtr hwp = VGAHWPTR(pScrn);
1874  S3VPtr ps3v = S3VPTR(pScrn);
1875  int vgaCRIndex, vgaCRReg, vgaIOBase;
1876  vgaIOBase = hwp->IOBase;
1877  vgaCRIndex = vgaIOBase + 4;
1878  vgaCRReg = vgaIOBase + 5;
1879
1880    PVERB5("	S3VWriteMode\n");
1881
1882  vgaHWProtect(pScrn, TRUE);
1883
1884   /* Are we going to reenable STREAMS in this new mode? */
1885   ps3v->STREAMSRunning = restore->CR67 & 0x0c;
1886
1887   /* First reset GE to make sure nothing is going on */
1888   if(ps3v->Chipset == S3_ViRGE_VX) {
1889      VGAOUT8(vgaCRIndex, 0x63);
1890      if(VGAIN8(vgaCRReg) & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__);
1891      }
1892   else {
1893      VGAOUT8(vgaCRIndex, 0x66);
1894      if(VGAIN8(vgaCRReg) & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__);
1895      }
1896
1897   /* As per databook, always disable STREAMS before changing modes */
1898   VGAOUT8(vgaCRIndex, 0x67);
1899   cr67 = VGAIN8(vgaCRReg);
1900   if ((cr67 & 0x0c) == 0x0c) {
1901      S3VDisableSTREAMS(pScrn);     /* If STREAMS was running, disable it */
1902      }
1903
1904   /* Restore S3 extended regs */
1905   VGAOUT8(vgaCRIndex, 0x63);
1906   VGAOUT8(vgaCRReg, restore->CR63);
1907   VGAOUT8(vgaCRIndex, 0x66);
1908   VGAOUT8(vgaCRReg, restore->CR66);
1909   VGAOUT8(vgaCRIndex, 0x3a);
1910   VGAOUT8(vgaCRReg, restore->CR3A);
1911   VGAOUT8(vgaCRIndex, 0x31);
1912   VGAOUT8(vgaCRReg, restore->CR31);
1913   VGAOUT8(vgaCRIndex, 0x58);
1914   VGAOUT8(vgaCRReg, restore->CR58);
1915   VGAOUT8(vgaCRIndex, 0x55);
1916   VGAOUT8(vgaCRReg, restore->CR55);
1917
1918   /* Extended mode timings registers */
1919   VGAOUT8(vgaCRIndex, 0x53);
1920   VGAOUT8(vgaCRReg, restore->CR53);
1921   VGAOUT8(vgaCRIndex, 0x5d);
1922   VGAOUT8(vgaCRReg, restore->CR5D);
1923   VGAOUT8(vgaCRIndex, 0x5e);
1924   VGAOUT8(vgaCRReg, restore->CR5E);
1925   VGAOUT8(vgaCRIndex, 0x3b);
1926   VGAOUT8(vgaCRReg, restore->CR3B);
1927   VGAOUT8(vgaCRIndex, 0x3c);
1928   VGAOUT8(vgaCRReg, restore->CR3C);
1929   VGAOUT8(vgaCRIndex, 0x43);
1930   VGAOUT8(vgaCRReg, restore->CR43);
1931   VGAOUT8(vgaCRIndex, 0x65);
1932   VGAOUT8(vgaCRReg, restore->CR65);
1933   VGAOUT8(vgaCRIndex, 0x6d);
1934   VGAOUT8(vgaCRReg, restore->CR6D);
1935
1936   /* Restore the desired video mode with CR67 */
1937
1938   VGAOUT8(vgaCRIndex, 0x67);
1939   cr67 = VGAIN8(vgaCRReg) & 0xf; /* Possible hardware bug on VX? */
1940   VGAOUT8(vgaCRReg, 0x50 | cr67);
1941   usleep(10000);
1942   VGAOUT8(vgaCRIndex, 0x67);
1943   VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c); /* Don't enable STREAMS yet */
1944
1945   /* Other mode timing and extended regs */
1946   VGAOUT8(vgaCRIndex, 0x34);
1947   VGAOUT8(vgaCRReg, restore->CR34);
1948   if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
1949	/* S3_ViRGE_MX_SERIES(ps3v->Chipset) || CR40 reserved on MX */
1950	S3_ViRGE_MXP_SERIES(ps3v->Chipset) ||
1951	S3_ViRGE_VX_SERIES(ps3v->Chipset) ||
1952	/* S3_TRIO_3D_2X_SERIES(ps3v->Chipset) * included in GX2 series */
1953	ps3v->Chipset == S3_ViRGE_DXGX ||
1954	ps3v->Chipset == S3_ViRGE
1955	)
1956     {
1957       VGAOUT8(vgaCRIndex, 0x40);
1958       VGAOUT8(vgaCRReg, restore->CR40);
1959     }
1960   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
1961     VGAOUT8(vgaCRIndex, 0x41);
1962     VGAOUT8(vgaCRReg, restore->CR41);
1963   }
1964   VGAOUT8(vgaCRIndex, 0x42);
1965   VGAOUT8(vgaCRReg, restore->CR42);
1966   VGAOUT8(vgaCRIndex, 0x45);
1967   VGAOUT8(vgaCRReg, restore->CR45);
1968   VGAOUT8(vgaCRIndex, 0x51);
1969   VGAOUT8(vgaCRReg, restore->CR51);
1970   VGAOUT8(vgaCRIndex, 0x54);
1971   VGAOUT8(vgaCRReg, restore->CR54);
1972
1973   /* Memory timings */
1974   VGAOUT8(vgaCRIndex, 0x36);
1975   VGAOUT8(vgaCRReg, restore->CR36);
1976   VGAOUT8(vgaCRIndex, 0x68);
1977   VGAOUT8(vgaCRReg, restore->CR68);
1978   VGAOUT8(vgaCRIndex, 0x69);
1979   VGAOUT8(vgaCRReg, restore->CR69);
1980
1981   VGAOUT8(vgaCRIndex, 0x33);
1982   VGAOUT8(vgaCRReg, restore->CR33);
1983   if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) || S3_ViRGE_GX2_SERIES(ps3v->Chipset)
1984       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
1985   {
1986      VGAOUT8(vgaCRIndex, 0x85);
1987      VGAOUT8(vgaCRReg, restore->CR85);
1988   }
1989   if (ps3v->Chipset == S3_ViRGE_DXGX) {
1990      VGAOUT8(vgaCRIndex, 0x86);
1991      VGAOUT8(vgaCRReg, restore->CR86);
1992   }
1993   if ( (ps3v->Chipset == S3_ViRGE_GX2) ||
1994	S3_ViRGE_MX_SERIES(ps3v->Chipset) ) {
1995      VGAOUT8(vgaCRIndex, 0x7B);
1996      VGAOUT8(vgaCRReg, restore->CR7B);
1997      VGAOUT8(vgaCRIndex, 0x7D);
1998      VGAOUT8(vgaCRReg, restore->CR7D);
1999      VGAOUT8(vgaCRIndex, 0x87);
2000      VGAOUT8(vgaCRReg, restore->CR87);
2001      VGAOUT8(vgaCRIndex, 0x92);
2002      VGAOUT8(vgaCRReg, restore->CR92);
2003      VGAOUT8(vgaCRIndex, 0x93);
2004      VGAOUT8(vgaCRReg, restore->CR93);
2005   }
2006   if (ps3v->Chipset == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
2007       S3_ViRGE_MX_SERIES(ps3v->Chipset) || S3_TRIO_3D_SERIES(ps3v->Chipset)) {
2008      VGAOUT8(vgaCRIndex, 0x90);
2009      VGAOUT8(vgaCRReg, restore->CR90);
2010      VGAOUT8(vgaCRIndex, 0x91);
2011      VGAOUT8(vgaCRReg, restore->CR91);
2012   }
2013
2014   /* Unlock extended sequencer regs */
2015   VGAOUT8(0x3c4, 0x08);
2016   VGAOUT8(0x3c5, 0x06);
2017
2018
2019   /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates that
2020    * we should leave the default SR10 and SR11 values there.
2021    */
2022
2023   if (restore->SR10 != 255) {
2024       VGAOUT8(0x3c4, 0x10);
2025       VGAOUT8(0x3c5, restore->SR10);
2026       VGAOUT8(0x3c4, 0x11);
2027       VGAOUT8(0x3c5, restore->SR11);
2028       }
2029
2030   /* Restore extended sequencer regs for DCLK */
2031   VGAOUT8(0x3c4, 0x12);
2032   VGAOUT8(0x3c5, restore->SR12);
2033   VGAOUT8(0x3c4, 0x13);
2034   VGAOUT8(0x3c5, restore->SR13);
2035   if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
2036     VGAOUT8(0x3c4, 0x29);
2037     VGAOUT8(0x3c5, restore->SR29);
2038   }
2039   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
2040     VGAOUT8(0x3c4, 0x54);
2041     VGAOUT8(0x3c5, restore->SR54);
2042     VGAOUT8(0x3c4, 0x55);
2043     VGAOUT8(0x3c5, restore->SR55);
2044     VGAOUT8(0x3c4, 0x56);
2045     VGAOUT8(0x3c5, restore->SR56);
2046     VGAOUT8(0x3c4, 0x57);
2047     VGAOUT8(0x3c5, restore->SR57);
2048   }
2049
2050   VGAOUT8(0x3c4, 0x18);
2051   VGAOUT8(0x3c5, restore->SR18);
2052
2053   /* Load new m,n PLL values for DCLK & MCLK */
2054   VGAOUT8(0x3c4, 0x15);
2055   tmp = VGAIN8(0x3c5) & ~0x21;
2056
2057   /* databook either 0x3 or 0x20, but not both?? */
2058   VGAOUT8(0x3c5, tmp | 0x03);
2059   VGAOUT8(0x3c5, tmp | 0x23);
2060   VGAOUT8(0x3c5, tmp | 0x03);
2061   VGAOUT8(0x3c5, restore->SR15);
2062   if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
2063     VGAOUT8(0x3c4, 0x0a);
2064     VGAOUT8(0x3c5, restore->SR0A);
2065     VGAOUT8(0x3c4, 0x0f);
2066     VGAOUT8(0x3c5, restore->SR0F);
2067   }
2068
2069   VGAOUT8(0x3c4, 0x08);
2070   VGAOUT8(0x3c5, restore->SR08);
2071
2072
2073   /* Now write out CR67 in full, possibly starting STREAMS */
2074
2075   VerticalRetraceWait();
2076   VGAOUT8(vgaCRIndex, 0x67);
2077   VGAOUT8(vgaCRReg, 0x50);   /* For possible bug on VX?! */
2078   usleep(10000);
2079   VGAOUT8(vgaCRIndex, 0x67);
2080   VGAOUT8(vgaCRReg, restore->CR67);
2081
2082   VGAOUT8(vgaCRIndex, 0x66);
2083   cr66 = VGAIN8(vgaCRReg);
2084   VGAOUT8(vgaCRReg, cr66 | 0x80);
2085   VGAOUT8(vgaCRIndex, 0x3a);
2086
2087   /* workaround cr3a corruption */
2088   if( ps3v->mx_cr3a_fix )
2089     {
2090       VGAOUT8(vgaCRReg, restore->CR3A | 0x80);
2091     }
2092   else
2093     {
2094       cr3a = VGAIN8(vgaCRReg);
2095       VGAOUT8(vgaCRReg, cr3a | 0x80);
2096     }
2097
2098   /* And finally, we init the STREAMS processor if we have CR67 indicate 24bpp
2099    * We also restore FIFO and TIMEOUT memory controller registers. (later...)
2100    */
2101
2102   if (ps3v->NeedSTREAMS) {
2103      if(ps3v->STREAMSRunning) S3VRestoreSTREAMS(pScrn, restore->STREAMS);
2104      }
2105
2106   /* Now, before we continue, check if this mode has the graphic engine ON
2107    * If yes, then we reset it.
2108    * This fixes some problems with corruption at 24bpp with STREAMS
2109    * Also restore the MIU registers.
2110    */
2111
2112#ifndef MetroLink
2113   if(ps3v->Chipset == S3_ViRGE_VX) {
2114      if(restore->CR63 & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__);
2115      }
2116   else {
2117      if(restore->CR66 & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__);
2118      }
2119#else
2120   S3VGEReset(pScrn,0,__LINE__,__FILE__);
2121#endif
2122
2123   VerticalRetraceWait();
2124   if (S3_ViRGE_GX2_SERIES(ps3v->Chipset)
2125       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
2126     {
2127      VGAOUT8(vgaCRIndex, 0x85);
2128      /* primary stream threshold */
2129      VGAOUT8(vgaCRReg, 0x1f );
2130     }
2131   else
2132     {
2133       OUTREG(FIFO_CONTROL_REG, restore->MMPR0);
2134     }
2135   if( !( S3_ViRGE_GX2_SERIES(ps3v->Chipset)
2136	  /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) ))
2137   {
2138     WaitIdle();                  /* Don't ask... */
2139     OUTREG(MIU_CONTROL_REG, restore->MMPR1);
2140     WaitIdle();
2141     OUTREG(STREAMS_TIMEOUT_REG, restore->MMPR2);
2142     WaitIdle();
2143     OUTREG(MISC_TIMEOUT_REG, restore->MMPR3);
2144   }
2145
2146   /* Restore the standard VGA registers */
2147   /* False indicates no fontinfo restore. */
2148   /* VGA_SR_MODE restores mode info only, no font, no colormap */
2149   					/* Do all for primary video */
2150   if (xf86IsPrimaryPci(ps3v->PciInfo))
2151     vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
2152   					/* Mode only for non-primary? */
2153   else
2154     vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE);
2155 		/* moved from before vgaHWRestore, to prevent segfault? */
2156   VGAOUT8(vgaCRIndex, 0x66);
2157   VGAOUT8(vgaCRReg, cr66);
2158   VGAOUT8(vgaCRIndex, 0x3a);
2159
2160   /* workaround cr3a corruption */
2161   if( ps3v->mx_cr3a_fix )
2162     VGAOUT8(vgaCRReg, restore->CR3A);
2163   else
2164     VGAOUT8(vgaCRReg, cr3a);
2165
2166   if (xf86GetVerbosity() > 1) {
2167      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
2168         "ViRGE driver: done restoring mode, dumping CR registers:\n");
2169      S3VPrintRegs(pScrn);
2170   }
2171
2172   vgaHWProtect(pScrn, FALSE);
2173
2174   return;
2175
2176}
2177
2178
2179/* This function restores the saved STREAMS registers */
2180
2181static void
2182S3VRestoreSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams)
2183{
2184  S3VPtr ps3v = S3VPTR(pScrn);
2185
2186
2187/* For now, set most regs to their default values for 24bpp
2188 * Restore only those that are needed for width/height/stride
2189 * Otherwise, we seem to get lockups because some registers
2190 * when saved have some reserved bits set.
2191 */
2192
2193  OUTREG(PSTREAM_CONTROL_REG, streams[0] & 0x77000000);
2194  OUTREG(COL_CHROMA_KEY_CONTROL_REG, 0x00);
2195  OUTREG(SSTREAM_CONTROL_REG, 0x03000000);
2196  OUTREG(CHROMA_KEY_UPPER_BOUND_REG, 0x00);
2197  OUTREG(SSTREAM_STRETCH_REG, 0x00);
2198  OUTREG(BLEND_CONTROL_REG, 0x01000000);
2199  OUTREG(PSTREAM_FBADDR0_REG, 0x00);
2200  OUTREG(PSTREAM_FBADDR1_REG, 0x00);
2201  OUTREG(PSTREAM_STRIDE_REG, streams[8] & 0x0fff);
2202  OUTREG(DOUBLE_BUFFER_REG, 0x00);
2203  OUTREG(SSTREAM_FBADDR0_REG, 0x00);
2204  OUTREG(SSTREAM_FBADDR1_REG, 0x00);
2205  OUTREG(SSTREAM_STRIDE_REG, 0x01);
2206  OUTREG(OPAQUE_OVERLAY_CONTROL_REG, 0x40000000);
2207  OUTREG(K1_VSCALE_REG, 0x00);
2208  OUTREG(K2_VSCALE_REG, 0x00);
2209  OUTREG(DDA_VERT_REG, 0x00);
2210  OUTREG(PSTREAM_START_REG, 0x00010001);
2211  OUTREG(PSTREAM_WINDOW_SIZE_REG, streams[19] & 0x07ff07ff);
2212  OUTREG(SSTREAM_START_REG, 0x07ff07ff);
2213  OUTREG(SSTREAM_WINDOW_SIZE_REG, 0x00010001);
2214
2215
2216}
2217
2218
2219
2220
2221/* And this function disables the STREAMS processor as per databook.
2222 * This is usefull before we do a mode change
2223 */
2224
2225static void
2226S3VDisableSTREAMS(ScrnInfoPtr pScrn)
2227{
2228unsigned char tmp;
2229  vgaHWPtr hwp = VGAHWPTR(pScrn);
2230  S3VPtr ps3v = S3VPTR(pScrn);
2231  int vgaCRIndex, vgaCRReg, vgaIOBase;
2232  vgaIOBase = hwp->IOBase;
2233  vgaCRIndex = vgaIOBase + 4;
2234  vgaCRReg = vgaIOBase + 5;
2235
2236   VerticalRetraceWait();
2237   OUTREG(FIFO_CONTROL_REG, 0xC000);
2238   VGAOUT8(vgaCRIndex, 0x67);
2239   tmp = VGAIN8(vgaCRReg);
2240                         /* Disable STREAMS processor */
2241   VGAOUT8( vgaCRReg, tmp & ~0x0C );
2242
2243   return;
2244}
2245
2246
2247
2248/* MapMem - contains half of pre-4.0 EnterLeave function */
2249/* The EnterLeave function which en/dis access to IO ports and ext. regs */
2250                /********************************************************/
2251		/* Aaagh...  So many locations!  On my machine (KJB) the*/
2252		/* following is true. 					*/
2253		/* PciInfo->memBase[0] returns e400 0000 		*/
2254		/* From my ViRGE manual, the memory map looks like 	*/
2255		/* Linear mem - 16M  	000 0000 - 0ff ffff 		*/
2256		/* Image xfer - 32k  	100 0000 - 100 7fff 		*/
2257		/* PCI cnfg    		100 8000 - 100 8043 		*/
2258		/* ...				   			*/
2259		/* CRT VGA 3b? reg	100 83b0 - 			*/
2260		/* And S3_NEWMMIO_VGABASE = S3_NEWMMIO_REGBASE + 0x8000	*/
2261		/* where S3_NEWMMIO_REGBASE = 0x100 0000  ( 16MB )      */
2262		/* S3_NEWMMIO_REGSIZE = 0x1 0000  ( 64KB )		*/
2263		/* S3V_MMIO_REGSIZE = 0x8000 ( 32KB ) - above includes	*/
2264		/* the image transfer area, so this one is used instead.*/
2265		/* ps3v->IOBase is assinged the virtual address returned*/
2266		/* from MapPciMem, it is the address to base all 	*/
2267		/* register access. (It is a pointer.)  		*/
2268		/* hwp->MemBase is a CARD32, containing the register	*/
2269		/* base. (It's a conversion from IOBase above.) 	*/
2270                /********************************************************/
2271
2272
2273static Bool
2274S3VMapMem(ScrnInfoPtr pScrn)
2275{
2276  S3VPtr ps3v;
2277  vgaHWPtr hwp;
2278
2279    PVERB5("	S3VMapMem\n");
2280
2281  ps3v = S3VPTR(pScrn);
2282
2283    					/* Map the ViRGE register space */
2284					/* Starts with Image Transfer area */
2285					/* so that we can use registers map */
2286					/* structure - see newmmio.h */
2287					/* around 0x10000 from MemBase */
2288#ifndef XSERVER_LIBPCIACCESS
2289  ps3v->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, ps3v->PciTag,
2290				PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) + S3_NEWMMIO_REGBASE,
2291				S3_NEWMMIO_REGSIZE);
2292
2293  ps3v->MapBaseDense = xf86MapPciMem(pScrn->scrnIndex,
2294				     VIDMEM_MMIO_32BIT,
2295				     ps3v->PciTag,
2296				     PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) + S3_NEWMMIO_REGBASE,
2297				     0x8000);
2298#else
2299  {
2300    void** result = (void**)&ps3v->MapBase;
2301    int err = pci_device_map_range(ps3v->PciInfo,
2302				   PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) + S3_NEWMMIO_REGBASE,
2303				   S3_NEWMMIO_REGSIZE,
2304				   PCI_DEV_MAP_FLAG_WRITABLE,
2305				   result);
2306
2307    if (err)
2308      return FALSE;
2309  }
2310  ps3v->MapBaseDense = ps3v->MapBase;
2311#endif
2312
2313  if( !ps3v->MapBase ) {
2314    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2315	"Internal error: could not map registers.\n");
2316    return FALSE;
2317  }
2318					/* Map the framebuffer */
2319  if (ps3v->videoRambytes) { /* not set in PreInit() */
2320#ifndef XSERVER_LIBPCIACCESS
2321      ps3v->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2322				   ps3v->PciTag, PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM),
2323				   ps3v->videoRambytes );
2324
2325#else
2326      {
2327	void** result = (void**)&ps3v->FBBase;
2328	int err = pci_device_map_range(ps3v->PciInfo,
2329				       PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM),
2330				       ps3v->videoRambytes,
2331				       PCI_DEV_MAP_FLAG_WRITABLE |
2332				       PCI_DEV_MAP_FLAG_WRITE_COMBINE,
2333				       result);
2334
2335	if (err)
2336	  return FALSE;
2337      }
2338#endif
2339
2340      if( !ps3v->FBBase ) {
2341	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2342		     "Internal error: could not map framebuffer.\n");
2343	  return FALSE;
2344      }
2345  		       		/* Initially the visual display start */
2346				/* is the same as the mapped start. */
2347      ps3v->FBStart = ps3v->FBBase;
2348  }
2349
2350  pScrn->memPhysBase = PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM);
2351  pScrn->fbOffset = 0;
2352
2353  				/* Set up offset to hwcursor memory area */
2354  				/* It's a 1K chunk at the end of the frame buffer */
2355  ps3v->FBCursorOffset = ps3v->videoRambytes - 1024;
2356  S3VEnableMmio( pScrn);
2357   					/* Assign hwp->MemBase & IOBase here */
2358  hwp = VGAHWPTR(pScrn);
2359					/* Sets MMIOBase and Offset, assigns */
2360					/* functions. Offset from map area   */
2361					/* to VGA reg area is 0x8000. */
2362  vgaHWSetMmioFuncs( hwp, ps3v->MapBase, S3V_MMIO_REGSIZE );
2363  					/* assigns hwp->IOBase to 3D0 or 3B0 */
2364					/* needs hwp->MMIOBase to work */
2365  vgaHWGetIOBase(hwp);
2366
2367    					/* Map the VGA memory when the */
2368					/* primary video */
2369
2370  if (xf86IsPrimaryPci(ps3v->PciInfo)) {
2371    hwp->MapSize = 0x10000;
2372    if (!vgaHWMapMem(pScrn))
2373      return FALSE;
2374    ps3v->PrimaryVidMapped = TRUE;
2375  }
2376
2377  return TRUE;
2378}
2379
2380
2381
2382/* UnMapMem - contains half of pre-4.0 EnterLeave function */
2383/* The EnterLeave function which en/dis access to IO ports and ext. regs */
2384
2385static void
2386S3VUnmapMem(ScrnInfoPtr pScrn)
2387{
2388  S3VPtr ps3v;
2389
2390  ps3v = S3VPTR(pScrn);
2391					/* Unmap VGA mem if mapped. */
2392  if( ps3v->PrimaryVidMapped ) {
2393    vgaHWUnmapMem( pScrn );
2394    ps3v->PrimaryVidMapped = FALSE;
2395  }
2396
2397#ifndef XSERVER_LIBPCIACCESS
2398  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)ps3v->MapBase,
2399		  S3_NEWMMIO_REGSIZE);
2400#else
2401  pci_device_unmap_range(ps3v->PciInfo, ps3v->MapBase,
2402			 S3_NEWMMIO_REGSIZE);
2403#endif
2404
2405#ifndef XSERVER_LIBPCIACCESS
2406  if (ps3v->FBBase)
2407      xf86UnMapVidMem(pScrn->scrnIndex, (pointer)ps3v->FBBase,
2408		      ps3v->videoRambytes);
2409  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)ps3v->MapBaseDense,
2410		  0x8000);
2411#else
2412  pci_device_unmap_range(ps3v->PciInfo, ps3v->FBBase,
2413			 ps3v->videoRambytes);
2414#endif
2415  return;
2416}
2417
2418
2419
2420/* Mandatory */
2421
2422/* This gets called at the start of each server generation */
2423
2424static Bool
2425S3VScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
2426{
2427  ScrnInfoPtr pScrn;
2428  S3VPtr ps3v;
2429  int ret;
2430
2431  PVERB5("	S3VScreenInit\n");
2432                                        /* First get the ScrnInfoRec */
2433  pScrn = xf86Screens[pScreen->myNum];
2434  					/* Get S3V rec */
2435  ps3v = S3VPTR(pScrn);
2436  					/* Make sure we have card access */
2437/*  xf86EnableAccess(pScrn);*/
2438   					/* Map MMIO regs and framebuffer */
2439  if( !S3VMapMem(pScrn) )
2440    return FALSE;
2441    					/* Save the chip/graphics state */
2442  S3VSave(pScrn);
2443				 	/* Blank the screen during init */
2444  vgaHWBlankScreen(pScrn, TRUE );
2445    					/* Initialise the first mode */
2446  if (!S3VModeInit(pScrn, pScrn->currentMode))
2447    return FALSE;
2448
2449    /*
2450     * The next step is to setup the screen's visuals, and initialise the
2451     * framebuffer code.  In cases where the framebuffer's default
2452     * choices for things like visual layouts and bits per RGB are OK,
2453     * this may be as simple as calling the framebuffer's ScreenInit()
2454     * function.  If not, the visuals will need to be setup before calling
2455     * a fb ScreenInit() function and fixed up after.
2456     *
2457     * For most PC hardware at depths >= 8, the defaults that fb uses
2458     * are not appropriate.  In this driver, we fixup the visuals after.
2459     */
2460
2461    /*
2462     * Reset the visual list.
2463     */
2464  miClearVisualTypes();
2465
2466    /* Setup the visuals we support. */
2467
2468    /*
2469     * For bpp > 8, the default visuals are not acceptable because we only
2470     * support TrueColor and not DirectColor.  To deal with this, call
2471     * miSetVisualTypes with the appropriate visual mask.
2472     */
2473
2474  if (pScrn->bitsPerPixel > 8) {
2475	if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits,
2476				pScrn->defaultVisual))
2477	    return FALSE;
2478
2479	if (!miSetPixmapDepths ())
2480	    return FALSE;
2481  } else {
2482	if (!miSetVisualTypes(pScrn->depth,
2483			      miGetDefaultVisualMask(pScrn->depth),
2484			      pScrn->rgbBits, pScrn->defaultVisual))
2485	    return FALSE;
2486
2487	if (!miSetPixmapDepths ())
2488	    return FALSE;
2489  }
2490
2491  ret = S3VInternalScreenInit(scrnIndex, pScreen);
2492
2493  if (!ret)
2494    return FALSE;
2495
2496  xf86SetBlackWhitePixels(pScreen);
2497
2498  if (pScrn->bitsPerPixel > 8) {
2499    	VisualPtr visual;
2500					/* Fixup RGB ordering */
2501	visual = pScreen->visuals + pScreen->numVisuals;
2502	while (--visual >= pScreen->visuals) {
2503	    if ((visual->class | DynamicClass) == DirectColor) {
2504		visual->offsetRed = pScrn->offset.red;
2505		visual->offsetGreen = pScrn->offset.green;
2506		visual->offsetBlue = pScrn->offset.blue;
2507		visual->redMask = pScrn->mask.red;
2508		visual->greenMask = pScrn->mask.green;
2509		visual->blueMask = pScrn->mask.blue;
2510	    }
2511	}
2512  }
2513
2514  /* must be after RGB ordering fixed */
2515  fbPictureInit (pScreen, 0, 0);
2516
2517  	      				/* Initialize acceleration layer */
2518  if (!ps3v->NoAccel) {
2519    if(pScrn->bitsPerPixel == 32) {
2520      /* 32 bit Accel currently broken
2521      if (!S3VAccelInit32(pScreen))
2522        return FALSE;
2523	*/
2524	;
2525    } else
2526      if (!S3VAccelInit(pScreen))
2527        return FALSE;
2528  }
2529
2530  miInitializeBackingStore(pScreen);
2531  xf86SetBackingStore(pScreen);
2532  xf86SetSilkenMouse(pScreen);
2533  						/* hardware cursor needs to wrap this layer */
2534  S3VDGAInit(pScreen);
2535
2536    					/* Initialise cursor functions */
2537  miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
2538
2539    /* Initialize HW cursor layer.
2540	Must follow software cursor initialization*/
2541  if (ps3v->hwcursor) {
2542  if(!S3VHWCursorInit(pScreen)) {
2543	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2544		"Hardware cursor initialization failed\n");
2545		}
2546  }
2547
2548  if (ps3v->shadowFB) {
2549      RefreshAreaFuncPtr refreshArea = s3vRefreshArea;
2550
2551      if(ps3v->rotate) {
2552	  if (!ps3v->PointerMoved) {
2553	      ps3v->PointerMoved = pScrn->PointerMoved;
2554	      pScrn->PointerMoved = s3vPointerMoved;
2555	  }
2556
2557	  switch(pScrn->bitsPerPixel) {
2558	  case 8:	refreshArea = s3vRefreshArea8;	break;
2559	  case 16:	refreshArea = s3vRefreshArea16;	break;
2560	  case 24:	refreshArea = s3vRefreshArea24;	break;
2561	  case 32:	refreshArea = s3vRefreshArea32;	break;
2562	  }
2563      }
2564
2565      ShadowFBInit(pScreen, refreshArea);
2566  }
2567
2568    					/* Initialise default colourmap */
2569  if (!miCreateDefColormap(pScreen))
2570    return FALSE;
2571  					/* Initialize colormap layer.   */
2572					/* Must follow initialization   */
2573					/* of the default colormap. 	*/
2574					/* And SetGamma call, else it 	*/
2575					/* will load palette with solid */
2576					/* white. */
2577  if(!xf86HandleColormaps(pScreen, 256, 6, S3VLoadPalette, NULL,
2578			CMAP_RELOAD_ON_MODE_SWITCH ))
2579	return FALSE;
2580				    	/* All the ugly stuff is done, 	*/
2581					/* so re-enable the screen. 	*/
2582  vgaHWBlankScreen(pScrn, FALSE );
2583
2584#if 0
2585  pScrn->racMemFlags = RAC_COLORMAP | RAC_CURSOR | RAC_FB | RAC_VIEWPORT;
2586#endif
2587  pScreen->SaveScreen = S3VSaveScreen;
2588
2589    					/* Wrap the current CloseScreen function */
2590  ps3v->CloseScreen = pScreen->CloseScreen;
2591  pScreen->CloseScreen = S3VCloseScreen;
2592
2593  if(xf86DPMSInit(pScreen, S3VDisplayPowerManagementSet, 0) == FALSE)
2594    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n");
2595
2596  S3VInitVideo(pScreen);
2597
2598    /* Report any unused options (only for the first generation) */
2599  if (serverGeneration == 1) {
2600    xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
2601  }
2602    					/* Done */
2603  return TRUE;
2604}
2605
2606
2607
2608/* Common init routines needed in EnterVT and ScreenInit */
2609
2610static int
2611S3VInternalScreenInit( int scrnIndex, ScreenPtr pScreen)
2612{
2613  int ret = TRUE;
2614  ScrnInfoPtr pScrn;
2615  S3VPtr ps3v;
2616  int width, height, displayWidth;
2617  unsigned char* FBStart;
2618
2619  					/* First get the ScrnInfoRec */
2620  pScrn = xf86Screens[pScreen->myNum];
2621
2622  ps3v = S3VPTR(pScrn);
2623
2624  displayWidth = pScrn->displayWidth;
2625  if (ps3v->rotate) {
2626      height = pScrn->virtualX;
2627      width = pScrn->virtualY;
2628  } else {
2629      width = pScrn->virtualX;
2630      height = pScrn->virtualY;
2631  }
2632
2633  if(ps3v->shadowFB) {
2634      ps3v->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
2635      ps3v->ShadowPtr = xalloc(ps3v->ShadowPitch * height);
2636      displayWidth = ps3v->ShadowPitch / (pScrn->bitsPerPixel >> 3);
2637      FBStart = ps3v->ShadowPtr;
2638  } else {
2639      ps3v->ShadowPtr = NULL;
2640      FBStart = ps3v->FBStart;
2641  }
2642
2643    /*
2644     * Call the framebuffer layer's ScreenInit function, and fill in other
2645     * pScreen fields.
2646     */
2647
2648    switch (pScrn->bitsPerPixel)
2649    {
2650	case 8:
2651	case 16:
2652	case 24:
2653	case 32:
2654	    ret = fbScreenInit(pScreen, FBStart, width,
2655			       height, pScrn->xDpi, pScrn->yDpi,
2656			       displayWidth, pScrn->bitsPerPixel);
2657	    break;
2658	default:
2659	    xf86DrvMsg(scrnIndex, X_ERROR,
2660		       "Internal error: invalid bpp (%d) in S3VScreenInit\n",
2661		       pScrn->bitsPerPixel);
2662	    ret = FALSE;
2663	    break;
2664    }
2665
2666  return ret;
2667}
2668
2669
2670
2671/* Checks if a mode is suitable for the selected chipset. */
2672
2673static ModeStatus
2674S3VValidMode(int index, DisplayModePtr mode, Bool verbose, int flags)
2675{
2676    ScrnInfoPtr pScrn = xf86Screens[index];
2677
2678    if ((pScrn->bitsPerPixel + 7)/8 * mode->HDisplay > 4095)
2679	return MODE_VIRTUAL_X;
2680
2681    return MODE_OK;
2682}
2683
2684
2685
2686static Bool
2687S3VModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
2688{
2689  vgaHWPtr hwp = VGAHWPTR(pScrn);
2690  S3VPtr ps3v = S3VPTR(pScrn);
2691  int width, dclk;
2692  int i, j;
2693  unsigned char tmp = 0;
2694
2695  		      		/* Store values to current mode register structs */
2696  S3VRegPtr new = &ps3v->ModeReg;
2697  vgaRegPtr vganew = &hwp->ModeReg;
2698  int vgaCRIndex, vgaCRReg, vgaIOBase;
2699
2700  vgaIOBase = hwp->IOBase;
2701  vgaCRIndex = vgaIOBase + 4;
2702  vgaCRReg = vgaIOBase + 5;
2703
2704    PVERB5("	S3VModeInit\n");
2705
2706    /* Set scale factors for mode timings */
2707
2708    if (ps3v->Chipset == S3_ViRGE_VX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
2709	S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
2710      ps3v->HorizScaleFactor = 1;
2711    }
2712    else if (pScrn->bitsPerPixel == 8) {
2713      ps3v->HorizScaleFactor = 1;
2714    }
2715    else if (pScrn->bitsPerPixel == 16) {
2716      if (S3_TRIO_3D_SERIES(ps3v->Chipset) && mode->Clock > 115000)
2717	ps3v->HorizScaleFactor = 1;
2718      else
2719	ps3v->HorizScaleFactor = 2;
2720    }
2721    else {
2722      ps3v->HorizScaleFactor = 1;
2723    }
2724
2725
2726   /* First we adjust the horizontal timings if needed */
2727
2728   if(ps3v->HorizScaleFactor != 1)
2729      if (!mode->CrtcHAdjusted) {
2730             mode->CrtcHDisplay *= ps3v->HorizScaleFactor;
2731             mode->CrtcHSyncStart *= ps3v->HorizScaleFactor;
2732             mode->CrtcHSyncEnd *= ps3v->HorizScaleFactor;
2733             mode->CrtcHTotal *= ps3v->HorizScaleFactor;
2734             mode->CrtcHSkew *= ps3v->HorizScaleFactor;
2735             mode->CrtcHAdjusted = TRUE;
2736             }
2737
2738   if(!vgaHWInit (pScrn, mode))
2739      return FALSE;
2740
2741   /* Now we fill in the rest of the stuff we need for the virge */
2742   /* Start with MMIO, linear addr. regs */
2743
2744   VGAOUT8(vgaCRIndex, 0x3a);
2745   tmp = VGAIN8(vgaCRReg);
2746   if( S3_ViRGE_GX2_SERIES(ps3v->Chipset)
2747       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
2748     {
2749     if(ps3v->pci_burst)
2750       /*new->CR3A = (tmp & 0x38) | 0x10; / ENH 256, PCI burst */
2751       /* Don't clear reserved bits... */
2752        new->CR3A = (tmp & 0x7f) | 0x10; /* ENH 256, PCI burst */
2753     else
2754        new->CR3A = tmp | 0x90;      /* ENH 256, no PCI burst! */
2755     }
2756   else
2757     {
2758     if(ps3v->pci_burst)
2759        new->CR3A = (tmp & 0x7f) | 0x15; /* ENH 256, PCI burst */
2760     else
2761        new->CR3A = tmp | 0x95;      /* ENH 256, no PCI burst! */
2762     }
2763
2764
2765   VGAOUT8(vgaCRIndex, 0x55);
2766   new->CR55 = VGAIN8(vgaCRReg);
2767   if (ps3v->hwcursor)
2768     new->CR55 |= 0x10;  /* Enables X11 hw cursor mode */
2769   if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
2770     new->CR31 = 0x0c;               /* [trio3d] page 54 */
2771   } else {
2772     new->CR53 = 0x08;     /* Enables MMIO */
2773     new->CR31 = 0x8c;     /* Dis. 64k window, en. ENH maps */
2774   }
2775
2776   /* Enables S3D graphic engine and PCI disconnects */
2777   if(ps3v->Chipset == S3_ViRGE_VX){
2778      new->CR66 = 0x90;
2779      new->CR63 = 0x09;
2780      }
2781   else {
2782     new->CR66 = 0x89;
2783     /* Set display fifo */
2784     if( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
2785	 S3_ViRGE_MX_SERIES(ps3v->Chipset) )
2786       {
2787	 /* Changed from 0x08 based on reports that this */
2788	 /* prevents MX from running properly below 1024x768 */
2789	 new->CR63 = 0x10;
2790       }
2791     else
2792       {
2793	 new->CR63 = 0;
2794       }
2795      }
2796
2797  /* Now set linear addr. registers */
2798  /* LAW size: we have 2 cases, 2MB, 4MB or >= 4MB for VX */
2799   VGAOUT8(vgaCRIndex, 0x58);
2800   new->CR58 = VGAIN8(vgaCRReg) & 0x80;
2801   if(pScrn->videoRam == 2048){
2802      new->CR58 |= 0x02 | 0x10;
2803      }
2804   else if (pScrn->videoRam == 1024) {
2805      new->CR58 |= 0x01 | 0x10;
2806   }
2807   else {
2808     if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) && pScrn->videoRam == 8192)
2809       new->CR58 |= 0x07 | 0x10; /* 8MB window on Trio3D/2X */
2810     else
2811       new->CR58 |= 0x03 | 0x10; /* 4MB window on virge, 8MB on VX */
2812      }
2813   if(ps3v->Chipset == S3_ViRGE_VX)
2814      new->CR58 |= 0x40;
2815   if (ps3v->early_ras_precharge)
2816      new->CR58 |= 0x80;
2817   if (ps3v->late_ras_precharge)
2818      new->CR58 &= 0x7f;
2819
2820  /* ** On PCI bus, no need to reprogram the linear window base address */
2821
2822  /* Now do clock PLL programming. Use the s3gendac function to get m,n */
2823  /* Also determine if we need doubling etc. */
2824
2825   dclk = mode->Clock;
2826   new->CR67 = 0x00;             /* Defaults */
2827
2828   if (!S3_TRIO_3D_SERIES(ps3v->Chipset))
2829     new->SR15 = 0x03 | 0x80;
2830   else {
2831     VGAOUT8(0x3c4, 0x15);
2832     new->SR15 = VGAIN8(0x3c5);
2833     VGAOUT8(0x3c4, 0x0a);
2834     new->SR0A = VGAIN8(0x3c5);
2835     if (ps3v->slow_dram) {
2836       new->SR15 = 0x03;  /* 3 CYC MWR */
2837       new->SR0A &= 0x7F;
2838     } else if (ps3v->fast_dram) {
2839       new->SR15 = 0x03 | 0x80; /* 2 CYC MWR */
2840       new->SR0A |= 0x80;
2841     } else { /* keep BIOS init defaults */
2842       new->SR15 = (new->SR15 & 0x80) | 0x03;
2843     }
2844   }
2845   new->SR18 = 0x00;
2846   new->CR43 = 0x00;
2847   new->CR45 = 0x00;
2848   				/* Enable MMIO to RAMDAC registers */
2849   new->CR65 = 0x00;		/* CR65_2 must be zero, doc seems to be wrong */
2850   new->CR54 = 0x00;
2851
2852   if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
2853	/* S3_ViRGE_MX_SERIES(ps3v->Chipset) || CR40 reserved on MX */
2854	S3_ViRGE_MXP_SERIES(ps3v->Chipset) ||
2855	S3_ViRGE_VX_SERIES(ps3v->Chipset) ||
2856	/* S3_TRIO_3D_2X_SERIES(ps3v->Chipset) * included in GX2 series */
2857	ps3v->Chipset == S3_ViRGE_DXGX ||
2858	ps3v->Chipset == S3_ViRGE
2859	) {
2860     VGAOUT8(vgaCRIndex, 0x40);
2861     new->CR40 = VGAIN8(vgaCRReg) & ~0x01;
2862   }
2863
2864   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
2865     /* fix problems with APM suspend/resume trashing CR90/91 */
2866     switch(pScrn->bitsPerPixel) {
2867       case  8: new->CR41 = 0x38; break;
2868       case 15: new->CR41 = 0x58; break;
2869       case 16: new->CR41 = 0x48; break;
2870       default: new->CR41 = 0x77;
2871     }
2872   }
2873
2874    xf86ErrorFVerb(VERBLEV, "	S3VModeInit dclk=%i \n",
2875   	dclk
2876	);
2877
2878   /* Memory controller registers. Optimize for better graphics engine
2879    * performance. These settings are adjusted/overridden below for other bpp/
2880    * XConfig options.The idea here is to give a longer number of contiguous
2881    * MCLK's to both refresh and the graphics engine, to diminish the
2882    * relative penalty of 3 or 4 mclk's needed to setup memory transfers.
2883    */
2884   new->MMPR0 = 0x010400; /* defaults */
2885   new->MMPR1 = 0x00;
2886   new->MMPR2 = 0x0808;
2887   new->MMPR3 = 0x08080810;
2888
2889   /*
2890    * These settings look like they ought to be better adjusted for depth,
2891    * so for problem modes running without any fifo_ option should be
2892    * usable.  Note that these adjust some memory timings and relate to
2893    * the boards MCLK setting.
2894    * */
2895    if( ps3v->fifo_aggressive || ps3v->fifo_moderate ||
2896       ps3v->fifo_conservative ) {
2897
2898         new->MMPR1 = 0x0200;   /* Low P. stream waits before filling */
2899         new->MMPR2 = 0x1808;   /* Let the FIFO refill itself */
2900         new->MMPR3 = 0x08081810; /* And let the GE hold the bus for a while */
2901      }
2902
2903   /* And setup here the new value for MCLK. We use the XConfig
2904    * option "set_mclk", whose value gets stored in ps3v->MCLK.
2905    * I'm not sure what the maximum "permitted" value should be, probably
2906    * 100 MHz is more than enough for now.
2907    */
2908
2909   if(ps3v->MCLK> 0) {
2910       if (S3_ViRGE_MX_SERIES(ps3v->Chipset))
2911	  S3VCommonCalcClock(pScrn, mode,
2912			     (int)(ps3v->MCLK / ps3v->refclk_fact),
2913			     1, 1, 31, 0, 3,
2914			     135000, 270000, &new->SR11, &new->SR10);
2915       else
2916	  S3VCommonCalcClock(pScrn, mode, ps3v->MCLK, 1, 1, 31, 0, 3,
2917			     135000, 270000, &new->SR11, &new->SR10);
2918       }
2919   else {
2920       new->SR10 = 255; /* This is a reserved value, so we use as flag */
2921       new->SR11 = 255;
2922       }
2923
2924   					/* most modes don't need STREAMS */
2925					/* processor, preset FALSE */
2926   /* support for XVideo needs streams, so added it to some modes */
2927   ps3v->NeedSTREAMS = FALSE;
2928
2929   if(ps3v->Chipset == S3_ViRGE_VX){
2930       if (pScrn->bitsPerPixel == 8) {
2931          if (dclk <= 110000) new->CR67 = 0x00; /* 8bpp, 135MHz */
2932          else new->CR67 = 0x10;                /* 8bpp, 220MHz */
2933          }
2934       else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) {
2935          if (dclk <= 110000) new->CR67 = 0x20; /* 15bpp, 135MHz */
2936          else new->CR67 = 0x30;                /* 15bpp, 220MHz */
2937          }
2938       else if (pScrn->bitsPerPixel == 16) {
2939          if (dclk <= 110000) new->CR67 = 0x40; /* 16bpp, 135MHz */
2940          else new->CR67 = 0x50;                /* 16bpp, 220MHz */
2941          }
2942       else if ((pScrn->bitsPerPixel == 24) || (pScrn->bitsPerPixel == 32)) {
2943          new->CR67 = 0xd0 | 0x0c;              /* 24bpp, 135MHz, STREAMS */
2944	  					/* Flag STREAMS proc. required */
2945          ps3v->NeedSTREAMS = TRUE;
2946          S3VInitSTREAMS(pScrn, new->STREAMS, mode);
2947          new->MMPR0 = 0xc098;            /* Adjust FIFO slots */
2948          }
2949       S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 4,
2950	   220000, 440000, &new->SR13, &new->SR12);
2951
2952      } /* end VX if() */
2953   else if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
2954       if (pScrn->bitsPerPixel == 8)
2955	  new->CR67 = 0x00;
2956       else if (pScrn->bitsPerPixel == 16) {
2957	 /* XV support needs STREAMS in depth 16 */
2958          ps3v->NeedSTREAMS = TRUE;
2959          S3VInitSTREAMS(pScrn, new->STREAMS, mode);
2960	  if (pScrn->weight.green == 5)
2961	     new->CR67 = 0x30 | 0x4;                  /* 15bpp */
2962	  else
2963	     new->CR67 = 0x50 | 0x4;                  /* 16bpp */
2964          }
2965       else if ((pScrn->bitsPerPixel == 24) ) {
2966	 new->CR67 = 0x74;              /* 24bpp, STREAMS */
2967	  					/* Flag STREAMS proc. required */
2968          ps3v->NeedSTREAMS = TRUE;
2969          S3VInitSTREAMS(pScrn, new->STREAMS, mode);
2970          }
2971       else if (pScrn->bitsPerPixel == 32) {
2972          new->CR67 = 0xd0;              /* 32bpp */
2973	  	/* Missing STREAMs and other stuff here? KJB */
2974          /* new->MMPR0 = 0xc098;            / Adjust FIFO slots */
2975          }
2976       {
2977         unsigned char ndiv;
2978	 if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
2979	   unsigned char sr8;
2980	   VGAOUT8(0x3c4, 0x08);  /* unlock extended SEQ regs */
2981	   sr8 = VGAIN8(0x3c5);
2982	   VGAOUT8(0x3c5, 0x06);
2983	   VGAOUT8(0x3c4, 0x31);
2984	   if (VGAIN8(0x3c5) & 0x10) { /* LCD on */
2985	     if (!ps3v->LCDClk) {  /* entered only once for first mode */
2986	       int h_lcd, v_lcd;
2987	       VGAOUT8(0x3c4, 0x61);
2988	       h_lcd = VGAIN8(0x3c5);
2989	       VGAOUT8(0x3c4, 0x66);
2990	       h_lcd |= ((VGAIN8(0x3c5) & 0x02) << 7);
2991	       h_lcd = (h_lcd+1) * 8;
2992	       VGAOUT8(0x3c4, 0x69);
2993	       v_lcd = VGAIN8(0x3c5);
2994	       VGAOUT8(0x3c4, 0x6e);
2995	       v_lcd |= ((VGAIN8(0x3c5) & 0x70) << 4);
2996	       v_lcd++;
2997
2998	       /* check if first mode has physical LCD resolution */
2999	       if (pScrn->modes->HDisplay == h_lcd && pScrn->modes->VDisplay == v_lcd)
3000		 ps3v->LCDClk = mode->Clock;
3001	       else {
3002		 int n1, n2, sr12, sr13, sr29;
3003		 VGAOUT8(0x3c4, 0x12);
3004		 sr12 = VGAIN8(0x3c5);
3005		 VGAOUT8(0x3c4, 0x13);
3006		 sr13 = VGAIN8(0x3c5) & 0x7f;
3007		 VGAOUT8(0x3c4, 0x29);
3008		 sr29 = VGAIN8(0x3c5);
3009		 n1 = sr12 & 0x1f;
3010		 n2 = ((sr12>>6) & 0x03) | ((sr29 & 0x01) << 2);
3011		 ps3v->LCDClk = ((int)(ps3v->refclk_fact * 1431818 * (sr13+2)) / (n1+2) / (1 << n2) + 50) / 100;
3012	       }
3013	     }
3014	     S3VCommonCalcClock(pScrn, mode,
3015			     (int)(ps3v->LCDClk / ps3v->refclk_fact),
3016			     1, 1, 31, 0, 4,
3017			     170000, 340000, &new->SR13, &ndiv);
3018	   }
3019	   else
3020	     S3VCommonCalcClock(pScrn, mode,
3021			     (int)(dclk / ps3v->refclk_fact),
3022			     1, 1, 31, 0, 4,
3023			     170000, 340000, &new->SR13, &ndiv);
3024	   VGAOUT8(0x3c4, 0x08);
3025	   VGAOUT8(0x3c5, sr8);
3026	 }
3027	 else  /* S3_ViRGE_GX2 */
3028	   S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 4,
3029			   170000, 340000, &new->SR13, &ndiv);
3030         new->SR29 = ndiv >> 7;
3031         new->SR12 = (ndiv & 0x1f) | ((ndiv & 0x60) << 1);
3032       }
3033   } /* end GX2 or MX if() */
3034   else if(S3_TRIO_3D_SERIES(ps3v->Chipset)) {
3035      new->SR0F = 0x00;
3036      if (pScrn->bitsPerPixel == 8) {
3037         if(dclk > 115000) {                     /* We need pixmux */
3038            new->CR67 = 0x10;
3039            new->SR15 |= 0x10;                   /* Set DCLK/2 bit */
3040            new->SR18 = 0x80;                   /* Enable pixmux */
3041        }
3042      }
3043      else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) {
3044        if(dclk > 115000) {
3045           new->CR67 = 0x20;
3046           new->SR15 |= 0x10;
3047           new->SR18 = 0x80;
3048	   new->SR0F = 0x10;
3049        } else {
3050           new->CR67 = 0x30;                       /* 15bpp */
3051        }
3052      }
3053      else if (pScrn->bitsPerPixel == 16) {
3054        if(dclk > 115000) {
3055            new->CR67 = 0x40;
3056            new->SR15 |= 0x10;
3057            new->SR18 = 0x80;
3058	    new->SR0F = 0x10;
3059        } else {
3060           new->CR67 = 0x50;
3061        }
3062      }
3063      else if (pScrn->bitsPerPixel == 24) {
3064         new->CR67 = 0xd0 | 0x0c;
3065	 ps3v->NeedSTREAMS = TRUE;
3066         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
3067         new->MMPR0 = 0xc000;            /* Adjust FIFO slots */
3068      }
3069      else if (pScrn->bitsPerPixel == 32) {
3070         new->CR67 = 0xd0 | 0x0c;
3071	 ps3v->NeedSTREAMS = TRUE;
3072         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
3073         new->MMPR0 = 0x10000;            /* Still more FIFO slots */
3074	 new->SR0F = 0x10;
3075      }
3076      S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 4,
3077                     230000, 460000, &new->SR13, &new->SR12);
3078   } /* end TRIO_3D if() */
3079   else if(ps3v->Chipset == S3_ViRGE_DXGX) {
3080      if (pScrn->bitsPerPixel == 8) {
3081         if(dclk > 80000) {                     /* We need pixmux */
3082            new->CR67 = 0x10;
3083            new->SR15 |= 0x10;                   /* Set DCLK/2 bit */
3084            new->SR18 = 0x80;                   /* Enable pixmux */
3085            }
3086         }
3087      else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) {
3088         new->CR67 = 0x30;                       /* 15bpp */
3089         }
3090      else if (pScrn->bitsPerPixel == 16) {
3091	if(mode->Flags & V_DBLSCAN)
3092	  {
3093	    new->CR67 = 0x50;
3094	  }
3095	else
3096	  {
3097	    new->CR67 = 0x50 | 0x0c;
3098	    /* Flag STREAMS proc. required */
3099	    /* XV support needs STREAMS in depth 16 */
3100	    ps3v->NeedSTREAMS = TRUE;
3101	    S3VInitSTREAMS(pScrn, new->STREAMS, mode);
3102	  }
3103	 if( ps3v->XVideo )
3104	   {
3105	     new->MMPR0 = 0x107c02;            /* Adjust FIFO slots, overlay */
3106	   }
3107	 else
3108	   {
3109	     new->MMPR0 = 0xc000;            /* Adjust FIFO slots */
3110	   }
3111         }
3112      else if (pScrn->bitsPerPixel == 24) {
3113         new->CR67 = 0xd0 | 0x0c;
3114	  					/* Flag STREAMS proc. required */
3115         ps3v->NeedSTREAMS = TRUE;
3116         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
3117	 if( ps3v->XVideo )
3118	   {
3119	     new->MMPR0 = 0x107c02;            /* Adjust FIFO slots, overlay */
3120	   }
3121	 else
3122	   {
3123	     new->MMPR0 = 0xc000;            /* Adjust FIFO slots */
3124	   }
3125         }
3126      else if (pScrn->bitsPerPixel == 32) {
3127         new->CR67 = 0xd0 | 0x0c;
3128	  					/* Flag STREAMS proc. required */
3129         ps3v->NeedSTREAMS = TRUE;
3130         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
3131         new->MMPR0 = 0x10000;            /* Still more FIFO slots */
3132         }
3133      S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 3,
3134	135000, 270000, &new->SR13, &new->SR12);
3135   } /* end DXGX if() */
3136   else {           /* Everything else ... (only ViRGE) */
3137      if (pScrn->bitsPerPixel == 8) {
3138         if(dclk > 80000) {                     /* We need pixmux */
3139            new->CR67 = 0x10;
3140            new->SR15 |= 0x10;                   /* Set DCLK/2 bit */
3141            new->SR18 = 0x80;                   /* Enable pixmux */
3142            }
3143         }
3144      else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) {
3145         new->CR67 = 0x30;                       /* 15bpp */
3146         }
3147      else if (pScrn->bitsPerPixel == 16) {
3148         new->CR67 = 0x50;
3149         }
3150      else if (pScrn->bitsPerPixel == 24) {
3151         new->CR67 = 0xd0 | 0x0c;
3152	  					/* Flag STREAMS proc. required */
3153         ps3v->NeedSTREAMS = TRUE;
3154         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
3155	 new->MMPR0 = 0xc000;            /* Adjust FIFO slots */
3156         }
3157      else if (pScrn->bitsPerPixel == 32) {
3158         new->CR67 = 0xd0 | 0x0c;
3159	  					/* Flag STREAMS proc. required */
3160         ps3v->NeedSTREAMS = TRUE;
3161         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
3162         new->MMPR0 = 0x10000;            /* Still more FIFO slots */
3163         }
3164      S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 3,
3165	135000, 270000, &new->SR13, &new->SR12);
3166      } /* end great big if()... */
3167
3168
3169   /* Now adjust the value of the FIFO based upon options specified */
3170   if( ps3v->fifo_moderate ) {
3171      if(pScrn->bitsPerPixel < 24)
3172         new->MMPR0 -= 0x8000;
3173      else
3174         new->MMPR0 -= 0x4000;
3175      }
3176   else if( ps3v->fifo_aggressive ) {
3177      if(pScrn->bitsPerPixel < 24)
3178         new->MMPR0 -= 0xc000;
3179      else
3180         new->MMPR0 -= 0x6000;
3181      }
3182
3183   /* If we have an interlace mode, set the interlace bit. Note that mode
3184    * vertical timings are already adjusted by the standard VGA code
3185    */
3186   if(mode->Flags & V_INTERLACE) {
3187        new->CR42 = 0x20; /* Set interlace mode */
3188        }
3189   else {
3190        new->CR42 = 0x00;
3191        }
3192
3193   if(S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
3194      S3_ViRGE_MX_SERIES(ps3v->Chipset) )
3195     {
3196       new->CR34 = 0;
3197     }
3198   else
3199     {
3200       /* Set display fifo */
3201       new->CR34 = 0x10;
3202     }
3203   /* Now we adjust registers for extended mode timings */
3204   /* This is taken without change from the accel/s3_virge code */
3205
3206   i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) |
3207       ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) |
3208       ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) |
3209       ((mode->CrtcHSyncStart & 0x800) >> 7);
3210
3211   if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64)
3212      i |= 0x08;   /* add another 64 DCLKs to blank pulse width */
3213
3214   if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32)
3215      i |= 0x20;   /* add another 32 DCLKs to hsync pulse width */
3216
3217   /* video playback chokes if sync start and display end are equal */
3218   if (mode->CrtcHSyncStart - mode->CrtcHDisplay < ps3v->HorizScaleFactor) {
3219       int tmp = vganew->CRTC[4] + ((i&0x10)<<4) + ps3v->HorizScaleFactor;
3220       vganew->CRTC[4] = tmp & 0xff;
3221       i |= ((tmp >> 4) & 0x10);
3222   }
3223
3224   j = (  vganew->CRTC[0] + ((i&0x01)<<8)
3225        + vganew->CRTC[4] + ((i&0x10)<<4) + 1) / 2;
3226
3227   if (j-(vganew->CRTC[4] + ((i&0x10)<<4)) < 4) {
3228      if (vganew->CRTC[4] + ((i&0x10)<<4) + 4 <= vganew->CRTC[0]+ ((i&0x01)<<8))
3229         j = vganew->CRTC[4] + ((i&0x10)<<4) + 4;
3230      else
3231         j = vganew->CRTC[0]+ ((i&0x01)<<8) + 1;
3232   }
3233   new->CR3B = j & 0xFF;
3234   i |= (j & 0x100) >> 2;
3235   new->CR3C = (vganew->CRTC[0] + ((i&0x01)<<8))/2;
3236   new->CR5D = i;
3237
3238   new->CR5E = (((mode->CrtcVTotal - 2) & 0x400) >> 10)  |
3239               (((mode->CrtcVDisplay - 1) & 0x400) >> 9) |
3240               (((mode->CrtcVSyncStart) & 0x400) >> 8)   |
3241               (((mode->CrtcVSyncStart) & 0x400) >> 6)   | 0x40;
3242
3243
3244   width = (pScrn->displayWidth * (pScrn->bitsPerPixel / 8))>> 3;
3245   vganew->CRTC[19] = 0xFF & width;
3246   new->CR51 = (0x300 & width) >> 4; /* Extension bits */
3247
3248   /* Set doublescan */
3249   if( mode->Flags & V_DBLSCAN)
3250     vganew->CRTC[9] |= 0x80;
3251
3252   /* And finally, select clock source 2 for programmable PLL */
3253   vganew->MiscOutReg |= 0x0c;
3254
3255
3256   new->CR33 = 0x20;
3257   if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) || S3_ViRGE_GX2_SERIES(ps3v->Chipset)
3258       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
3259   {
3260     new->CR85 = 0x12;  /* avoid sreen flickering */
3261      /* by increasing FIFO filling, larger # fills FIFO from memory earlier */
3262      /* on GX2 this affects all depths, not just those running STREAMS. */
3263      /* new, secondary stream settings. */
3264      new->CR87 = 0x10;
3265      /* gx2 - set up in XV init code */
3266      new->CR92 = 0x00;
3267      new->CR93 = 0x00;
3268      /* gx2 primary mclk timeout, def=0xb */
3269      new->CR7B = 0xb;
3270      /* gx2 secondary mclk timeout, def=0xb */
3271      new->CR7D = 0xb;
3272   }
3273   if (ps3v->Chipset == S3_ViRGE_DXGX || S3_TRIO_3D_SERIES(ps3v->Chipset)) {
3274      new->CR86 = 0x80;  /* disable DAC power saving to avoid bright left edge */
3275   }
3276   if (ps3v->Chipset == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
3277       S3_ViRGE_MX_SERIES(ps3v->Chipset) || S3_TRIO_3D_SERIES(ps3v->Chipset)) {
3278      int dbytes = pScrn->displayWidth * ((pScrn->bitsPerPixel+7)/8);
3279      new->CR91 =   (dbytes + 7) / 8;
3280      new->CR90 = (((dbytes + 7) / 8) >> 8) | 0x80;
3281   }
3282
3283
3284   /* Now we handle various XConfig memory options and others */
3285
3286   VGAOUT8(vgaCRIndex, 0x36);
3287   new->CR36 = VGAIN8(vgaCRReg);
3288   /* option "slow_edodram" sets EDO to 2 cycle mode on ViRGE */
3289   if (ps3v->Chipset == S3_ViRGE) {
3290      if( ps3v->slow_edodram )
3291         new->CR36 = (new->CR36 & 0xf3) | 0x08;
3292      else
3293         new->CR36 &= 0xf3;
3294      }
3295
3296   /* Option "fpm_vram" for ViRGE_VX sets memory in fast page mode */
3297   if (ps3v->Chipset == S3_ViRGE_VX) {
3298      if( ps3v->fpm_vram )
3299         new->CR36 |=  0x0c;
3300      else
3301         new->CR36 &= ~0x0c;
3302   }
3303
3304   				/* S3_INVERT_VCLK was defaulted to 0 	*/
3305				/* in 3.3.3 and never changed. 		*/
3306				/* Also, bit 0 is never set in 3.9Nm,	*/
3307				/* so I left this out for 4.0.			*/
3308#if 0
3309      if (mode->Private[0] & (1 << S3_INVERT_VCLK)) {
3310	 if (mode->Private[S3_INVERT_VCLK])
3311	    new->CR67 |= 1;
3312	 else
3313	    new->CR67 &= ~1;
3314      }
3315#endif
3316      				/* S3_BLANK_DELAY settings based on 	*/
3317				/* defaults only. From 3.3.3 		*/
3318   {
3319      int blank_delay;
3320
3321      if(ps3v->Chipset == S3_ViRGE_VX)
3322	    /* these values need to be changed once CR67_1 is set
3323	       for gamma correction (see S3V server) ! */
3324	    if (pScrn->bitsPerPixel == 8)
3325	       blank_delay = 0x00;
3326	    else if (pScrn->bitsPerPixel == 16)
3327	       blank_delay = 0x00;
3328	    else
3329	       blank_delay = 0x51;
3330      else
3331	    if (pScrn->bitsPerPixel == 8)
3332	       blank_delay = 0x00;
3333	    else if (pScrn->bitsPerPixel == 16)
3334	       blank_delay = 0x02;
3335	    else
3336	       blank_delay = 0x04;
3337
3338      if (ps3v->Chipset == S3_ViRGE_VX)
3339	    new->CR6D = blank_delay;
3340      else {
3341	    new->CR65 = (new->CR65 & ~0x38)
3342	       | (blank_delay & 0x07) << 3;
3343	    VGAOUT8(vgaCRIndex, 0x6d);
3344	    new->CR6D = VGAIN8(vgaCRReg);
3345      }
3346   }
3347   				/* S3_EARLY_SC was defaulted to 0 	*/
3348				/* in 3.3.3 and never changed. 		*/
3349				/* Also, bit 1 is never set in 3.9Nm,	*/
3350				/* so I left this out for 4.0.			*/
3351#if 0
3352      if (mode->Private[0] & (1 << S3_EARLY_SC)) {
3353	 if (mode->Private[S3_EARLY_SC])
3354	    new->CR65 |= 2;
3355	 else
3356	    new->CR65 &= ~2;
3357      }
3358#endif
3359
3360   VGAOUT8(vgaCRIndex, 0x68);
3361   new->CR68 = VGAIN8(vgaCRReg);
3362   new->CR69 = 0;
3363
3364   /* Flat panel centering and expansion registers */
3365   if (S3_ViRGE_MX_SERIES(ps3v->Chipset) && (ps3v->lcd_center)) {
3366     new->SR54 = 0x10 ;
3367     new->SR55 = 0x80 ;
3368     new->SR56 = 0x10 ;
3369     new->SR57 = 0x80 ;
3370   } else {
3371     new->SR54 = 0x1f ;
3372     new->SR55 = 0x9f ;
3373     new->SR56 = 0x1f ;
3374     new->SR57 = 0xff ;
3375   }
3376
3377   pScrn->vtSema = TRUE;
3378
3379   					/* Do it!  Write the mode registers */
3380					/* to hardware, start STREAMS if    */
3381					/* needed, etc.		    	    */
3382   S3VWriteMode( pScrn, vganew, new );
3383   					/* Adjust the viewport */
3384   S3VAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
3385
3386   return TRUE;
3387}
3388
3389
3390/*
3391 * This is called at the end of each server generation.  It restores the
3392 * original (text) mode.  It should also unmap the video memory, and free
3393 * any per-generation data allocated by the driver.  It should finish
3394 * by unwrapping and calling the saved CloseScreen function.
3395 */
3396
3397/* Mandatory */
3398static Bool
3399S3VCloseScreen(int scrnIndex, ScreenPtr pScreen)
3400{
3401  ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
3402  vgaHWPtr hwp = VGAHWPTR(pScrn);
3403  S3VPtr ps3v = S3VPTR(pScrn);
3404  vgaRegPtr vgaSavePtr = &hwp->SavedReg;
3405  S3VRegPtr S3VSavePtr = &ps3v->SavedReg;
3406
3407    					/* Like S3VRestore, but uses passed */
3408					/* mode registers.		    */
3409  if (pScrn->vtSema) {
3410      S3VWriteMode(pScrn, vgaSavePtr, S3VSavePtr);
3411      vgaHWLock(hwp);
3412      S3VDisableMmio(pScrn);
3413      S3VUnmapMem(pScrn);
3414  }
3415
3416  if (ps3v->AccelInfoRec)
3417    XAADestroyInfoRec(ps3v->AccelInfoRec);
3418  if (ps3v->DGAModes)
3419  	xfree(ps3v->DGAModes);
3420
3421  pScrn->vtSema = FALSE;
3422
3423  pScreen->CloseScreen = ps3v->CloseScreen;
3424
3425  return (*pScreen->CloseScreen)(scrnIndex, pScreen);
3426}
3427
3428
3429
3430
3431/* Do screen blanking */
3432
3433/* Mandatory */
3434static Bool
3435S3VSaveScreen(ScreenPtr pScreen, int mode)
3436{
3437  return vgaHWSaveScreen(pScreen, mode);
3438}
3439
3440
3441
3442
3443
3444/* This function inits the STREAMS processor variables.
3445 * This has essentially been taken from the accel/s3_virge code and the databook.
3446 */
3447static void
3448S3VInitSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams, DisplayModePtr mode)
3449{
3450  PVERB5("	S3VInitSTREAMS\n");
3451
3452  switch (pScrn->bitsPerPixel)
3453    {
3454    case 16:
3455      streams[0] = 0x05000000;
3456      break;
3457    case 24:
3458                         /* data format 8.8.8 (24 bpp) */
3459      streams[0] = 0x06000000;
3460      break;
3461    case 32:
3462                         /* one more bit for X.8.8.8, 32 bpp */
3463      streams[0] = 0x07000000;
3464      break;
3465    }
3466                         /* NO chroma keying... */
3467   streams[1] = 0x0;
3468                         /* Secondary stream format KRGB-16 */
3469                         /* data book suggestion... */
3470   streams[2] = 0x03000000;
3471
3472   streams[3] = 0x0;
3473
3474   streams[4] = 0x0;
3475                         /* use 0x01000000 for primary over second. */
3476                         /* use 0x0 for second over prim. */
3477   streams[5] = 0x01000000;
3478
3479   streams[6] = 0x0;
3480
3481   streams[7] = 0x0;
3482                                /* Stride is 3 bytes for 24 bpp mode and */
3483                                /* 4 bytes for 32 bpp. */
3484   switch(pScrn->bitsPerPixel)
3485     {
3486     case 16:
3487       streams[8] =
3488	 pScrn->displayWidth * 2;
3489       break;
3490     case 24:
3491       streams[8] =
3492	 pScrn->displayWidth * 3;
3493      break;
3494     case 32:
3495       streams[8] =
3496	 pScrn->displayWidth * 4;
3497      break;
3498     }
3499                                /* Choose fbaddr0 as stream source. */
3500   streams[9] = 0x0;
3501   streams[10] = 0x0;
3502   streams[11] = 0x0;
3503   streams[12] = 0x1;
3504
3505                                /* Set primary stream on top of secondary */
3506                                /* stream. */
3507   streams[13] = 0xc0000000;
3508                               /* Vertical scale factor. */
3509   streams[14] = 0x0;
3510
3511   streams[15] = 0x0;
3512                                /* Vertical accum. initial value. */
3513   streams[16] = 0x0;
3514                                /* X and Y start coords + 1. */
3515   streams[18] =  0x00010001;
3516
3517         /* Specify window Width -1 and Height of */
3518         /* stream. */
3519   streams[19] =
3520         (mode->HDisplay - 1) << 16 |
3521         (mode->VDisplay);
3522
3523                                /* Book says 0x07ff07ff. */
3524   streams[20] = 0x07ff07ff;
3525
3526   streams[21] = 0x00010001;
3527
3528}
3529
3530
3531
3532
3533/* Used to adjust start address in frame buffer. We use the new
3534 * CR69 reg for this purpose instead of the older CR31/CR51 combo.
3535 * If STREAMS is running, we program the STREAMS start addr. registers.
3536 */
3537
3538void
3539S3VAdjustFrame(int scrnIndex, int x, int y, int flags)
3540{
3541   ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
3542   vgaHWPtr hwp = VGAHWPTR(pScrn);
3543   S3VPtr ps3v = S3VPTR(pScrn);
3544   int Base;
3545   int vgaCRIndex, vgaCRReg, vgaIOBase;
3546   vgaIOBase = hwp->IOBase;
3547   vgaCRIndex = vgaIOBase + 4;
3548   vgaCRReg = vgaIOBase + 5;
3549
3550   if(ps3v->ShowCache && y)
3551	y += pScrn->virtualY - 1;
3552
3553   if( (ps3v->STREAMSRunning == FALSE) ||
3554      S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
3555      Base = ((y * pScrn->displayWidth + x)
3556		* (pScrn->bitsPerPixel / 8)) >> 2;
3557      if (pScrn->bitsPerPixel == 24)
3558	Base = Base+2 - (Base+2) % 3;
3559      if (pScrn->bitsPerPixel == 16)
3560	if (S3_TRIO_3D_SERIES(ps3v->Chipset) && pScrn->modes->Clock > 115000)
3561	  Base &= ~1;
3562
3563      /* Now program the start address registers */
3564      VGAOUT16(vgaCRIndex, (Base & 0x00FF00) | 0x0C);
3565      VGAOUT16(vgaCRIndex, ((Base & 0x00FF) << 8) | 0x0D);
3566      VGAOUT8(vgaCRIndex, 0x69);
3567      VGAOUT8(vgaCRReg, (Base & 0x0F0000) >> 16);
3568      }
3569   else {          /* Change start address for STREAMS case */
3570      VerticalRetraceWait();
3571      if(ps3v->Chipset == S3_ViRGE_VX)
3572	OUTREG(PSTREAM_FBADDR0_REG,
3573		   ((y * pScrn->displayWidth + (x & ~7)) *
3574		    pScrn->bitsPerPixel / 8));
3575      else
3576	OUTREG(PSTREAM_FBADDR0_REG,
3577		   ((y * pScrn->displayWidth + (x & ~3)) *
3578		    pScrn->bitsPerPixel / 8));
3579      }
3580
3581   return;
3582}
3583
3584
3585
3586
3587/* Usually mandatory */
3588Bool
3589S3VSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
3590{
3591    return S3VModeInit(xf86Screens[scrnIndex], mode);
3592}
3593
3594
3595
3596void S3VLoadPalette(
3597    ScrnInfoPtr pScrn,
3598    int numColors,
3599    int *indicies,
3600    LOCO *colors,
3601    VisualPtr pVisual
3602){
3603    S3VPtr ps3v = S3VPTR(pScrn);
3604    int i, index;
3605
3606    for(i = 0; i < numColors; i++) {
3607	index = indicies[i];
3608        VGAOUT8(0x3c8, index);
3609        VGAOUT8(0x3c9, colors[index].red);
3610        VGAOUT8(0x3c9, colors[index].green);
3611        VGAOUT8(0x3c9, colors[index].blue);
3612    }
3613}
3614
3615
3616/*
3617 * Functions to support getting a ViRGE card into MMIO mode if it fails to
3618 * default to MMIO enabled.
3619 */
3620
3621void
3622S3VEnableMmio(ScrnInfoPtr pScrn)
3623{
3624  vgaHWPtr hwp;
3625  S3VPtr ps3v;
3626  IOADDRESS vgaCRIndex, vgaCRReg;
3627  unsigned char val;
3628
3629  PVERB5("	S3VEnableMmio\n");
3630
3631  hwp = VGAHWPTR(pScrn);
3632  ps3v = S3VPTR(pScrn);
3633  /*
3634   * enable chipset (seen on uninitialized secondary cards)
3635   * might not be needed once we use the VGA softbooter
3636   * (EE 05/04/99)
3637   */
3638  vgaHWSetStdFuncs(hwp);
3639  /*
3640   * any access to the legacy VGA ports is done here.
3641   * If legacy VGA is inaccessable the MMIO base _has_
3642   * to be set correctly already and MMIO _has_ to be
3643   * enabled.
3644   */
3645  val = inb(hwp->PIOOffset + 0x3C3);               /*@@@EE*/
3646  outb(hwp->PIOOffset + 0x3C3, val | 0x01);
3647  /*
3648   * set CR registers to color mode
3649   * in mono mode extended CR registers
3650   * are not accessible. (EE 05/04/99)
3651   */
3652  val = inb(hwp->PIOOffset + VGA_MISC_OUT_R);      /*@@@EE*/
3653  outb(hwp->PIOOffset + VGA_MISC_OUT_W, val | 0x01);
3654  vgaHWGetIOBase(hwp);             	/* Get VGA I/O base */
3655  vgaCRIndex = hwp->PIOOffset + hwp->IOBase + 4;
3656  vgaCRReg = vgaCRIndex + 1;
3657#if 1
3658  /*
3659   * set linear base register to the PCI register values
3660   * some DX chipsets don't seem to do it automatically
3661   * (EE 06/03/99)
3662   */
3663  outb(vgaCRIndex, 0x59);         /*@@@EE*/
3664  outb(vgaCRReg, PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) >> 24);
3665  outb(vgaCRIndex, 0x5A);
3666  outb(vgaCRReg, PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) >> 16);
3667  outb(vgaCRIndex, 0x53);
3668#endif
3669  /* Save register for restore */
3670  ps3v->EnableMmioCR53 = inb(vgaCRReg);
3671  			      	/* Enable new MMIO, if TRIO mmio is already */
3672				/* enabled, then it stays enabled. */
3673  outb(vgaCRReg, ps3v->EnableMmioCR53 | 0x08);
3674  outb(hwp->PIOOffset + VGA_MISC_OUT_W, val);
3675  if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
3676    outb(vgaCRIndex, 0x40);
3677    val = inb(vgaCRReg);
3678    outb(vgaCRReg, val | 1);
3679  }
3680}
3681
3682
3683
3684void
3685S3VDisableMmio(ScrnInfoPtr pScrn)
3686{
3687  vgaHWPtr hwp;
3688  S3VPtr ps3v;
3689  IOADDRESS vgaCRIndex, vgaCRReg;
3690
3691  PVERB5("	S3VDisableMmio\n");
3692
3693  hwp = VGAHWPTR(pScrn);
3694  ps3v = S3VPTR(pScrn);
3695
3696  vgaCRIndex = hwp->PIOOffset + hwp->IOBase + 4;
3697  vgaCRReg = vgaCRIndex + 1;
3698  outb(vgaCRIndex, 0x53);
3699				/* Restore register's original state */
3700  outb(vgaCRReg, ps3v->EnableMmioCR53);
3701  if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
3702    unsigned char val;
3703    outb(vgaCRIndex, 0x40);
3704    val = inb(vgaCRReg);
3705    outb(vgaCRReg, val | 1);
3706  }
3707}
3708
3709
3710
3711/* This function is used to debug, it prints out the contents of s3 regs */
3712
3713static void
3714S3VPrintRegs(ScrnInfoPtr pScrn)
3715{
3716    unsigned char tmp1, tmp2;
3717    vgaHWPtr hwp = VGAHWPTR(pScrn);
3718    S3VPtr ps3v = S3VPTR(pScrn);
3719    int vgaCRIndex, vgaCRReg, vgaIOBase, vgaIR;
3720    vgaIOBase = hwp->IOBase;
3721    vgaCRIndex = vgaIOBase + 4;
3722    vgaCRReg = vgaIOBase + 5;
3723    vgaIR = vgaIOBase + 0xa;
3724
3725/* All registers */
3726/* New formatted registers, matches s3rc (sort of) */
3727    xf86DrvMsgVerb( pScrn->scrnIndex, X_INFO, VERBLEV, "START register dump ------------------\n");
3728    xf86ErrorFVerb(VERBLEV, "Misc Out[3CC]\n  ");
3729    xf86ErrorFVerb(VERBLEV, "%02x\n",VGAIN8(0x3cc));
3730
3731    xf86ErrorFVerb(VERBLEV, "\nCR[00-2f]\n  ");
3732    for(tmp1=0x0;tmp1<=0x2f;tmp1++){
3733	VGAOUT8(vgaCRIndex, tmp1);
3734	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(vgaCRReg));
3735	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
3736	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
3737    }
3738
3739    xf86ErrorFVerb(VERBLEV, "\nSR[00-27]\n  ");
3740    for(tmp1=0x0;tmp1<=0x27;tmp1++){
3741	VGAOUT8(0x3c4, tmp1);
3742	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(0x3c5));
3743	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
3744	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
3745    }
3746    xf86ErrorFVerb(VERBLEV, "\n"); /* odd hex number of digits... */
3747
3748    xf86ErrorFVerb(VERBLEV, "\nGr Cont GR[00-0f]\n  ");
3749    for(tmp1=0x0;tmp1<=0x0f;tmp1++){
3750	VGAOUT8(0x3ce, tmp1);
3751	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(0x3cf));
3752	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
3753	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
3754    }
3755
3756    xf86ErrorFVerb(VERBLEV, "\nAtt Cont AR[00-1f]\n  ");
3757    VGAIN8(vgaIR); /* preset AR flip-flop by reading 3DA, ignore return value */
3758    tmp2=VGAIN8(0x3c0) & 0x20;
3759    for(tmp1=0x0;tmp1<=0x1f;tmp1++){
3760    VGAIN8(vgaIR); /* preset AR flip-flop by reading 3DA, ignore return value */
3761	VGAOUT8(0x3c0, (tmp1 & ~0x20) | tmp2);
3762	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(0x3c1));
3763	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
3764	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
3765    }
3766
3767    xf86ErrorFVerb(VERBLEV, "\nCR[30-6f]\n  ");
3768    for(tmp1=0x30;tmp1<=0x6f;tmp1++){
3769	VGAOUT8(vgaCRIndex, tmp1);
3770	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(vgaCRReg));
3771	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
3772	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
3773    }
3774
3775    xf86ErrorFVerb(VERBLEV, "\n");
3776    xf86DrvMsgVerb( pScrn->scrnIndex, X_INFO, VERBLEV, "END register dump --------------------\n");
3777}
3778
3779/* this is just a debugger hook */
3780/*
3781void print_subsys_stat(void *s3vMmioMem);
3782void
3783print_subsys_stat(void *s3vMmioMem)
3784{
3785  ErrorF("IN_SUBSYS_STAT() = %x\n", IN_SUBSYS_STAT());
3786  return;
3787}
3788*/
3789
3790/*
3791 * S3VDisplayPowerManagementSet --
3792 *
3793 * Sets VESA Display Power Management Signaling (DPMS) Mode.
3794 */
3795static void
3796S3VDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
3797			     int flags)
3798{
3799  S3VPtr ps3v;
3800  unsigned char sr8 = 0x0, srd = 0x0;
3801  char modestr[][40] = { "On","Standby","Suspend","Off" };
3802
3803  ps3v = S3VPTR(pScrn);
3804
3805  /* unlock extended sequence registers */
3806
3807  VGAOUT8(0x3c4, 0x08);
3808  sr8 = VGAIN8(0x3c5);
3809  sr8 |= 0x6;
3810  VGAOUT8(0x3c5, sr8);
3811
3812  /* load SRD */
3813  VGAOUT8(0x3c4, 0x0d);
3814  srd = VGAIN8(0x3c5);
3815
3816  srd &= 0x03; /* clear the sync control bits of srd */
3817
3818  switch (PowerManagementMode) {
3819  case DPMSModeOn:
3820    /* Screen: On; HSync: On, VSync: On */
3821    break;
3822  case DPMSModeStandby:
3823    /* Screen: Off; HSync: Off, VSync: On */
3824    srd |= 0x10;
3825    break;
3826  case DPMSModeSuspend:
3827    /* Screen: Off; HSync: On, VSync: Off */
3828    srd |= 0x40;
3829    break;
3830  case DPMSModeOff:
3831    /* Screen: Off; HSync: Off, VSync: Off */
3832    srd |= 0x50;
3833    break;
3834  default:
3835    xf86ErrorFVerb(VERBLEV, "Invalid PowerManagementMode %d passed to S3VDisplayPowerManagementSet\n", PowerManagementMode);
3836    break;
3837  }
3838
3839  VGAOUT8(0x3c4, 0x0d);
3840  VGAOUT8(0x3c5, srd);
3841
3842  xf86ErrorFVerb(VERBLEV, "Power Manag: set:%s\n",
3843		 modestr[PowerManagementMode]);
3844
3845  return;
3846}
3847
3848static unsigned int
3849S3Vddc1Read(ScrnInfoPtr pScrn)
3850{
3851    register vgaHWPtr hwp = VGAHWPTR(pScrn);
3852    register CARD32 tmp;
3853    S3VPtr ps3v = S3VPTR(pScrn);
3854
3855    while (hwp->readST01(hwp)&0x8) {};
3856    while (!(hwp->readST01(hwp)&0x8)) {};
3857
3858    tmp = (INREG(DDC_REG));
3859    return ((unsigned int) (tmp & 0x08));
3860}
3861
3862static Bool
3863S3Vddc1(int scrnIndex)
3864{
3865    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
3866    S3VPtr ps3v = S3VPTR(pScrn);
3867    CARD32 tmp;
3868    Bool success = FALSE;
3869    xf86MonPtr pMon;
3870
3871    /* initialize chipset */
3872    tmp = INREG(DDC_REG);
3873    OUTREG(DDC_REG,(tmp | 0x12));
3874
3875    if ((pMon = xf86PrintEDID(
3876	xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(),
3877	                S3Vddc1Read))) != NULL)
3878	success = TRUE;
3879    xf86SetDDCproperties(pScrn,pMon);
3880
3881    /* undo initialization */
3882    OUTREG(DDC_REG,(tmp));
3883    return success;
3884}
3885
3886static Bool
3887S3Vddc2(int scrnIndex)
3888{
3889    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
3890    S3VPtr ps3v = S3VPTR(pScrn);
3891
3892    if ( xf86LoadSubModule(pScrn, "i2c") ) {
3893	xf86LoaderReqSymLists(i2cSymbols,NULL);
3894	if (S3V_I2CInit(pScrn)) {
3895	    CARD32 tmp = (INREG(DDC_REG));
3896	    OUTREG(DDC_REG,(tmp | 0x13));
3897	    xf86SetDDCproperties(pScrn,xf86PrintEDID(
3898		xf86DoEDID_DDC2(pScrn->scrnIndex,ps3v->I2C)));
3899	    OUTREG(DDC_REG,tmp);
3900	    return TRUE;
3901	}
3902    }
3903    return FALSE;
3904}
3905
3906static void
3907S3VProbeDDC(ScrnInfoPtr pScrn, int index)
3908{
3909    vbeInfoPtr pVbe;
3910    if (xf86LoadSubModule(pScrn, "vbe")) {
3911        pVbe = VBEInit(NULL,index);
3912        ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3913	vbeFree(pVbe);
3914    }
3915}
3916
3917/*EOF*/
3918
3919
3920