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