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