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