11d54945dSmrg
21d54945dSmrg/*
31d54945dSmrgCopyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
41d54945dSmrg
51d54945dSmrgPermission is hereby granted, free of charge, to any person obtaining a copy of
61d54945dSmrgthis software and associated documentation files (the "Software"), to deal in
71d54945dSmrgthe Software without restriction, including without limitation the rights to
81d54945dSmrguse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
91d54945dSmrgof the Software, and to permit persons to whom the Software is furnished to do
101d54945dSmrgso, subject to the following conditions:
111d54945dSmrg
121d54945dSmrgThe above copyright notice and this permission notice shall be included in all
131d54945dSmrgcopies or substantial portions of the Software.
141d54945dSmrg
151d54945dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161d54945dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
171d54945dSmrgNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
181d54945dSmrgXFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
191d54945dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
201d54945dSmrgWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
211d54945dSmrg
221d54945dSmrgExcept as contained in this notice, the name of the XFree86 Project shall not
231d54945dSmrgbe used in advertising or otherwise to promote the sale, use or other dealings
241d54945dSmrgin this Software without prior written authorization from the XFree86 Project.
251d54945dSmrg*/
261d54945dSmrg
271d54945dSmrg#ifdef HAVE_CONFIG_H
281d54945dSmrg#include "config.h"
291d54945dSmrg#endif
301d54945dSmrg
31ba85709eSmrg#include <unistd.h>
32ec713c28Smrg
33ec713c28Smrg#include "xf86.h"
34ec713c28Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
351d54945dSmrg#include "xf86Resources.h"
361d54945dSmrg/* Needed by Resources Access Control (RAC) */
371d54945dSmrg#include "xf86RAC.h"
38ec713c28Smrg#endif
391d54945dSmrg
401d54945dSmrg#include "xf86DDC.h"
411d54945dSmrg#include "vbe.h"
421d54945dSmrg
431d54945dSmrg/* Needed by the Shadow Framebuffer */
441d54945dSmrg#include "shadowfb.h"
451d54945dSmrg
461d54945dSmrg/*
471d54945dSmrg * s3v_driver.c
481d54945dSmrg * Port to 4.0 design level
491d54945dSmrg *
501d54945dSmrg * S3 ViRGE driver
511d54945dSmrg *
521d54945dSmrg * 10/98 - 3/99 Kevin Brosius
531d54945dSmrg * based largely on the SVGA ViRGE driver from 3.3.3x,
541d54945dSmrg * Started 09/03/97 by S. Marineau
551d54945dSmrg *
561d54945dSmrg *
571d54945dSmrg */
581d54945dSmrg
591d54945dSmrg
605788ca14Smrg/* Most xf86 commons are already in s3v.h */
615788ca14Smrg#include "s3v.h"
625788ca14Smrg#include "s3v_pciids.h"
631d54945dSmrg
641d54945dSmrg
651d54945dSmrg#include "globals.h"
66ec713c28Smrg#ifdef HAVE_XEXTPROTO_71
67ec713c28Smrg#include <X11/extensions/dpmsconst.h>
68ec713c28Smrg#else
691d54945dSmrg#define DPMS_SERVER
701d54945dSmrg#include <X11/extensions/dpms.h>
71ec713c28Smrg#endif
72ec713c28Smrg
731d54945dSmrg
741d54945dSmrg#ifndef USE_INT10
751d54945dSmrg#define USE_INT10 0
761d54945dSmrg#endif
771d54945dSmrg
781d54945dSmrg/*
791d54945dSmrg * Internals
801d54945dSmrg */
811d54945dSmrgstatic void S3VEnableMmio(ScrnInfoPtr pScrn);
821d54945dSmrgstatic void S3VDisableMmio(ScrnInfoPtr pScrn);
831d54945dSmrg
841d54945dSmrg/*
851d54945dSmrg * Forward definitions for the functions that make up the driver.
861d54945dSmrg */
871d54945dSmrg
881d54945dSmrg/* Mandatory functions */
891d54945dSmrgstatic const OptionInfoRec * S3VAvailableOptions(int chipid, int busid);
901d54945dSmrgstatic void S3VIdentify(int flags);
911d54945dSmrgstatic Bool S3VProbe(DriverPtr drv, int flags);
921d54945dSmrgstatic Bool S3VPreInit(ScrnInfoPtr pScrn, int flags);
931d54945dSmrg
945788ca14Smrgstatic Bool S3VEnterVT(VT_FUNC_ARGS_DECL);
955788ca14Smrgstatic void S3VLeaveVT(VT_FUNC_ARGS_DECL);
961d54945dSmrgstatic void S3VSave (ScrnInfoPtr pScrn);
971d54945dSmrgstatic void S3VWriteMode (ScrnInfoPtr pScrn, vgaRegPtr, S3VRegPtr);
981d54945dSmrg
991d54945dSmrgstatic void S3VSaveSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams);
1001d54945dSmrgstatic void S3VRestoreSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams);
1011d54945dSmrgstatic void S3VDisableSTREAMS(ScrnInfoPtr pScrn);
1025788ca14Smrgstatic Bool S3VScreenInit(SCREEN_INIT_ARGS_DECL);
1035788ca14Smrgstatic int S3VInternalScreenInit(ScrnInfoPtr pScrn, ScreenPtr pScreen);
1041d54945dSmrgstatic void S3VPrintRegs(ScrnInfoPtr);
1055788ca14Smrgstatic ModeStatus S3VValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags);
1061d54945dSmrg
1071d54945dSmrgstatic Bool S3VMapMem(ScrnInfoPtr pScrn);
1081d54945dSmrgstatic void S3VUnmapMem(ScrnInfoPtr pScrn);
1091d54945dSmrgstatic Bool S3VModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
1105788ca14Smrgstatic Bool S3VCloseScreen(CLOSE_SCREEN_ARGS_DECL);
1111d54945dSmrgstatic Bool S3VSaveScreen(ScreenPtr pScreen, int mode);
1121d54945dSmrgstatic void S3VInitSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams, DisplayModePtr mode);
1130b7217d9Smrgstatic void S3VLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual);
1141d54945dSmrg
1151d54945dSmrgstatic void S3VDisplayPowerManagementSet(ScrnInfoPtr pScrn,
1161d54945dSmrg					 int PowerManagementMode,
1171d54945dSmrg					 int flags);
1185788ca14Smrgstatic Bool S3Vddc1(ScrnInfoPtr pScrn);
1195788ca14Smrgstatic Bool S3Vddc2(ScrnInfoPtr pScrn);
1201d54945dSmrg
1211d54945dSmrgstatic unsigned int S3Vddc1Read(ScrnInfoPtr pScrn);
1221d54945dSmrgstatic void S3VProbeDDC(ScrnInfoPtr pScrn, int index);
1231d54945dSmrg
1241d54945dSmrg/*
1251d54945dSmrg * This is intentionally screen-independent.  It indicates the binding
1261d54945dSmrg * choice made in the first PreInit.
1271d54945dSmrg */
1281d54945dSmrgstatic int pix24bpp = 0;
1291d54945dSmrg
1301d54945dSmrg#define S3VIRGE_NAME "S3VIRGE"
1311d54945dSmrg#define S3VIRGE_DRIVER_NAME "s3virge"
132ba85709eSmrg#define S3VIRGE_VERSION_NAME PACKAGE_VERSION
133ba85709eSmrg#define S3VIRGE_VERSION_MAJOR   PACKAGE_VERSION_MAJOR
134ba85709eSmrg#define S3VIRGE_VERSION_MINOR   PACKAGE_VERSION_MINOR
135ba85709eSmrg#define S3VIRGE_PATCHLEVEL      PACKAGE_VERSION_PATCHLEVEL
1361d54945dSmrg#define S3VIRGE_DRIVER_VERSION ((S3VIRGE_VERSION_MAJOR << 24) | \
1371d54945dSmrg				(S3VIRGE_VERSION_MINOR << 16) | \
1381d54945dSmrg				S3VIRGE_PATCHLEVEL)
1391d54945dSmrg
1401d54945dSmrg/*
1411d54945dSmrg * This contains the functions needed by the server after loading the
1421d54945dSmrg * driver module.  It must be supplied, and gets added the driver list by
1430b7217d9Smrg * the Module Setup function in the dynamic case.  In the static case a
1441d54945dSmrg * reference to this is compiled in, and this requires that the name of
1451d54945dSmrg * this DriverRec be an upper-case version of the driver name.
1461d54945dSmrg */
1471d54945dSmrg
1481d54945dSmrg_X_EXPORT DriverRec S3VIRGE =
1491d54945dSmrg{
1501d54945dSmrg    S3VIRGE_DRIVER_VERSION,
1511d54945dSmrg    S3VIRGE_DRIVER_NAME,
1521d54945dSmrg    S3VIdentify,
1531d54945dSmrg    S3VProbe,
1541d54945dSmrg    S3VAvailableOptions,
1551d54945dSmrg    NULL,
1561d54945dSmrg    0
1571d54945dSmrg};
1581d54945dSmrg
1591d54945dSmrg
1601d54945dSmrg/* Supported chipsets */
1611d54945dSmrgstatic SymTabRec S3VChipsets[] = {
1621d54945dSmrg				  	/* base (86C325) */
1631d54945dSmrg  { PCI_CHIP_VIRGE,			"virge" },
1641d54945dSmrg  { PCI_CHIP_VIRGE,			"86C325" },
1651d54945dSmrg  					/* VX (86C988) */
1661d54945dSmrg  { PCI_CHIP_VIRGE_VX,		"virge vx" },
1671d54945dSmrg  { PCI_CHIP_VIRGE_VX,		"86C988" },
1681d54945dSmrg  					/* DX (86C375) GX (86C385) */
1691d54945dSmrg  { PCI_CHIP_VIRGE_DXGX,	"virge dx" },
1701d54945dSmrg  { PCI_CHIP_VIRGE_DXGX,	"virge gx" },
1711d54945dSmrg  { PCI_CHIP_VIRGE_DXGX,	"86C375" },
1721d54945dSmrg  { PCI_CHIP_VIRGE_DXGX,	"86C385" },
1731d54945dSmrg                                        /* GX2 (86C357) */
1741d54945dSmrg  { PCI_CHIP_VIRGE_GX2,		"virge gx2" },
1751d54945dSmrg  { PCI_CHIP_VIRGE_GX2,		"86C357" },
1761d54945dSmrg  					/* MX (86C260) */
1771d54945dSmrg  { PCI_CHIP_VIRGE_MX,		"virge mx" },
1781d54945dSmrg  { PCI_CHIP_VIRGE_MX,		"86C260" },
1791d54945dSmrg  					/* MX+ (86C280) */
1801d54945dSmrg  { PCI_CHIP_VIRGE_MXP,		"virge mx+" },
1811d54945dSmrg  { PCI_CHIP_VIRGE_MXP,		"86C280" },
1821d54945dSmrg  					/* Trio3D (86C365) */
1831d54945dSmrg  { PCI_CHIP_Trio3D,		"trio 3d" },
1841d54945dSmrg  { PCI_CHIP_Trio3D,		"86C365" },
1851d54945dSmrg  					/* Trio3D/2x (86C362/86C368) */
1861d54945dSmrg  { PCI_CHIP_Trio3D_2X,		"trio 3d/2x" },
1871d54945dSmrg  { PCI_CHIP_Trio3D_2X,		"86C362" },
1881d54945dSmrg  { PCI_CHIP_Trio3D_2X,		"86C368" },
1891d54945dSmrg  {-1,			NULL }
1901d54945dSmrg};
1911d54945dSmrg
1921d54945dSmrgstatic PciChipsets S3VPciChipsets[] = {
1931d54945dSmrg  /* numChipset,		PciID,			Resource */
1941d54945dSmrg  { PCI_CHIP_VIRGE,      PCI_CHIP_VIRGE,     	RES_SHARED_VGA },
1951d54945dSmrg  { PCI_CHIP_VIRGE_VX,   PCI_CHIP_VIRGE_VX,     RES_SHARED_VGA },
1961d54945dSmrg  { PCI_CHIP_VIRGE_DXGX, PCI_CHIP_VIRGE_DXGX,	RES_SHARED_VGA },
1971d54945dSmrg  { PCI_CHIP_VIRGE_GX2,  PCI_CHIP_VIRGE_GX2,  	RES_SHARED_VGA },
1981d54945dSmrg  { PCI_CHIP_VIRGE_MX,   PCI_CHIP_VIRGE_MX,   	RES_SHARED_VGA },
1991d54945dSmrg  { PCI_CHIP_VIRGE_MXP,  PCI_CHIP_VIRGE_MXP,  	RES_SHARED_VGA },
2001d54945dSmrg  { PCI_CHIP_Trio3D,     PCI_CHIP_Trio3D,  	RES_SHARED_VGA },
2011d54945dSmrg  { PCI_CHIP_Trio3D_2X,  PCI_CHIP_Trio3D_2X,  	RES_SHARED_VGA },
2021d54945dSmrg  { -1,                       -1,   		RES_UNDEFINED }
2031d54945dSmrg};
2041d54945dSmrg
2051d54945dSmrgtypedef enum {
2061d54945dSmrg   OPTION_SLOW_EDODRAM,
2071d54945dSmrg   OPTION_SLOW_DRAM,
2081d54945dSmrg   OPTION_FAST_DRAM,
2091d54945dSmrg   OPTION_FPM_VRAM,
2101d54945dSmrg   OPTION_PCI_BURST,
2111d54945dSmrg   OPTION_FIFO_CONSERV,
2121d54945dSmrg   OPTION_FIFO_MODERATE,
2131d54945dSmrg   OPTION_FIFO_AGGRESSIVE,
2141d54945dSmrg   OPTION_PCI_RETRY,
2151d54945dSmrg   OPTION_NOACCEL,
2161d54945dSmrg   OPTION_EARLY_RAS_PRECHARGE,
2171d54945dSmrg   OPTION_LATE_RAS_PRECHARGE,
2181d54945dSmrg   OPTION_LCD_CENTER,
2191d54945dSmrg   OPTION_LCDCLOCK,
2201d54945dSmrg   OPTION_MCLK,
2211d54945dSmrg   OPTION_REFCLK,
2221d54945dSmrg   OPTION_SHOWCACHE,
2231d54945dSmrg   OPTION_SWCURSOR,
2241d54945dSmrg   OPTION_HWCURSOR,
2251d54945dSmrg   OPTION_SHADOW_FB,
2261d54945dSmrg   OPTION_ROTATE,
2271d54945dSmrg   OPTION_FB_DRAW,
2281d54945dSmrg   OPTION_MX_CR3A_FIX,
2291d54945dSmrg   OPTION_XVIDEO
2301d54945dSmrg} S3VOpts;
2311d54945dSmrg
2321d54945dSmrgstatic const OptionInfoRec S3VOptions[] =
2331d54945dSmrg{
2341d54945dSmrg  /*    int token, const char* name, OptionValueType type,
2351d54945dSmrg	ValueUnion value, Bool found.
2361d54945dSmrg  */
2371d54945dSmrg   { OPTION_SLOW_EDODRAM, 	"slow_edodram",	OPTV_BOOLEAN,	{0}, FALSE },
2381d54945dSmrg   { OPTION_SLOW_DRAM, 		"slow_dram",	OPTV_BOOLEAN,	{0}, FALSE },
2391d54945dSmrg   { OPTION_FAST_DRAM, 		"fast_dram",	OPTV_BOOLEAN,	{0}, FALSE },
2401d54945dSmrg   { OPTION_FPM_VRAM, 		"fpm_vram",	OPTV_BOOLEAN,	{0}, FALSE },
2411d54945dSmrg   { OPTION_PCI_BURST, 		"pci_burst",	OPTV_BOOLEAN,	{0}, FALSE },
2421d54945dSmrg   { OPTION_FIFO_CONSERV, 	"fifo_conservative", OPTV_BOOLEAN, {0}, FALSE },
2431d54945dSmrg   { OPTION_FIFO_MODERATE, 	"fifo_moderate", OPTV_BOOLEAN, 	{0}, FALSE },
2441d54945dSmrg   { OPTION_FIFO_AGGRESSIVE, 	"fifo_aggressive", OPTV_BOOLEAN, {0}, FALSE },
2451d54945dSmrg   { OPTION_PCI_RETRY, 		"pci_retry",	OPTV_BOOLEAN,	{0}, FALSE  },
2461d54945dSmrg   { OPTION_NOACCEL, 		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE  },
2471d54945dSmrg   { OPTION_EARLY_RAS_PRECHARGE, "early_ras_precharge",	OPTV_BOOLEAN, {0}, FALSE },
2481d54945dSmrg   { OPTION_LATE_RAS_PRECHARGE, "late_ras_precharge", OPTV_BOOLEAN, {0}, FALSE },
2491d54945dSmrg   { OPTION_LCD_CENTER, 	"lcd_center", 	OPTV_BOOLEAN, 	{0}, FALSE },
2501d54945dSmrg   { OPTION_LCDCLOCK, 		"set_lcdclk", 	OPTV_INTEGER, 	{0}, FALSE },
2511d54945dSmrg   { OPTION_MCLK, 		"set_mclk", 	OPTV_FREQ, 	{0}, FALSE },
2521d54945dSmrg   { OPTION_REFCLK, 		"set_refclk", 	OPTV_FREQ, 	{0}, FALSE },
2531d54945dSmrg   { OPTION_SHOWCACHE,		"show_cache",   OPTV_BOOLEAN,	{0}, FALSE },
2541d54945dSmrg   { OPTION_HWCURSOR,		"HWCursor",     OPTV_BOOLEAN,	{0}, FALSE },
2551d54945dSmrg   { OPTION_SWCURSOR,		"SWCursor",     OPTV_BOOLEAN,	{0}, FALSE },
2561d54945dSmrg   { OPTION_SHADOW_FB,          "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
2571d54945dSmrg   { OPTION_ROTATE, 	        "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
2581d54945dSmrg   { OPTION_MX_CR3A_FIX,        "mxcr3afix",	OPTV_BOOLEAN,	{0}, FALSE },
2591d54945dSmrg   { OPTION_XVIDEO,             "XVideo",	OPTV_BOOLEAN,	{0}, FALSE },
2601d54945dSmrg   {-1, NULL, OPTV_NONE,	{0}, FALSE}
2611d54945dSmrg};
2621d54945dSmrg
2631d54945dSmrg#ifdef XFree86LOADER
2641d54945dSmrg
2651d54945dSmrgstatic MODULESETUPPROTO(s3virgeSetup);
2661d54945dSmrg
2671d54945dSmrgstatic XF86ModuleVersionInfo S3VVersRec =
2681d54945dSmrg{
2691d54945dSmrg    "s3virge",
2701d54945dSmrg    MODULEVENDORSTRING,
2711d54945dSmrg    MODINFOSTRING1,
2721d54945dSmrg    MODINFOSTRING2,
2731d54945dSmrg    XORG_VERSION_CURRENT,
2741d54945dSmrg    S3VIRGE_VERSION_MAJOR, S3VIRGE_VERSION_MINOR, S3VIRGE_PATCHLEVEL,
2751d54945dSmrg    ABI_CLASS_VIDEODRV,		       /* This is a video driver */
2761d54945dSmrg    ABI_VIDEODRV_VERSION,
2771d54945dSmrg    MOD_CLASS_VIDEODRV,
2781d54945dSmrg    {0, 0, 0, 0}
2791d54945dSmrg};
2801d54945dSmrg
2811d54945dSmrg
2821d54945dSmrg/*
2831d54945dSmrg * This is the module init data for XFree86 modules.
2841d54945dSmrg *
2851d54945dSmrg * Its name has to be the driver name followed by ModuleData.
2861d54945dSmrg */
2871d54945dSmrg_X_EXPORT XF86ModuleData s3virgeModuleData = {
2881d54945dSmrg    &S3VVersRec,
2891d54945dSmrg    s3virgeSetup,
2901d54945dSmrg    NULL
2911d54945dSmrg};
2921d54945dSmrg
2931d54945dSmrgstatic pointer
2941d54945dSmrgs3virgeSetup(pointer module, pointer opts, int *errmaj, int *errmin)
2951d54945dSmrg{
2961d54945dSmrg    static Bool setupDone = FALSE;
2971d54945dSmrg
2981d54945dSmrg    if (!setupDone) {
2991d54945dSmrg	setupDone = TRUE;
3001d54945dSmrg	xf86AddDriver(&S3VIRGE, module, 0);
3011d54945dSmrg
3021d54945dSmrg	/*
3031d54945dSmrg	 * The return value must be non-NULL on success even though there
3041d54945dSmrg	 * is no TearDownProc.
3051d54945dSmrg	 */
3061d54945dSmrg	return (pointer) 1;
3071d54945dSmrg    } else {
3081d54945dSmrg	if (errmaj)
3091d54945dSmrg	    *errmaj = LDR_ONCEONLY;
3101d54945dSmrg	return NULL;
3111d54945dSmrg    }
3121d54945dSmrg}
3131d54945dSmrg
3141d54945dSmrg#endif /* XFree86LOADER */
3151d54945dSmrg
3161d54945dSmrg
3170b7217d9Smrgstatic unsigned char *find_bios_string(S3VPtr ps3v, int BIOSbase,
3180b7217d9Smrg                                       const char *match1, const char *match2)
3191d54945dSmrg{
3201b8468c1Sskrll#define BIOS_BSIZE 0x10000
3211d54945dSmrg#define BIOS_BASE  0xc0000
3221d54945dSmrg
3231d54945dSmrg   static unsigned char bios[BIOS_BSIZE];
3241d54945dSmrg   static int init=0;
3251d54945dSmrg   int i,j,l1,l2;
3261d54945dSmrg
3271d54945dSmrg   if (!init) {
3281d54945dSmrg      init = 1;
329ba85709eSmrg#ifndef XSERVER_LIBPCIACCESS
330ba85709eSmrg      if (xf86ReadDomainMemory(ps3v->PciTag, BIOSbase, BIOS_BSIZE, bios) != BIOS_BSIZE)
3311d54945dSmrg	 return NULL;
332ba85709eSmrg#else
333ba85709eSmrg      if (pci_device_read_rom(ps3v->PciInfo, bios))
334ba85709eSmrg	return NULL;
335ba85709eSmrg#endif
3361d54945dSmrg      if ((bios[0] != 0x55) || (bios[1] != 0xaa))
3371d54945dSmrg	 return NULL;
3381d54945dSmrg   }
3391d54945dSmrg   if (match1 == NULL)
3401d54945dSmrg      return NULL;
3411d54945dSmrg
3421d54945dSmrg   l1 = strlen(match1);
3431d54945dSmrg   if (match2 != NULL)
3441d54945dSmrg      l2 = strlen(match2);
3451d54945dSmrg   else	/* for compiler-warnings */
3461d54945dSmrg      l2 = 0;
3471d54945dSmrg
3481d54945dSmrg   for (i=0; i<BIOS_BSIZE-l1; i++)
3491d54945dSmrg       if (bios[i] == match1[0] && !memcmp(&bios[i],match1,l1)) {
3501d54945dSmrg	 if (match2 == NULL)
3511d54945dSmrg	    return &bios[i+l1];
3521d54945dSmrg	 else
3531d54945dSmrg	    for(j=i+l1; (j<BIOS_BSIZE-l2) && bios[j]; j++)
3541d54945dSmrg	       if (bios[j] == match2[0] && !memcmp(&bios[j],match2,l2))
3551d54945dSmrg		   return &bios[j+l2];
3561d54945dSmrg       }
3571d54945dSmrg
3581d54945dSmrg   return NULL;
3591d54945dSmrg}
3601d54945dSmrg
3611d54945dSmrg
3621d54945dSmrgstatic Bool
3631d54945dSmrgS3VGetRec(ScrnInfoPtr pScrn)
3641d54945dSmrg{
3651d54945dSmrg    PVERB5("	S3VGetRec\n");
3661d54945dSmrg    /*
3671d54945dSmrg     * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate.
3681d54945dSmrg     * pScrn->driverPrivate is initialised to NULL, so we can check if
3691d54945dSmrg     * the allocation has already been done.
3701d54945dSmrg     */
3711d54945dSmrg    if (pScrn->driverPrivate != NULL)
3721d54945dSmrg	return TRUE;
3731d54945dSmrg
3741d54945dSmrg    pScrn->driverPrivate = xnfcalloc(sizeof(S3VRec), 1);
3751d54945dSmrg    /* Initialise it here when needed (or possible) */
3761d54945dSmrg
3771d54945dSmrg    return TRUE;
3781d54945dSmrg}
3791d54945dSmrg
3801d54945dSmrgstatic void
3811d54945dSmrgS3VFreeRec(ScrnInfoPtr pScrn)
3821d54945dSmrg{
3831d54945dSmrg    PVERB5("	S3VFreeRec\n");
3841d54945dSmrg    if (pScrn->driverPrivate == NULL)
3851d54945dSmrg	return;
3865788ca14Smrg    free(pScrn->driverPrivate);
3871d54945dSmrg    pScrn->driverPrivate = NULL;
3881d54945dSmrg}
3891d54945dSmrg
3901d54945dSmrgstatic const OptionInfoRec *
3911d54945dSmrgS3VAvailableOptions(int chipid, int busid)
3921d54945dSmrg{
3931d54945dSmrg    return S3VOptions;
3941d54945dSmrg}
3951d54945dSmrg
3961d54945dSmrgstatic void
3971d54945dSmrgS3VIdentify(int flags)
3981d54945dSmrg{
3991d54945dSmrg    PVERB5("	S3VIdentify\n");
4001d54945dSmrg    xf86PrintChipsets(S3VIRGE_NAME,
4011d54945dSmrg	"driver (version " S3VIRGE_VERSION_NAME ") for S3 ViRGE chipsets",
4021d54945dSmrg	S3VChipsets);
4031d54945dSmrg}
4041d54945dSmrg
4051d54945dSmrg
4061d54945dSmrgstatic Bool
4071d54945dSmrgS3VProbe(DriverPtr drv, int flags)
4081d54945dSmrg{
4091d54945dSmrg    int i;
4101d54945dSmrg    GDevPtr *devSections;
4111d54945dSmrg    int *usedChips;
4121d54945dSmrg    int numDevSections;
4131d54945dSmrg    int numUsed;
4141d54945dSmrg    Bool foundScreen = FALSE;
4151d54945dSmrg
4161d54945dSmrg    PVERB5("	S3VProbe begin\n");
4171d54945dSmrg
4181d54945dSmrg    if ((numDevSections = xf86MatchDevice(S3VIRGE_DRIVER_NAME,
4191d54945dSmrg					  &devSections)) <= 0) {
4201d54945dSmrg	/*
4211d54945dSmrg	 * There's no matching device section in the config file, so quit
4221d54945dSmrg	 * now.
4231d54945dSmrg	 */
4241d54945dSmrg	return FALSE;
4251d54945dSmrg    }
426ba85709eSmrg
427ba85709eSmrg#ifndef XSERVER_LIBPCIACCESS
4281d54945dSmrg    if (xf86GetPciVideoInfo() == NULL) {
4291d54945dSmrg	return FALSE;
4301d54945dSmrg    }
431ba85709eSmrg#endif
4321d54945dSmrg
4331d54945dSmrg    numUsed = xf86MatchPciInstances(S3VIRGE_NAME, PCI_S3_VENDOR_ID,
4341d54945dSmrg				    S3VChipsets, S3VPciChipsets, devSections,
4351d54945dSmrg				    numDevSections, drv, &usedChips);
4361d54945dSmrg
4371d54945dSmrg    /* Free it since we don't need that list after this */
4385788ca14Smrg    free(devSections);
4391d54945dSmrg    if (numUsed <= 0)
4401d54945dSmrg	return FALSE;
4411d54945dSmrg
4421d54945dSmrg    if (flags & PROBE_DETECT)
4431d54945dSmrg	foundScreen = TRUE;
4441d54945dSmrg    else for (i = 0; i < numUsed; i++) {
4451d54945dSmrg	/* Allocate a ScrnInfoRec and claim the slot */
4461d54945dSmrg	ScrnInfoPtr pScrn = NULL;
4471d54945dSmrg	if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
4481d54945dSmrg					       S3VPciChipsets,NULL,NULL, NULL,
4491d54945dSmrg					       NULL,NULL))) {
4501d54945dSmrg	    /* Fill in what we can of the ScrnInfoRec */
4511d54945dSmrg	    pScrn->driverVersion = S3VIRGE_DRIVER_VERSION;
4521d54945dSmrg	    pScrn->driverName	 = S3VIRGE_DRIVER_NAME;
4531d54945dSmrg	    pScrn->name		 = S3VIRGE_NAME;
4541d54945dSmrg	    pScrn->Probe	 = S3VProbe;
4551d54945dSmrg	    pScrn->PreInit	 = S3VPreInit;
4561d54945dSmrg	    pScrn->ScreenInit	 = S3VScreenInit;
4571d54945dSmrg	    pScrn->SwitchMode	 = S3VSwitchMode;
4581d54945dSmrg	    pScrn->AdjustFrame	 = S3VAdjustFrame;
4591d54945dSmrg	    pScrn->EnterVT	 = S3VEnterVT;
4601d54945dSmrg	    pScrn->LeaveVT	 = S3VLeaveVT;
4611d54945dSmrg	    pScrn->FreeScreen	 = NULL; /*S3VFreeScreen;*/
4621d54945dSmrg	    pScrn->ValidMode	 = S3VValidMode;
4631d54945dSmrg	    foundScreen = TRUE;
4641d54945dSmrg	}
4651d54945dSmrg    }
4665788ca14Smrg    free(usedChips);
4671d54945dSmrg    PVERB5("	S3VProbe end\n");
4681d54945dSmrg    return foundScreen;
4691d54945dSmrg}
4701d54945dSmrg
4711d54945dSmrg
4721d54945dSmrg/* Mandatory */
4731d54945dSmrgstatic Bool
4741d54945dSmrgS3VPreInit(ScrnInfoPtr pScrn, int flags)
4751d54945dSmrg{
4761d54945dSmrg    EntityInfoPtr pEnt;
4771d54945dSmrg    S3VPtr ps3v;
4781d54945dSmrg    MessageType from;
4791d54945dSmrg    int i;
4801d54945dSmrg    double real;
4811d54945dSmrg    ClockRangePtr clockRanges;
482820a851cSmrg    const char *s;
4831d54945dSmrg
4841d54945dSmrg    unsigned char config1, config2, m, n, n1, n2, cr66 = 0;
4851d54945dSmrg    int mclk;
4861d54945dSmrg
4871d54945dSmrg    vgaHWPtr hwp;
4881d54945dSmrg    int vgaCRIndex, vgaCRReg, vgaIOBase;
4891d54945dSmrg
4901d54945dSmrg    PVERB5("	S3VPreInit 1\n");
4911d54945dSmrg
4921d54945dSmrg    if (flags & PROBE_DETECT) {
4931d54945dSmrg	  S3VProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
4941d54945dSmrg      return TRUE;
4951d54945dSmrg      }
4961d54945dSmrg
4971d54945dSmrg    /*
4981d54945dSmrg     * Note: This function is only called once at server startup, and
4991d54945dSmrg     * not at the start of each server generation.  This means that
5001d54945dSmrg     * only things that are persistent across server generations can
5011d54945dSmrg     * be initialised here.  xf86Screens[] is (pScrn is a pointer to one
5021d54945dSmrg     * of these).  Privates allocated using xf86AllocateScrnInfoPrivateIndex()
5031d54945dSmrg     * are too, and should be used for data that must persist across
5041d54945dSmrg     * server generations.
5051d54945dSmrg     *
5061d54945dSmrg     * Per-generation data should be allocated with
5071d54945dSmrg     * AllocateScreenPrivateIndex() from the ScreenInit() function.
5081d54945dSmrg     */
5091d54945dSmrg
5101d54945dSmrg    /* The vgahw module should be loaded here when needed */
5111d54945dSmrg
5121d54945dSmrg    if (!xf86LoadSubModule(pScrn, "vgahw"))
5131d54945dSmrg	return FALSE;
5141d54945dSmrg
5151d54945dSmrg    /*
5161d54945dSmrg     * Allocate a vgaHWRec
5171d54945dSmrg     */
5181d54945dSmrg    if (!vgaHWGetHWRec(pScrn))
5191d54945dSmrg	return FALSE;
5205788ca14Smrg    vgaHWSetStdFuncs(VGAHWPTR(pScrn));
5211d54945dSmrg
5221d54945dSmrg    /* Set pScrn->monitor */
5231d54945dSmrg    pScrn->monitor = pScrn->confScreen->monitor;
5241d54945dSmrg
5251d54945dSmrg    /*
5261d54945dSmrg     * The first thing we should figure out is the depth, bpp, etc.
5271d54945dSmrg     * We support both 24bpp and 32bpp layouts, so indicate that.
5281d54945dSmrg     */
5291d54945dSmrg    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb |
5301d54945dSmrg				SupportConvert32to24 | PreferConvert32to24)) {
5311d54945dSmrg	return FALSE;
5321d54945dSmrg    } else {
5331d54945dSmrg	/* Check that the returned depth is one we support */
5341d54945dSmrg	switch (pScrn->depth) {
5351d54945dSmrg	case 8:
5361d54945dSmrg	case 15:
5371d54945dSmrg	case 16:
5381d54945dSmrg	case 24:
5391d54945dSmrg	    /* OK */
5401d54945dSmrg	    break;
5411d54945dSmrg	default:
5421d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5431d54945dSmrg		       "Given depth (%d) is not supported by this driver\n",
5441d54945dSmrg		       pScrn->depth);
5451d54945dSmrg	    return FALSE;
5461d54945dSmrg	}
5471d54945dSmrg    }
5481d54945dSmrg    xf86PrintDepthBpp(pScrn);
5491d54945dSmrg
5501d54945dSmrg    /* Get the depth24 pixmap format */
5511d54945dSmrg    if (pScrn->depth == 24 && pix24bpp == 0)
5521d54945dSmrg	pix24bpp = xf86GetBppFromDepth(pScrn, 24);
5531d54945dSmrg
5541d54945dSmrg    /*
5551d54945dSmrg     * This must happen after pScrn->display has been set because
5561d54945dSmrg     * xf86SetWeight references it.
5571d54945dSmrg     */
5581d54945dSmrg    if (pScrn->depth > 8) {
5591d54945dSmrg	/* The defaults are OK for us */
5601d54945dSmrg	rgb zeros = {0, 0, 0};
5611d54945dSmrg
5621d54945dSmrg	if (!xf86SetWeight(pScrn, zeros, zeros)) {
5631d54945dSmrg	    return FALSE;
5641d54945dSmrg	} else {
5651d54945dSmrg	    /* XXX check that weight returned is supported */
5661d54945dSmrg            ;
5671d54945dSmrg        }
5681d54945dSmrg    }
5691d54945dSmrg
5701d54945dSmrg    if (!xf86SetDefaultVisual(pScrn, -1)) {
5711d54945dSmrg	return FALSE;
5721d54945dSmrg    } else {		/* editme - from MGA, does ViRGE? */
5731d54945dSmrg	/* We don't currently support DirectColor at > 8bpp */
5741d54945dSmrg	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
5751d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
5761d54945dSmrg		       " (%s) is not supported at depth %d\n",
5771d54945dSmrg		       xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
5781d54945dSmrg	    return FALSE;
5791d54945dSmrg	}
5801d54945dSmrg    }
5811d54945dSmrg
5821d54945dSmrg    /* We use a programmable clock */
5831d54945dSmrg    pScrn->progClock = TRUE;
5841d54945dSmrg
5851d54945dSmrg    /* Allocate the S3VRec driverPrivate */
5861d54945dSmrg    if (!S3VGetRec(pScrn)) {
5871d54945dSmrg	return FALSE;
5881d54945dSmrg    }
5891d54945dSmrg    ps3v = S3VPTR(pScrn);
5901d54945dSmrg
5911d54945dSmrg    /* Collect all of the relevant option flags (fill in pScrn->options) */
5921d54945dSmrg    xf86CollectOptions(pScrn, NULL);
5931d54945dSmrg
5941d54945dSmrg    /* Set the bits per RGB for 8bpp mode */
5951d54945dSmrg    if (pScrn->depth == 8) {
5961d54945dSmrg    				/* ViRGE supports 6 RGB bits in depth 8 */
5971d54945dSmrg				/* modes (with 256 entry LUT) */
5981d54945dSmrg      pScrn->rgbBits = 6;
5991d54945dSmrg    }
6001d54945dSmrg
6011d54945dSmrg    /* Process the options */
6025788ca14Smrg    if (!(ps3v->Options = malloc(sizeof(S3VOptions))))
6031d54945dSmrg	return FALSE;
6041d54945dSmrg    memcpy(ps3v->Options, S3VOptions, sizeof(S3VOptions));
6051d54945dSmrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ps3v->Options);
6061d54945dSmrg
6071d54945dSmrg
6081d54945dSmrg    if (xf86ReturnOptValBool(ps3v->Options, OPTION_PCI_BURST, FALSE)) {
6091d54945dSmrg	ps3v->pci_burst = TRUE;
6101d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_burst - PCI burst read enabled\n");
6111d54945dSmrg    } else
6121d54945dSmrg   	ps3v->pci_burst = FALSE;
6131d54945dSmrg					/* default */
6141d54945dSmrg    ps3v->NoPCIRetry = 1;
6151d54945dSmrg   					/* Set option */
6161d54945dSmrg    if (xf86ReturnOptValBool(ps3v->Options, OPTION_PCI_RETRY, FALSE)) {
6171d54945dSmrg      if (xf86ReturnOptValBool(ps3v->Options, OPTION_PCI_BURST, FALSE)) {
6181d54945dSmrg      	ps3v->NoPCIRetry = 0;
6191d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n");
6201d54945dSmrg	}
6211d54945dSmrg      else {
6221d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
6231d54945dSmrg		"\"pci_retry\" option requires \"pci_burst\".\n");
6241d54945dSmrg	}
6251d54945dSmrg    }
6261d54945dSmrg    if (xf86IsOptionSet(ps3v->Options, OPTION_FIFO_CONSERV)) {
6271d54945dSmrg	ps3v->fifo_conservative = TRUE;
6281d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_conservative set\n");
6291d54945dSmrg    } else
6301d54945dSmrg   	ps3v->fifo_conservative = FALSE;
6311d54945dSmrg
6321d54945dSmrg    if (xf86IsOptionSet(ps3v->Options, OPTION_FIFO_MODERATE)) {
6331d54945dSmrg	ps3v->fifo_moderate = TRUE;
6341d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_moderate set\n");
6351d54945dSmrg    } else
6361d54945dSmrg   	ps3v->fifo_moderate = FALSE;
6371d54945dSmrg
6381d54945dSmrg    if (xf86IsOptionSet(ps3v->Options, OPTION_FIFO_AGGRESSIVE)) {
6391d54945dSmrg	ps3v->fifo_aggressive = TRUE;
6401d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_aggressive set\n");
6411d54945dSmrg    } else
6421d54945dSmrg   	ps3v->fifo_aggressive = FALSE;
6431d54945dSmrg
6441d54945dSmrg    if (xf86IsOptionSet(ps3v->Options, OPTION_SLOW_EDODRAM)) {
6451d54945dSmrg	ps3v->slow_edodram = TRUE;
6461d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: slow_edodram set\n");
6471d54945dSmrg    } else
6481d54945dSmrg   	ps3v->slow_edodram = FALSE;
6491d54945dSmrg
6501d54945dSmrg    if (xf86IsOptionSet(ps3v->Options, OPTION_SLOW_DRAM)) {
6511d54945dSmrg	ps3v->slow_dram = TRUE;
6521d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: slow_dram set\n");
6531d54945dSmrg    } else
6541d54945dSmrg   	ps3v->slow_dram = FALSE;
6551d54945dSmrg
6561d54945dSmrg    if (xf86IsOptionSet(ps3v->Options, OPTION_FAST_DRAM)) {
6571d54945dSmrg	ps3v->fast_dram = TRUE;
6581d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fast_dram set\n");
6591d54945dSmrg    } else
6601d54945dSmrg   	ps3v->fast_dram = FALSE;
6611d54945dSmrg
6621d54945dSmrg    if (xf86IsOptionSet(ps3v->Options, OPTION_FPM_VRAM)) {
6631d54945dSmrg	ps3v->fpm_vram = TRUE;
6641d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fpm_vram set\n");
6651d54945dSmrg    } else
6661d54945dSmrg   	ps3v->fpm_vram = FALSE;
6671d54945dSmrg
6681d54945dSmrg    if (xf86ReturnOptValBool(ps3v->Options, OPTION_NOACCEL, FALSE)) {
6691d54945dSmrg	ps3v->NoAccel = TRUE;
6701d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: NoAccel - Acceleration disabled\n");
6711d54945dSmrg    } else
6721d54945dSmrg   	ps3v->NoAccel = FALSE;
6731d54945dSmrg
6741d54945dSmrg    if (xf86ReturnOptValBool(ps3v->Options, OPTION_EARLY_RAS_PRECHARGE, FALSE)) {
6751d54945dSmrg	ps3v->early_ras_precharge = TRUE;
6761d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: early_ras_precharge set\n");
6771d54945dSmrg    } else
6781d54945dSmrg   	ps3v->early_ras_precharge = FALSE;
6791d54945dSmrg
6801d54945dSmrg    if (xf86ReturnOptValBool(ps3v->Options, OPTION_LATE_RAS_PRECHARGE, FALSE)) {
6811d54945dSmrg	ps3v->late_ras_precharge = TRUE;
6821d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: late_ras_precharge set\n");
6831d54945dSmrg    } else
6841d54945dSmrg   	ps3v->late_ras_precharge = FALSE;
6851d54945dSmrg
6861d54945dSmrg    if (xf86ReturnOptValBool(ps3v->Options, OPTION_LCD_CENTER, FALSE)) {
6871d54945dSmrg	ps3v->lcd_center = TRUE;
6881d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: lcd_center set\n");
6891d54945dSmrg    } else
6901d54945dSmrg   	ps3v->lcd_center = FALSE;
6911d54945dSmrg
6921d54945dSmrg    if (xf86ReturnOptValBool(ps3v->Options, OPTION_SHOWCACHE, FALSE)) {
6931d54945dSmrg	ps3v->ShowCache = TRUE;
6941d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: show_cache set\n");
6951d54945dSmrg    } else
6961d54945dSmrg   	ps3v->ShowCache = FALSE;
6971d54945dSmrg
6981d54945dSmrg    if (xf86GetOptValInteger(ps3v->Options, OPTION_LCDCLOCK, &ps3v->LCDClk)) {
6991d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: lcd_setclk set to %1.3f Mhz\n",
7001d54945dSmrg		ps3v->LCDClk / 1000.0 );
7011d54945dSmrg    } else
7021d54945dSmrg   	ps3v->LCDClk = 0;
7031d54945dSmrg
7041d54945dSmrg    if (xf86GetOptValFreq(ps3v->Options, OPTION_MCLK, OPTUNITS_MHZ, &real)) {
7051d54945dSmrg	ps3v->MCLK = (int)(real * 1000.0);
7061d54945dSmrg    	if (ps3v->MCLK <= 100000) {
7071d54945dSmrg	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_mclk set to %1.3f Mhz\n",
7081d54945dSmrg		ps3v->MCLK / 1000.0 );
7091d54945dSmrg	} else {
7101d54945dSmrg	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING
7111d54945dSmrg	  	, "Memory Clock value of %1.3f MHz is larger than limit of 100 MHz\n"
7121d54945dSmrg		, ps3v->MCLK/1000.0);
7131d54945dSmrg	  ps3v->MCLK = 0;
7141d54945dSmrg	}
7151d54945dSmrg    } else
7161d54945dSmrg   	ps3v->MCLK = 0;
7171d54945dSmrg
7181d54945dSmrg    if (xf86GetOptValFreq(ps3v->Options, OPTION_REFCLK, OPTUNITS_MHZ, &real)) {
7191d54945dSmrg	ps3v->REFCLK = (int)(real * 1000.0);
7201d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_refclk set to %1.3f Mhz\n",
7211d54945dSmrg		   ps3v->REFCLK / 1000.0 );
7221d54945dSmrg    } else
7231d54945dSmrg   	ps3v->REFCLK = 0;
7241d54945dSmrg
7251d54945dSmrg    from = X_DEFAULT;
7261d54945dSmrg    ps3v->hwcursor = TRUE;
7271d54945dSmrg    if (xf86GetOptValBool(ps3v->Options, OPTION_HWCURSOR, &ps3v->hwcursor))
7281d54945dSmrg	  from = X_CONFIG;
7291d54945dSmrg    if (xf86ReturnOptValBool(ps3v->Options, OPTION_SWCURSOR, FALSE)) {
7301d54945dSmrg	  ps3v->hwcursor = FALSE;
7311d54945dSmrg	  from = X_CONFIG;
7321d54945dSmrg    }
7331d54945dSmrg    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s Cursor\n",
7341d54945dSmrg		ps3v->hwcursor ? "HW" : "SW");
7351d54945dSmrg
7361d54945dSmrg    if (xf86GetOptValBool(ps3v->Options, OPTION_SHADOW_FB,&ps3v->shadowFB))
7371d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n",
7381d54945dSmrg		   ps3v->shadowFB ? "enabled" : "disabled");
7391d54945dSmrg
7401d54945dSmrg    if ((s = xf86GetOptValString(ps3v->Options, OPTION_ROTATE))) {
7411d54945dSmrg	if(!xf86NameCmp(s, "CW")) {
7421d54945dSmrg	    /* accel is disabled below for shadowFB */
7431d54945dSmrg	    ps3v->shadowFB = TRUE;
7441d54945dSmrg	    ps3v->rotate = 1;
7451d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
7461d54945dSmrg		       "Rotating screen clockwise - acceleration disabled\n");
7471d54945dSmrg	} else if(!xf86NameCmp(s, "CCW")) {
7481d54945dSmrg	    ps3v->shadowFB = TRUE;
7491d54945dSmrg	    ps3v->rotate = -1;
7501d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
7511d54945dSmrg		       "counter clockwise - acceleration disabled\n");
7521d54945dSmrg	} else {
7531d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
7541d54945dSmrg		       "value for Option \"Rotate\"\n", s);
7551d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7561d54945dSmrg		       "Valid options are \"CW\" or \"CCW\"\n");
7571d54945dSmrg	}
7581d54945dSmrg    }
7591d54945dSmrg
7601d54945dSmrg    if (ps3v->shadowFB && !ps3v->NoAccel) {
7611d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
7621d54945dSmrg		   "HW acceleration not supported with \"shadowFB\".\n");
7631d54945dSmrg	ps3v->NoAccel = TRUE;
7641d54945dSmrg    }
7651d54945dSmrg
7661d54945dSmrg    if (ps3v->rotate && ps3v->hwcursor) {
7671d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
7681d54945dSmrg		   "HW cursor not supported with \"rotate\".\n");
7691d54945dSmrg	ps3v->hwcursor = FALSE;
7701d54945dSmrg    }
7711d54945dSmrg
7721d54945dSmrg    if (xf86IsOptionSet(ps3v->Options, OPTION_MX_CR3A_FIX))
7731d54945dSmrg      {
7741d54945dSmrg	if (xf86GetOptValBool(ps3v->Options, OPTION_MX_CR3A_FIX ,&ps3v->mx_cr3a_fix))
7751d54945dSmrg	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "%s mx_cr3a_fix.\n",
7761d54945dSmrg		     ps3v->mx_cr3a_fix ? "Enabling (default)" : "Disabling");
7771d54945dSmrg      }
7781d54945dSmrg    else
7791d54945dSmrg      {
7801d54945dSmrg	ps3v->mx_cr3a_fix = TRUE;
7811d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "mx_cr3a_fix.\n");
7821d54945dSmrg      }
7831d54945dSmrg
7841d54945dSmrg    /* Find the PCI slot for this screen */
7851d54945dSmrg    /*
7861d54945dSmrg     * XXX Ignoring the Type list for now.  It might be needed when
7871d54945dSmrg     * multiple cards are supported.
7881d54945dSmrg     */
7891d54945dSmrg    if (pScrn->numEntities > 1) {
7901d54945dSmrg	S3VFreeRec(pScrn);
7911d54945dSmrg	return FALSE;
7921d54945dSmrg    }
7931d54945dSmrg
7941d54945dSmrg    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
7951d54945dSmrg
796ec713c28Smrg#ifndef XSERVER_LIBPCIACCESS
7971d54945dSmrg    if (pEnt->resources) {
7985788ca14Smrg	free(pEnt);
7991d54945dSmrg	S3VFreeRec(pScrn);
8001d54945dSmrg	return FALSE;
8011d54945dSmrg    }
802ec713c28Smrg#endif
8031d54945dSmrg
8041d54945dSmrg#if USE_INT10
8051d54945dSmrg    if (xf86LoadSubModule(pScrn, "int10")) {
8061d54945dSmrg 	xf86Int10InfoPtr pInt;
8071d54945dSmrg#if 1
8081d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
8091d54945dSmrg	pInt = xf86InitInt10(pEnt->index);
8101d54945dSmrg	xf86FreeInt10(pInt);
8111d54945dSmrg#endif
8121d54945dSmrg    }
8131d54945dSmrg#endif
8141d54945dSmrg    if (xf86LoadSubModule(pScrn, "vbe")) {
8151d54945dSmrg	ps3v->pVbe =  VBEInit(NULL,pEnt->index);
8161d54945dSmrg    }
8171d54945dSmrg
8181d54945dSmrg    ps3v->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
819ec713c28Smrg#ifndef XSERVER_LIBPCIACCESS
8201d54945dSmrg    xf86RegisterResources(pEnt->index,NULL,ResNone);
8211d54945dSmrg    xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr);
8221d54945dSmrg    xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr);
823ec713c28Smrg#endif
8241d54945dSmrg
8251d54945dSmrg    /*
8261d54945dSmrg     * Set the Chipset and ChipRev, allowing config file entries to
8271d54945dSmrg     * override.
8281d54945dSmrg     */
8291d54945dSmrg    if (pEnt->device->chipset && *pEnt->device->chipset) {
8301d54945dSmrg	pScrn->chipset = pEnt->device->chipset;
8311d54945dSmrg        ps3v->Chipset = xf86StringToToken(S3VChipsets, pScrn->chipset);
8321d54945dSmrg        from = X_CONFIG;
8331d54945dSmrg    } else if (pEnt->device->chipID >= 0) {
8341d54945dSmrg	ps3v->Chipset = pEnt->device->chipID;
8351d54945dSmrg	pScrn->chipset = (char *)xf86TokenToString(S3VChipsets, ps3v->Chipset);
8361d54945dSmrg	from = X_CONFIG;
8371d54945dSmrg  	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
8381d54945dSmrg		   ps3v->Chipset);
8391d54945dSmrg    } else {
8401d54945dSmrg	from = X_PROBED;
841ba85709eSmrg	ps3v->Chipset = PCI_DEV_DEVICE_ID(ps3v->PciInfo);
8421d54945dSmrg	pScrn->chipset = (char *)xf86TokenToString(S3VChipsets, ps3v->Chipset);
8431d54945dSmrg    }
8441d54945dSmrg
8451d54945dSmrg    if (pEnt->device->chipRev >= 0) {
8461d54945dSmrg	ps3v->ChipRev = pEnt->device->chipRev;
8471d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
8481d54945dSmrg		   ps3v->ChipRev);
8491d54945dSmrg    } else {
850ba85709eSmrg        ps3v->ChipRev = PCI_DEV_REVISION(ps3v->PciInfo);
8511d54945dSmrg    }
8525788ca14Smrg    free(pEnt);
8531d54945dSmrg
8541d54945dSmrg    /*
8551d54945dSmrg     * This shouldn't happen because such problems should be caught in
8561d54945dSmrg     * S3VProbe(), but check it just in case.
8571d54945dSmrg     */
8581d54945dSmrg    if (pScrn->chipset == NULL) {
8591d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
8601d54945dSmrg		   "ChipID 0x%04X is not recognised\n", ps3v->Chipset);
8611d54945dSmrg	vbeFree(ps3v->pVbe);
8621d54945dSmrg	ps3v->pVbe = NULL;
8631d54945dSmrg	return FALSE;
8641d54945dSmrg    }
8651d54945dSmrg    if (ps3v->Chipset < 0) {
8661d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
8671d54945dSmrg		   "Chipset \"%s\" is not recognised\n", pScrn->chipset);
8681d54945dSmrg	vbeFree(ps3v->pVbe);
8691d54945dSmrg	ps3v->pVbe = NULL;
8701d54945dSmrg	return FALSE;
8711d54945dSmrg    }
8721d54945dSmrg
8731d54945dSmrg    xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
8741d54945dSmrg
875ba85709eSmrg#ifndef XSERVER_LIBPCIACCESS
8761d54945dSmrg    ps3v->PciTag = pciTag(ps3v->PciInfo->bus, ps3v->PciInfo->device,
8771d54945dSmrg			  ps3v->PciInfo->func);
878ba85709eSmrg#endif
8791d54945dSmrg
8801d54945dSmrg    /* Handle XVideo after we know chipset, so we can give an */
8811d54945dSmrg    /* intelligent comment about support */
8821d54945dSmrg    if (xf86IsOptionSet(ps3v->Options, OPTION_XVIDEO))
8831d54945dSmrg      {
8841d54945dSmrg	if(S3VQueryXvCapable(pScrn))
8851d54945dSmrg	  {
8861d54945dSmrg	    if (xf86GetOptValBool(ps3v->Options, OPTION_XVIDEO ,&ps3v->XVideo))
8871d54945dSmrg	      xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "%s XVideo.\n",
8881d54945dSmrg			 ps3v->XVideo ? "Enabling (default)" : "Disabling");
8891d54945dSmrg	  }
8901d54945dSmrg	else
8911d54945dSmrg	  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "XVideo not supported.\n");
8921d54945dSmrg      }
8931d54945dSmrg    else
8941d54945dSmrg      {
8951d54945dSmrg	ps3v->XVideo = S3VQueryXvCapable(pScrn);
8961d54945dSmrg	if(ps3v->XVideo)
8971d54945dSmrg	  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "XVideo supported.\n");
8981d54945dSmrg	else
8991d54945dSmrg	  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "XVideo not supported.\n");
9001d54945dSmrg      }
9011d54945dSmrg
9021d54945dSmrg
9031d54945dSmrg  S3VMapMem(pScrn);
9041d54945dSmrg  hwp = VGAHWPTR(pScrn);
9051d54945dSmrg  vgaIOBase = hwp->IOBase;
9061d54945dSmrg  vgaCRIndex = vgaIOBase + 4;
9071d54945dSmrg  vgaCRReg = vgaIOBase + 5;
9081d54945dSmrg
9091d54945dSmrg    xf86ErrorFVerb(VERBLEV,
9101d54945dSmrg	"	S3VPreInit vgaCRIndex=%x, vgaIOBase=%x, MMIOBase=%p\n",
9111d54945dSmrg	vgaCRIndex, vgaIOBase, hwp->MMIOBase );
9121d54945dSmrg
9131d54945dSmrg
9141d54945dSmrg#if 0	/* Not needed in 4.0 flavors */
9151d54945dSmrg   /* Unlock sys regs */
9161d54945dSmrg   VGAOUT8(vgaCRIndex, 0x38);
9171d54945dSmrg   VGAOUT8(vgaCRReg, 0x48);
9181d54945dSmrg#endif
9191d54945dSmrg
9201d54945dSmrg   /* Next go on to detect amount of installed ram */
9211d54945dSmrg
9221d54945dSmrg   VGAOUT8(vgaCRIndex, 0x36);           /* for register CR36 (CONFG_REG1),*/
9231d54945dSmrg   config1 = VGAIN8(vgaCRReg);          /* get amount of vram installed   */
9241d54945dSmrg
9251d54945dSmrg   VGAOUT8(vgaCRIndex, 0x37);           /* for register CR37 (CONFG_REG2),*/
9261d54945dSmrg   config2 = VGAIN8(vgaCRReg);          /* get amount of off-screen ram   */
9271d54945dSmrg
9281d54945dSmrg   if (xf86LoadSubModule(pScrn, "ddc")) {
9291d54945dSmrg       xf86MonPtr pMon = NULL;
9301d54945dSmrg
9311d54945dSmrg       if ((ps3v->pVbe)
9321d54945dSmrg	   && ((pMon = xf86PrintEDID(vbeDoEDID(ps3v->pVbe, NULL))) != NULL))
9331d54945dSmrg	   xf86SetDDCproperties(pScrn,pMon);
9345788ca14Smrg       else if (!S3Vddc1(pScrn)) {
9355788ca14Smrg	   S3Vddc2(pScrn);
9361d54945dSmrg       }
9371d54945dSmrg   }
9381d54945dSmrg   if (ps3v->pVbe) {
9391d54945dSmrg       vbeFree(ps3v->pVbe);
9401d54945dSmrg       ps3v->pVbe = NULL;
9411d54945dSmrg   }
9421d54945dSmrg
9431d54945dSmrg   /*
9441d54945dSmrg    * If the driver can do gamma correction, it should call xf86SetGamma()
9451d54945dSmrg    * here. (from MGA, no ViRGE gamma support yet, but needed for
9461d54945dSmrg    * xf86HandleColormaps support.)
9471d54945dSmrg    */
9481d54945dSmrg   {
9491d54945dSmrg       Gamma zeros = {0.0, 0.0, 0.0};
9501d54945dSmrg
9511d54945dSmrg       if (!xf86SetGamma(pScrn, zeros)) {
9521d54945dSmrg	   return FALSE;
9531d54945dSmrg       }
9541d54945dSmrg   }
9551d54945dSmrg
9561d54945dSmrg   /* And compute the amount of video memory and offscreen memory */
9571d54945dSmrg   ps3v->MemOffScreen = 0;
9581d54945dSmrg
9591d54945dSmrg   if (!pScrn->videoRam) {
9601d54945dSmrg      if (ps3v->Chipset == S3_ViRGE_VX) {
9611d54945dSmrg	  switch((config2 & 0x60) >> 5) {
9621d54945dSmrg         case 1:
9631d54945dSmrg            ps3v->MemOffScreen = 4 * 1024;
9641d54945dSmrg            break;
9651d54945dSmrg         case 2:
9661d54945dSmrg            ps3v->MemOffScreen = 2 * 1024;
9671d54945dSmrg            break;
9681d54945dSmrg         }
9691d54945dSmrg         switch ((config1 & 0x60) >> 5) {
9701d54945dSmrg         case 0:
9711d54945dSmrg            ps3v->videoRamKbytes = 2 * 1024;
9721d54945dSmrg            break;
9731d54945dSmrg         case 1:
9741d54945dSmrg            ps3v->videoRamKbytes = 4 * 1024;
9751d54945dSmrg            break;
9761d54945dSmrg         case 2:
9771d54945dSmrg            ps3v->videoRamKbytes = 6 * 1024;
9781d54945dSmrg            break;
9791d54945dSmrg         case 3:
9801d54945dSmrg            ps3v->videoRamKbytes = 8 * 1024;
9811d54945dSmrg            break;
9821d54945dSmrg         }
9831d54945dSmrg         ps3v->videoRamKbytes -= ps3v->MemOffScreen;
9841d54945dSmrg      }
9851d54945dSmrg      else if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset)) {
9861d54945dSmrg         switch((config1 & 0xE0) >> 5) {
9871d54945dSmrg         case 0:  /* 8MB -- only 4MB usable for display/cursor */
9881d54945dSmrg            ps3v->videoRamKbytes = 4 * 1024;
9891d54945dSmrg            ps3v->MemOffScreen   = 4 * 1024;
9901d54945dSmrg            break;
9911d54945dSmrg         case 1:    /* 32 bit interface -- yuck */
9921d54945dSmrg	   xf86ErrorFVerb(VERBLEV,
9931d54945dSmrg			  "	found 32 bit interface for video memory -- yuck:(\n");
9941d54945dSmrg         case 2:
9951d54945dSmrg            ps3v->videoRamKbytes = 4 * 1024;
9961d54945dSmrg            break;
9971d54945dSmrg         case 6:
9981d54945dSmrg            ps3v->videoRamKbytes = 2 * 1024;
9991d54945dSmrg            break;
10001d54945dSmrg         }
10011d54945dSmrg      }
10021d54945dSmrg      else if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
10031d54945dSmrg        switch((config1 & 0xE0) >> 5) {
10041d54945dSmrg        case 0:
10051d54945dSmrg        case 2:
10061d54945dSmrg           ps3v->videoRamKbytes = 4 * 1024;
10071d54945dSmrg           break;
10081d54945dSmrg        case 4:
10091d54945dSmrg           ps3v->videoRamKbytes = 2 * 1024;
10101d54945dSmrg           break;
10111d54945dSmrg        }
10121d54945dSmrg      }
10131d54945dSmrg      else if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
10141d54945dSmrg	  switch((config1 & 0xC0) >> 6) {
10151d54945dSmrg	  case 1:
10161d54945dSmrg            ps3v->videoRamKbytes = 4 * 1024;
10171d54945dSmrg            break;
10181d54945dSmrg         case 3:
10191d54945dSmrg            ps3v->videoRamKbytes = 2 * 1024;
10201d54945dSmrg            break;
10211d54945dSmrg         }
10221d54945dSmrg      }
10231d54945dSmrg      else {
10241d54945dSmrg         switch((config1 & 0xE0) >> 5) {
10251d54945dSmrg         case 0:
10261d54945dSmrg            ps3v->videoRamKbytes = 4 * 1024;
10271d54945dSmrg            break;
10281d54945dSmrg         case 4:
10291d54945dSmrg            ps3v->videoRamKbytes = 2 * 1024;
10301d54945dSmrg            break;
10311d54945dSmrg         case 6:
10321d54945dSmrg            ps3v->videoRamKbytes = 1 * 1024;
10331d54945dSmrg            break;
10341d54945dSmrg         }
10351d54945dSmrg      }
10361d54945dSmrg      					/* And save a byte value also */
10371d54945dSmrg      ps3v->videoRambytes = ps3v->videoRamKbytes * 1024;
10381d54945dSmrg      				       	/* Make sure the screen also */
10391d54945dSmrg					/* has correct videoRam setting */
10401d54945dSmrg      pScrn->videoRam = ps3v->videoRamKbytes;
10411d54945dSmrg
10421d54945dSmrg      if (ps3v->MemOffScreen)
10431d54945dSmrg	 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
10441d54945dSmrg	    	"videoram:  %dk (plus %dk off-screen)\n",
10451d54945dSmrg                ps3v->videoRamKbytes, ps3v->MemOffScreen);
10461d54945dSmrg      else
10471d54945dSmrg	 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "videoram:  %dk\n",
10481d54945dSmrg                ps3v->videoRamKbytes);
10491d54945dSmrg   } else {
10501d54945dSmrg   					/* Note: if ram is not probed then */
10511d54945dSmrg					/* ps3v->videoRamKbytes will not be init'd */
10521d54945dSmrg					/* should we? can do it here... */
10531d54945dSmrg
10541d54945dSmrg
10551d54945dSmrg      xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "videoram:  %dk\n",
10561d54945dSmrg              	ps3v->videoRamKbytes);
10571d54945dSmrg   }
10581d54945dSmrg
10591d54945dSmrg   /* reset S3 graphics engine to avoid memory corruption */
10601d54945dSmrg   if (ps3v->Chipset != S3_ViRGE_VX) {
10611d54945dSmrg      VGAOUT8(vgaCRIndex, 0x66);
10621d54945dSmrg      cr66 = VGAIN8(vgaCRReg);
10631d54945dSmrg      VGAOUT8(vgaCRReg, cr66 | 0x02);
10641d54945dSmrg      usleep(10000);  /* wait a little bit... */
10651d54945dSmrg   }
10661d54945dSmrg
10671d54945dSmrg   /*
10681d54945dSmrg    * There was a lot of plainly wrong code here. pScrn->clock is just a list
10691d54945dSmrg    * of supported _dotclocks_ used when you don't have a programmable clock.
10701d54945dSmrg    *
10711d54945dSmrg    * S3V and Savage seem to think that this is the max ramdac speed. This
10721d54945dSmrg    * driver just ignores the whole mess done before and sets
10731d54945dSmrg    * clockRange->maxClock differently slightly later.
10741d54945dSmrg    *
10751d54945dSmrg    * In order to not ditch information, here is a table of what the dacspeeds
10761d54945dSmrg    * "were" before the cleanup.
10771d54945dSmrg    *
10781d54945dSmrg    * Chipset              ### >= 24bpp ### lower
10791d54945dSmrg    *
10801d54945dSmrg    *  S3_ViRGE_VX               135000     220000
10811d54945dSmrg    *  S3_TRIO_3D_2X_SERIES      135000     230000
10821d54945dSmrg    *  S3_ViRGE_DXGX             135000     170000
10831d54945dSmrg    *  S3_ViRGE_GX2_SERIES       135000     170000
10841d54945dSmrg    *  S3_ViRGE_MX_SERIES        100000     135000
10851d54945dSmrg    *
10861d54945dSmrg    * Others devices get:
10871d54945dSmrg    *      > 24bpp:  57000
10881d54945dSmrg    *      = 24bpp:  95000
10891d54945dSmrg    *      < 24bpp: 135000
10901d54945dSmrg    *
10911d54945dSmrg    * Special case is the MELCO BIOS:
10921d54945dSmrg    *      > 24bpp:  83500
10931d54945dSmrg    *      = 24bpp: 111500
10941d54945dSmrg    *      >  8bpp: 162500
10951d54945dSmrg    *      <= 8bpp: 191500
10961d54945dSmrg    */
10971d54945dSmrg
1098ba85709eSmrg   if (find_bios_string(ps3v, BIOS_BASE, "S3 86C325",
10991d54945dSmrg			"MELCO WGP-VG VIDEO BIOS") != NULL) {
11001d54945dSmrg      if (xf86GetVerbosity())
11011d54945dSmrg	 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MELCO BIOS found\n");
11021d54945dSmrg      if (ps3v->MCLK <= 0)
11031d54945dSmrg          ps3v->MCLK = 74000;
11041d54945dSmrg   }
11051d54945dSmrg
11061d54945dSmrg   if (ps3v->Chipset != S3_ViRGE_VX) {
11071d54945dSmrg      VGAOUT8(vgaCRIndex, 0x66);
11081d54945dSmrg      VGAOUT8(vgaCRReg, cr66 & ~0x02);  /* clear reset flag */
11091d54945dSmrg      usleep(10000);  /* wait a little bit... */
11101d54945dSmrg   }
11111d54945dSmrg
11121d54945dSmrg   /* Detect current MCLK and print it for user */
11131d54945dSmrg   VGAOUT8(0x3c4, 0x08);
11141d54945dSmrg   VGAOUT8(0x3c5, 0x06);
11151d54945dSmrg   VGAOUT8(0x3c4, 0x10);
11161d54945dSmrg   n = VGAIN8(0x3c5);
11171d54945dSmrg   VGAOUT8(0x3c4, 0x11);
11181d54945dSmrg   m = VGAIN8(0x3c5);
11191d54945dSmrg   m &= 0x7f;
11201d54945dSmrg   n1 = n & 0x1f;
11211d54945dSmrg   n2 = (n>>5) & 0x03;
11221d54945dSmrg   mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
11231d54945dSmrg   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
11241d54945dSmrg      MessageType is_probed = X_PROBED;
11251d54945dSmrg      /*
11261d54945dSmrg       * try to figure out which reference clock is used:
11271d54945dSmrg       * Toshiba Tecra 5x0/7x0 seems to use 28.636 MHz
11281d54945dSmrg       * Compaq Armada 7x00 uses 14.318 MHz
11291d54945dSmrg       */
1130ba85709eSmrg      if (find_bios_string(ps3v, BIOS_BASE, "COMPAQ M5 BIOS", NULL) != NULL) {
11311d54945dSmrg	 if (xf86GetVerbosity())
11321d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "COMPAQ M5 BIOS found\n");
11331d54945dSmrg	 /* ps3v->refclk_fact = 1.0; */
11341d54945dSmrg      }
1135ba85709eSmrg      else if (find_bios_string(ps3v, BIOS_BASE, "TOSHIBA Video BIOS", NULL) != NULL) {
11361d54945dSmrg	 if (xf86GetVerbosity())
11371d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "TOSHIBA Video BIOS found\n");
11381d54945dSmrg	 /* ps3v->refclk_fact = 2.0; */
11391d54945dSmrg      }
11401d54945dSmrg      /* else */ {  /* always use guessed value... */
11411d54945dSmrg	 if (mclk > 60000)
11421d54945dSmrg	    ps3v->refclk_fact = 1.0;
11431d54945dSmrg	 else
11441d54945dSmrg	    ps3v->refclk_fact = 2.0;  /* don't know why ??? */
11451d54945dSmrg      }
11461d54945dSmrg      if (ps3v->REFCLK != 0) {
11471d54945dSmrg	 ps3v->refclk_fact = ps3v->REFCLK / 14318.0;
11481d54945dSmrg	 is_probed = X_CONFIG;
11491d54945dSmrg      }
11501d54945dSmrg      else
11511d54945dSmrg	 ps3v->REFCLK = (int)(14318.18 * ps3v->refclk_fact);
11521d54945dSmrg
11531d54945dSmrg      mclk = (int)(mclk * ps3v->refclk_fact);
11541d54945dSmrg      xf86DrvMsg(pScrn->scrnIndex, is_probed, "assuming RefCLK value of %1.3f MHz\n",
11551d54945dSmrg		 ps3v->REFCLK / 1000.0);
11561d54945dSmrg   }
11571d54945dSmrg   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of %1.3f MHz\n",
11581d54945dSmrg	     mclk / 1000.0);
11591d54945dSmrg
11601d54945dSmrg   if (S3_ViRGE_MX_SERIES(ps3v->Chipset) && xf86GetVerbosity()) {
11611d54945dSmrg       int lcdclk, h_lcd, v_lcd;
11621d54945dSmrg       if (ps3v->LCDClk) {
11631d54945dSmrg	  lcdclk = ps3v->LCDClk;
11641d54945dSmrg       } else {
11651d54945dSmrg	  unsigned char sr12, sr13, sr29;
11661d54945dSmrg          VGAOUT8(0x3c4, 0x12);
11671d54945dSmrg          sr12 = VGAIN8(0x3c5);
11681d54945dSmrg          VGAOUT8(0x3c4, 0x13);
11691d54945dSmrg          sr13 = VGAIN8(0x3c5) & 0x7f;
11701d54945dSmrg          VGAOUT8(0x3c4, 0x29);
11711d54945dSmrg          sr29 = VGAIN8(0x3c5);
11721d54945dSmrg    	  n1 = sr12 & 0x1f;
11731d54945dSmrg    	  n2 = ((sr12>>6) & 0x03) | ((sr29 & 0x01) << 2);
11741d54945dSmrg          lcdclk = ((int)(ps3v->refclk_fact * 1431818 * (sr13+2)) / (n1+2) / (1 << n2) + 50) / 100;
11751d54945dSmrg       }
11761d54945dSmrg       VGAOUT8(0x3c4, 0x61);
11771d54945dSmrg       h_lcd = VGAIN8(0x3c5);
11781d54945dSmrg       VGAOUT8(0x3c4, 0x66);
11791d54945dSmrg       h_lcd |= ((VGAIN8(0x3c5) & 0x02) << 7);
11801d54945dSmrg       h_lcd = (h_lcd+1) * 8;
11811d54945dSmrg       VGAOUT8(0x3c4, 0x69);
11821d54945dSmrg       v_lcd = VGAIN8(0x3c5);
11831d54945dSmrg       VGAOUT8(0x3c4, 0x6e);
11841d54945dSmrg       v_lcd |= ((VGAIN8(0x3c5) & 0x70) << 4);
11851d54945dSmrg       v_lcd++;
11861d54945dSmrg       xf86DrvMsg(pScrn->scrnIndex
11871d54945dSmrg	      , ps3v->LCDClk ? X_CONFIG : X_PROBED
11881d54945dSmrg       	      , "LCD size %dx%d, clock %1.3f MHz\n"
11891d54945dSmrg	      , h_lcd, v_lcd
11901d54945dSmrg	      , lcdclk / 1000.0);
11911d54945dSmrg   }
11921d54945dSmrg
11931d54945dSmrg   S3VDisableMmio(pScrn);
11941d54945dSmrg   S3VUnmapMem(pScrn);
11951d54945dSmrg
11961d54945dSmrg   /* And finally set various possible option flags */
11971d54945dSmrg
11981d54945dSmrg   ps3v->bankedMono = FALSE;
11991d54945dSmrg
12001d54945dSmrg
12011d54945dSmrg#if 0
12021d54945dSmrg   vga256InfoRec.directMode = XF86DGADirectPresent;
12031d54945dSmrg#endif
12041d54945dSmrg
12051d54945dSmrg    				/* Lower depths default to config file */
12061d54945dSmrg  pScrn->virtualX = pScrn->display->virtualX;
12071d54945dSmrg				/* Adjust the virtualX to meet ViRGE hardware */
12081d54945dSmrg				/* limits for depth 24, bpp 24 & 32.  This is */
12091d54945dSmrg				/* mostly for 32 bpp as 1024x768 is one pixel */
12101d54945dSmrg				/* larger than supported. */
12111d54945dSmrg  if (pScrn->depth == 24)
12121d54945dSmrg      if ( ((pScrn->bitsPerPixel/8) * pScrn->display->virtualX) > 4095 ) {
12131d54945dSmrg        pScrn->virtualX = 4095 / (pScrn->bitsPerPixel / 8);
12141d54945dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
12151d54945dSmrg	   "Virtual width adjusted, max for this depth & bpp is %d.\n",
12161d54945dSmrg	   pScrn->virtualX );
12171d54945dSmrg      }
12181d54945dSmrg
12191d54945dSmrg    /*
12201d54945dSmrg     * Setup the ClockRanges, which describe what clock ranges are available,
12211d54945dSmrg     * and what sort of modes they can be used for.
12221d54945dSmrg     */
12231d54945dSmrg    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
12241d54945dSmrg    clockRanges->next = NULL;
12251d54945dSmrg    clockRanges->minClock = 10000;
12261d54945dSmrg    if (ps3v->Chipset == S3_ViRGE_VX )
12271d54945dSmrg        clockRanges->maxClock = 440000;
12281d54945dSmrg    else
12291d54945dSmrg        clockRanges->maxClock = 270000;
12301d54945dSmrg    clockRanges->clockIndex = -1;		/* programmable */
12311d54945dSmrg    clockRanges->interlaceAllowed = TRUE;	/* yes, S3V SVGA 3.3.2 */
12321d54945dSmrg    clockRanges->doubleScanAllowed = TRUE;
12331d54945dSmrg
12341d54945dSmrg  					/* Screen pointer 		*/
12351d54945dSmrg    i = xf86ValidateModes(pScrn,
12361d54945dSmrg  					/* Available monitor modes 	*/
12371d54945dSmrg					/* (DisplayModePtr availModes)  */
12381d54945dSmrg		pScrn->monitor->Modes,
12391d54945dSmrg					/* req mode names for screen 	*/
12401d54945dSmrg					/* (char **modesNames)  	*/
12411d54945dSmrg		pScrn->display->modes,
12421d54945dSmrg					/* list of clock ranges allowed */
12431d54945dSmrg					/* (ClockRangePtr clockRanges) 	*/
12441d54945dSmrg		clockRanges,
12451d54945dSmrg					/* list of driver line pitches, */
12461d54945dSmrg					/* supply or NULL and use min/	*/
12471d54945dSmrg					/* max below			*/
12481d54945dSmrg					/* (int *linePitches)		*/
12491d54945dSmrg		NULL,
12501d54945dSmrg					/* min lin pitch (width)	*/
12511d54945dSmrg					/* (int minPitch)		*/
12521d54945dSmrg		256,
12531d54945dSmrg					/* max line pitch (width)	*/
12541d54945dSmrg					/* (int maxPitch)		*/
12551d54945dSmrg		2048,
12561d54945dSmrg					/* bits of granularity for line	*/
12571d54945dSmrg					/* pitch (width) above, reguired*/
12581d54945dSmrg					/* (int pitchInc)		*/
12591d54945dSmrg		pScrn->bitsPerPixel,
12601d54945dSmrg					/* min virt height, 0 no limit	*/
12611d54945dSmrg					/* (int minHeight)		*/
12621d54945dSmrg		128,
12631d54945dSmrg					/* max virt height, 0 no limit	*/
12641d54945dSmrg					/* (int maxHeight)		*/
12651d54945dSmrg		2048,
12661d54945dSmrg					/* force virtX, 0 for auto 	*/
12671d54945dSmrg					/* (int VirtualX) 		*/
12681d54945dSmrg					/* value is adjusted above for  */
12691d54945dSmrg					/* hardware limits */
12701d54945dSmrg		pScrn->virtualX,
12711d54945dSmrg					/* force virtY, 0 for auto	*/
12721d54945dSmrg					/* (int VirtualY)		*/
12731d54945dSmrg		pScrn->display->virtualY,
12741d54945dSmrg					/* size (bytes) of aper used to	*/
12751d54945dSmrg					/* access video memory		*/
12761d54945dSmrg					/* (unsigned long apertureSize)	*/
12771d54945dSmrg		ps3v->videoRambytes,
12781d54945dSmrg					/* how to pick mode */
12791d54945dSmrg					/* (LookupModeFlags strategy)	*/
12801d54945dSmrg		LOOKUP_BEST_REFRESH);
12811d54945dSmrg
12821d54945dSmrg    if (i == -1) {
12831d54945dSmrg	S3VFreeRec(pScrn);
12841d54945dSmrg	return FALSE;
12851d54945dSmrg    }
12861d54945dSmrg    /* Prune the modes marked as invalid */
12871d54945dSmrg    xf86PruneDriverModes(pScrn);
12881d54945dSmrg
12891d54945dSmrg    if (i == 0 || pScrn->modes == NULL) {
12901d54945dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
12911d54945dSmrg	S3VFreeRec(pScrn);
12921d54945dSmrg	return FALSE;
12931d54945dSmrg    }
12941d54945dSmrg
12951d54945dSmrg    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
12961d54945dSmrg    /*xf86SetCrtcForModes(pScrn, 0);*/
12971d54945dSmrg
12981d54945dSmrg    /* Set the current mode to the first in the list */
12991d54945dSmrg    pScrn->currentMode = pScrn->modes;
13001d54945dSmrg
13011d54945dSmrg    /* Print the list of modes being used */
13021d54945dSmrg    xf86PrintModes(pScrn);
13031d54945dSmrg
13041d54945dSmrg    /* Set display resolution */
13051d54945dSmrg    xf86SetDpi(pScrn, 0, 0);
13061d54945dSmrg
13071d54945dSmrg    /* Load bpp-specific modules */
1308ba85709eSmrg    if( xf86LoadSubModule(pScrn, "fb") == NULL )
1309ba85709eSmrg    {
1310ba85709eSmrg	S3VFreeRec(pScrn);
1311ba85709eSmrg	return FALSE;
1312ba85709eSmrg    }
13131d54945dSmrg
13141d54945dSmrg    /* Load XAA if needed */
13151d54945dSmrg    if (!ps3v->NoAccel || ps3v->hwcursor ) {
13161d54945dSmrg	if (!xf86LoadSubModule(pScrn, "xaa")) {
13175788ca14Smrg	    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
13185788ca14Smrg			   "Falling back to shadowfb\n");
13195788ca14Smrg	    ps3v->NoAccel = 1;
13205788ca14Smrg	    ps3v->hwcursor = 0;
13215788ca14Smrg	    ps3v->shadowFB = 1;
13221d54945dSmrg	}
13231d54945dSmrg    }
13241d54945dSmrg
13251d54945dSmrg    /* Load ramdac if needed */
13261d54945dSmrg    if (ps3v->hwcursor) {
13271d54945dSmrg	if (!xf86LoadSubModule(pScrn, "ramdac")) {
13281d54945dSmrg	    S3VFreeRec(pScrn);
13291d54945dSmrg	    return FALSE;
13301d54945dSmrg	}
13311d54945dSmrg    }
13321d54945dSmrg
13331d54945dSmrg    if (ps3v->shadowFB) {
13341d54945dSmrg	if (!xf86LoadSubModule(pScrn, "shadowfb")) {
13351d54945dSmrg	    S3VFreeRec(pScrn);
13361d54945dSmrg	    return FALSE;
13371d54945dSmrg	}
13381d54945dSmrg    }
13391d54945dSmrg
13401d54945dSmrg    /* Setup WAITFIFO() for accel and ModeInit() */
13411d54945dSmrg    /* Needs to be done prior to first ModeInit call */
13421d54945dSmrg    /* and any accel activity. */
13431d54945dSmrg    switch(ps3v->Chipset)
13441d54945dSmrg      {
13451d54945dSmrg	/* GX2_SERIES chips, GX2 & TRIO_3D_2X */
13461d54945dSmrg      case S3_ViRGE_GX2:
13471d54945dSmrg      case S3_TRIO_3D_2X:
13481d54945dSmrg	ps3v->pWaitFifo = S3VWaitFifoGX2;
13491d54945dSmrg	ps3v->pWaitCmd = S3VWaitCmdGX2;
13501d54945dSmrg	break;
13511d54945dSmrg      case S3_ViRGE:
13521d54945dSmrg      case S3_ViRGE_VX:
13531d54945dSmrg      default:
13541d54945dSmrg	ps3v->pWaitFifo = S3VWaitFifoMain;
13551d54945dSmrg	/* Do nothing... */
13561d54945dSmrg	ps3v->pWaitCmd = S3VWaitDummy;
13571d54945dSmrg	break;
13581d54945dSmrg      }
13591d54945dSmrg
13601d54945dSmrg    return TRUE;
13611d54945dSmrg}
13621d54945dSmrg
13631d54945dSmrg
13641d54945dSmrg/*
13651d54945dSmrg * This is called when VT switching back to the X server.  Its job is
13661d54945dSmrg * to reinitialise the video mode.
13671d54945dSmrg *
13681d54945dSmrg * We may wish to unmap video/MMIO memory too.
13691d54945dSmrg */
13701d54945dSmrg
13711d54945dSmrg
13721d54945dSmrg/* Mandatory */
13731d54945dSmrgstatic Bool
13745788ca14SmrgS3VEnterVT(VT_FUNC_ARGS_DECL)
13751d54945dSmrg{
13765788ca14Smrg    SCRN_INFO_PTR(arg);
13771d54945dSmrg/*      ScreenPtr pScreen = xf86Screens[scrnIndex]->pScreen; */
13781d54945dSmrg    /*vgaHWPtr hwp = VGAHWPTR(pScrn);*/
13791d54945dSmrg
13801d54945dSmrg    PVERB5("	S3VEnterVT\n");
13811d54945dSmrg    /*vgaHWUnlockMMIO(hwp);*/
13821d54945dSmrg    				/* Enable MMIO and map memory */
13831d54945dSmrg#ifdef unmap_always
13841d54945dSmrg    S3VMapMem(pScrn);
13851d54945dSmrg#endif
13861d54945dSmrg    S3VEnableMmio(pScrn);
13871d54945dSmrg
13881d54945dSmrg    S3VSave(pScrn);
13891d54945dSmrg    return S3VModeInit(pScrn, pScrn->currentMode);
13901d54945dSmrg}
13911d54945dSmrg
13921d54945dSmrg
13931d54945dSmrg/*
13941d54945dSmrg * This is called when VT switching away from the X server.  Its job is
13951d54945dSmrg * to restore the previous (text) mode.
13961d54945dSmrg *
13971d54945dSmrg * We may wish to remap video/MMIO memory too.
13981d54945dSmrg *
13991d54945dSmrg */
14001d54945dSmrg
14011d54945dSmrg/* Mandatory */
14021d54945dSmrgstatic void
14035788ca14SmrgS3VLeaveVT(VT_FUNC_ARGS_DECL)
14041d54945dSmrg{
14055788ca14Smrg    SCRN_INFO_PTR(arg);
14061d54945dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
14071d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
14081d54945dSmrg    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
14091d54945dSmrg    S3VRegPtr S3VSavePtr = &ps3v->SavedReg;
14101d54945dSmrg
14111d54945dSmrg    PVERB5("	S3VLeaveVT\n");
14121d54945dSmrg    					/* Like S3VRestore, but uses passed */
14131d54945dSmrg					/* mode registers.		    */
14141d54945dSmrg    S3VWriteMode(pScrn, vgaSavePtr, S3VSavePtr);
14151d54945dSmrg    					/* Restore standard register access */
14161d54945dSmrg					/* and unmap memory.		    */
14171d54945dSmrg    S3VDisableMmio(pScrn);
14181d54945dSmrg#ifdef unmap_always
14191d54945dSmrg    S3VUnmapMem(pScrn);
14201d54945dSmrg#endif
14211d54945dSmrg    /*vgaHWLockMMIO(hwp);*/
14221d54945dSmrg
14231d54945dSmrg}
14241d54945dSmrg
14251d54945dSmrg
14261d54945dSmrg/*
14271d54945dSmrg * This function performs the inverse of the restore function: It saves all
14281d54945dSmrg * the standard and extended registers that we are going to modify to set
14291d54945dSmrg * up a video mode. Again, we also save the STREAMS context if it is needed.
14301d54945dSmrg *
14311d54945dSmrg * prototype
14321d54945dSmrg *   void ChipSave(ScrnInfoPtr pScrn)
14331d54945dSmrg *
14341d54945dSmrg */
14351d54945dSmrg
14361d54945dSmrgstatic void
14371d54945dSmrgS3VSave (ScrnInfoPtr pScrn)
14381d54945dSmrg{
14391d54945dSmrg  unsigned char cr3a, cr66;
14401d54945dSmrg  vgaHWPtr hwp = VGAHWPTR(pScrn);
14411d54945dSmrg  vgaRegPtr vgaSavePtr = &hwp->SavedReg;
14421d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
14431d54945dSmrg  S3VRegPtr save = &ps3v->SavedReg;
14441d54945dSmrg  int vgaCRIndex, vgaCRReg, vgaIOBase;
14451d54945dSmrg  vgaIOBase = hwp->IOBase;
14461d54945dSmrg  vgaCRIndex = 0;
14471d54945dSmrg
14481d54945dSmrg  vgaCRReg = 0;
14491d54945dSmrg
14501d54945dSmrg  vgaCRReg = vgaIOBase + 5;
14511d54945dSmrg  vgaCRIndex = vgaIOBase + 4;
14521d54945dSmrg
14531d54945dSmrg    PVERB5("	S3VSave\n");
14541d54945dSmrg
14551d54945dSmrg   /*
14561d54945dSmrg    * This function will handle creating the data structure and filling
14571d54945dSmrg    * in the generic VGA portion.
14581d54945dSmrg    */
14591d54945dSmrg
14601d54945dSmrg   VGAOUT8(vgaCRIndex, 0x66);
14611d54945dSmrg   cr66 = VGAIN8(vgaCRReg);
14621d54945dSmrg   VGAOUT8(vgaCRReg, cr66 | 0x80);
14631d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3a);
14641d54945dSmrg   cr3a = VGAIN8(vgaCRReg);
14651d54945dSmrg   save->CR3A = cr3a;
14661d54945dSmrg
14671d54945dSmrg   VGAOUT8(vgaCRReg, cr3a | 0x80);
14681d54945dSmrg
14691d54945dSmrg   /* VGA_SR_MODE saves mode info only, no fonts, no colormap */
14701d54945dSmrg					/* Save all for primary, anything */
14711d54945dSmrg					/* for secondary cards?, do MODE */
14721d54945dSmrg					/* for the moment. */
14731d54945dSmrg   if (xf86IsPrimaryPci(ps3v->PciInfo))
14741d54945dSmrg   	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
14751d54945dSmrg   else
14761d54945dSmrg   	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_MODE);
14771d54945dSmrg
14781d54945dSmrg   VGAOUT8(vgaCRIndex, 0x66);
14791d54945dSmrg   VGAOUT8(vgaCRReg, cr66);
14801d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3a);
14811d54945dSmrg   VGAOUT8(vgaCRReg, cr3a);
14821d54945dSmrg
14831d54945dSmrg   /* First unlock extended sequencer regs */
14841d54945dSmrg   VGAOUT8(0x3c4, 0x08);
14851d54945dSmrg   save->SR08 = VGAIN8(0x3c5);
14861d54945dSmrg   VGAOUT8(0x3c5, 0x06);
14871d54945dSmrg
14881d54945dSmrg   /* Now we save all the s3 extended regs we need */
14891d54945dSmrg   VGAOUT8(vgaCRIndex, 0x31);
14901d54945dSmrg   save->CR31 = VGAIN8(vgaCRReg);
14911d54945dSmrg   VGAOUT8(vgaCRIndex, 0x34);
14921d54945dSmrg   save->CR34 = VGAIN8(vgaCRReg);
14931d54945dSmrg   VGAOUT8(vgaCRIndex, 0x36);
14941d54945dSmrg   save->CR36 = VGAIN8(vgaCRReg);
14951d54945dSmrg
14961d54945dSmrg   /* workaround cr3a corruption */
14971d54945dSmrg   if( !(ps3v->mx_cr3a_fix))
14981d54945dSmrg     {
14991d54945dSmrg       VGAOUT8(vgaCRIndex, 0x3a);
15001d54945dSmrg       save->CR3A = VGAIN8(vgaCRReg);
15011d54945dSmrg     }
15021d54945dSmrg
15031d54945dSmrg   if (!S3_TRIO_3D_SERIES(ps3v->Chipset)) {
15041d54945dSmrg     VGAOUT8(vgaCRIndex, 0x40);
15051d54945dSmrg     save->CR40 = VGAIN8(vgaCRReg);
15061d54945dSmrg   }
15071d54945dSmrg   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
15081d54945dSmrg     VGAOUT8(vgaCRIndex, 0x41);
15091d54945dSmrg     save->CR41 = VGAIN8(vgaCRReg);
15101d54945dSmrg   }
15111d54945dSmrg   VGAOUT8(vgaCRIndex, 0x42);
15121d54945dSmrg   save->CR42 = VGAIN8(vgaCRReg);
15131d54945dSmrg   VGAOUT8(vgaCRIndex, 0x45);
15141d54945dSmrg   save->CR45 = VGAIN8(vgaCRReg);
15151d54945dSmrg   VGAOUT8(vgaCRIndex, 0x51);
15161d54945dSmrg   save->CR51 = VGAIN8(vgaCRReg);
15171d54945dSmrg   VGAOUT8(vgaCRIndex, 0x53);
15181d54945dSmrg   save->CR53 = VGAIN8(vgaCRReg);
15191d54945dSmrg   VGAOUT8(vgaCRIndex, 0x54);
15201d54945dSmrg   save->CR54 = VGAIN8(vgaCRReg);
15211d54945dSmrg   VGAOUT8(vgaCRIndex, 0x55);
15221d54945dSmrg   save->CR55 = VGAIN8(vgaCRReg);
15231d54945dSmrg   VGAOUT8(vgaCRIndex, 0x58);
15241d54945dSmrg   save->CR58 = VGAIN8(vgaCRReg);
15251d54945dSmrg   VGAOUT8(vgaCRIndex, 0x63);
15261d54945dSmrg   save->CR63 = VGAIN8(vgaCRReg);
15271d54945dSmrg   VGAOUT8(vgaCRIndex, 0x66);
15281d54945dSmrg   save->CR66 = VGAIN8(vgaCRReg);
15291d54945dSmrg   VGAOUT8(vgaCRIndex, 0x67);
15301d54945dSmrg   save->CR67 = VGAIN8(vgaCRReg);
15311d54945dSmrg   VGAOUT8(vgaCRIndex, 0x68);
15321d54945dSmrg   save->CR68 = VGAIN8(vgaCRReg);
15331d54945dSmrg   VGAOUT8(vgaCRIndex, 0x69);
15341d54945dSmrg   save->CR69 = VGAIN8(vgaCRReg);
15351d54945dSmrg
15361d54945dSmrg   VGAOUT8(vgaCRIndex, 0x33);
15371d54945dSmrg   save->CR33 = VGAIN8(vgaCRReg);
15381d54945dSmrg   if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) || S3_ViRGE_GX2_SERIES(ps3v->Chipset)
15391d54945dSmrg       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
15401d54945dSmrg   {
15411d54945dSmrg      VGAOUT8(vgaCRIndex, 0x85);
15421d54945dSmrg      save->CR85 = VGAIN8(vgaCRReg);
15431d54945dSmrg   }
15441d54945dSmrg   if (ps3v->Chipset == S3_ViRGE_DXGX) {
15451d54945dSmrg      VGAOUT8(vgaCRIndex, 0x86);
15461d54945dSmrg      save->CR86 = VGAIN8(vgaCRReg);
15471d54945dSmrg   }
15481d54945dSmrg   if ((ps3v->Chipset == S3_ViRGE_GX2) ||
15491d54945dSmrg       S3_ViRGE_MX_SERIES(ps3v->Chipset) ) {
15501d54945dSmrg      VGAOUT8(vgaCRIndex, 0x7B);
15511d54945dSmrg      save->CR7B = VGAIN8(vgaCRReg);
15521d54945dSmrg      VGAOUT8(vgaCRIndex, 0x7D);
15531d54945dSmrg      save->CR7D = VGAIN8(vgaCRReg);
15541d54945dSmrg      VGAOUT8(vgaCRIndex, 0x87);
15551d54945dSmrg      save->CR87 = VGAIN8(vgaCRReg);
15561d54945dSmrg      VGAOUT8(vgaCRIndex, 0x92);
15571d54945dSmrg      save->CR92 = VGAIN8(vgaCRReg);
15581d54945dSmrg      VGAOUT8(vgaCRIndex, 0x93);
15591d54945dSmrg      save->CR93 = VGAIN8(vgaCRReg);
15601d54945dSmrg   }
15611d54945dSmrg   if (ps3v->Chipset == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
15621d54945dSmrg       S3_ViRGE_MX_SERIES(ps3v->Chipset) || S3_TRIO_3D_SERIES(ps3v->Chipset)) {
15631d54945dSmrg      VGAOUT8(vgaCRIndex, 0x90);
15641d54945dSmrg      save->CR90 = VGAIN8(vgaCRReg);
15651d54945dSmrg      VGAOUT8(vgaCRIndex, 0x91);
15661d54945dSmrg      save->CR91 = VGAIN8(vgaCRReg);
15671d54945dSmrg   }
15681d54945dSmrg
15691d54945dSmrg   /* Extended mode timings regs */
15701d54945dSmrg
15711d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3b);
15721d54945dSmrg   save->CR3B = VGAIN8(vgaCRReg);
15731d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3c);
15741d54945dSmrg   save->CR3C = VGAIN8(vgaCRReg);
15751d54945dSmrg   VGAOUT8(vgaCRIndex, 0x43);
15761d54945dSmrg   save->CR43 = VGAIN8(vgaCRReg);
15771d54945dSmrg   VGAOUT8(vgaCRIndex, 0x5d);
15781d54945dSmrg   save->CR5D = VGAIN8(vgaCRReg);
15791d54945dSmrg   VGAOUT8(vgaCRIndex, 0x5e);
15801d54945dSmrg   save->CR5E = VGAIN8(vgaCRReg);
15811d54945dSmrg   VGAOUT8(vgaCRIndex, 0x65);
15821d54945dSmrg   save->CR65 = VGAIN8(vgaCRReg);
15831d54945dSmrg   VGAOUT8(vgaCRIndex, 0x6d);
15841d54945dSmrg   save->CR6D = VGAIN8(vgaCRReg);
15851d54945dSmrg
15861d54945dSmrg
15871d54945dSmrg   /* Save sequencer extended regs for DCLK PLL programming */
15881d54945dSmrg
15891d54945dSmrg   VGAOUT8(0x3c4, 0x10);
15901d54945dSmrg   save->SR10 = VGAIN8(0x3c5);
15911d54945dSmrg   VGAOUT8(0x3c4, 0x11);
15921d54945dSmrg   save->SR11 = VGAIN8(0x3c5);
15931d54945dSmrg
15941d54945dSmrg   VGAOUT8(0x3c4, 0x12);
15951d54945dSmrg   save->SR12 = VGAIN8(0x3c5);
15961d54945dSmrg   VGAOUT8(0x3c4, 0x13);
15971d54945dSmrg   save->SR13 = VGAIN8(0x3c5);
15981d54945dSmrg   if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
15991d54945dSmrg     VGAOUT8(0x3c4, 0x29);
16001d54945dSmrg     save->SR29 = VGAIN8(0x3c5);
16011d54945dSmrg   }
16021d54945dSmrg        /* SR 54,55,56,57 undocumented for GX2.  Was this supposed to be CR? */
16031d54945dSmrg        /* (These used to be part of the above if() */
16041d54945dSmrg   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
16051d54945dSmrg     VGAOUT8(0x3c4, 0x54);
16061d54945dSmrg     save->SR54 = VGAIN8(0x3c5);
16071d54945dSmrg     VGAOUT8(0x3c4, 0x55);
16081d54945dSmrg     save->SR55 = VGAIN8(0x3c5);
16091d54945dSmrg     VGAOUT8(0x3c4, 0x56);
16101d54945dSmrg     save->SR56 = VGAIN8(0x3c5);
16111d54945dSmrg     VGAOUT8(0x3c4, 0x57);
16121d54945dSmrg     save->SR57 = VGAIN8(0x3c5);
16131d54945dSmrg   }
16141d54945dSmrg
16151d54945dSmrg   VGAOUT8(0x3c4, 0x15);
16161d54945dSmrg   save->SR15 = VGAIN8(0x3c5);
16171d54945dSmrg   VGAOUT8(0x3c4, 0x18);
16181d54945dSmrg   save->SR18 = VGAIN8(0x3c5);
16191d54945dSmrg   if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
16201d54945dSmrg     VGAOUT8(0x3c4, 0x0a);
16211d54945dSmrg     save->SR0A = VGAIN8(0x3c5);
16221d54945dSmrg     VGAOUT8(0x3c4, 0x0F);
16231d54945dSmrg     save->SR0F = VGAIN8(0x3c5);
16241d54945dSmrg   }
16251d54945dSmrg
16261d54945dSmrg   VGAOUT8(vgaCRIndex, 0x66);
16271d54945dSmrg   cr66 = VGAIN8(vgaCRReg);
16281d54945dSmrg   VGAOUT8(vgaCRReg, cr66 | 0x80);
16291d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3a);
16301d54945dSmrg   cr3a = VGAIN8(vgaCRReg);
16311d54945dSmrg   VGAOUT8(vgaCRReg, cr3a | 0x80);
16321d54945dSmrg
16331d54945dSmrg   /* And if streams is to be used, save that as well */
16341d54945dSmrg
16351d54945dSmrg   if(ps3v->NeedSTREAMS) {
16361d54945dSmrg      S3VSaveSTREAMS(pScrn, save->STREAMS);
16371d54945dSmrg      }
16381d54945dSmrg
16391d54945dSmrg   /* Now save Memory Interface Unit registers */
16401d54945dSmrg   if( S3_ViRGE_GX2_SERIES(ps3v->Chipset)
16411d54945dSmrg      /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
16421d54945dSmrg     {
16431d54945dSmrg     /* No MMPR regs on MX & GX2 */
16441d54945dSmrg     }
16451d54945dSmrg   else
16461d54945dSmrg     {
16471d54945dSmrg     save->MMPR0 = INREG(FIFO_CONTROL_REG);
16481d54945dSmrg     save->MMPR1 = INREG(MIU_CONTROL_REG);
16491d54945dSmrg     save->MMPR2 = INREG(STREAMS_TIMEOUT_REG);
16501d54945dSmrg     save->MMPR3 = INREG(MISC_TIMEOUT_REG);
16511d54945dSmrg     }
16521d54945dSmrg
16531d54945dSmrg   if (xf86GetVerbosity() > 1) {
16541d54945dSmrg      /* Debug */
16551d54945dSmrg     /* Which chipsets? */
16561d54945dSmrg     if (
16571d54945dSmrg	 /* virge */
16581d54945dSmrg	 ps3v->Chipset == S3_ViRGE ||
16591d54945dSmrg	 /* VX */
16601d54945dSmrg	 S3_ViRGE_VX_SERIES(ps3v->Chipset) ||
16611d54945dSmrg	 /* DX & GX */
16621d54945dSmrg	 ps3v->Chipset == S3_ViRGE_DXGX ||
16631d54945dSmrg	 /* GX2 & Trio3D_2X */
16641d54945dSmrg	 /* S3_ViRGE_GX2_SERIES(ps3v->Chipset) || */
16651d54945dSmrg	 /* Trio3D_2X */
16661d54945dSmrg	 /* S3_TRIO_3D_2X_SERIES(ps3v->Chipset) */
16671d54945dSmrg	 /* MX & MX+ */
16681d54945dSmrg	 /* S3_ViRGE_MX_SERIES(ps3v->Chipset) || */
16691d54945dSmrg	 /* MX+ only */
16701d54945dSmrg	 /* S3_ViRGE_MXP_SERIES(ps3v->Chipset) || */
16711d54945dSmrg	 /* Trio3D */
16721d54945dSmrg	 ps3v->Chipset == S3_TRIO_3D
16731d54945dSmrg         )
16741d54945dSmrg       {
16751d54945dSmrg
16761d54945dSmrg      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
16771d54945dSmrg         "MMPR regs: %08lx %08lx %08lx %08lx\n",
16781d54945dSmrg	     (unsigned long)INREG(FIFO_CONTROL_REG),
16791d54945dSmrg	     (unsigned long)INREG(MIU_CONTROL_REG),
16801d54945dSmrg	     (unsigned long)INREG(STREAMS_TIMEOUT_REG),
16811d54945dSmrg	     (unsigned long)INREG(MISC_TIMEOUT_REG));
16821d54945dSmrg       }
16831d54945dSmrg
16841d54945dSmrg      PVERB5("\n\nViRGE driver: saved current video mode. Register dump:\n\n");
16851d54945dSmrg   }
16861d54945dSmrg
16871d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3a);
16881d54945dSmrg   VGAOUT8(vgaCRReg, cr3a);
16891d54945dSmrg   VGAOUT8(vgaCRIndex, 0x66);
16901d54945dSmrg   VGAOUT8(vgaCRReg, cr66);
16911d54945dSmrg   				/* Dup the VGA & S3V state to the */
16921d54945dSmrg				/* new mode state, but only first time. */
16931d54945dSmrg   if( !ps3v->ModeStructInit ) {
16941d54945dSmrg     /* XXX Should check the return value of vgaHWCopyReg() */
16951d54945dSmrg     vgaHWCopyReg( &hwp->ModeReg, vgaSavePtr );
16961d54945dSmrg     memcpy( &ps3v->ModeReg, save, sizeof(S3VRegRec) );
16971d54945dSmrg     ps3v->ModeStructInit = TRUE;
16981d54945dSmrg   }
16991d54945dSmrg
17001d54945dSmrg   if (xf86GetVerbosity() > 1) S3VPrintRegs(pScrn);
17011d54945dSmrg
17021d54945dSmrg   return;
17031d54945dSmrg}
17041d54945dSmrg
17051d54945dSmrg
17061d54945dSmrg/* This function saves the STREAMS registers to our private structure */
17071d54945dSmrg
17081d54945dSmrgstatic void
17091d54945dSmrgS3VSaveSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams)
17101d54945dSmrg{
17111d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
17121d54945dSmrg
17131d54945dSmrg   streams[0] = INREG(PSTREAM_CONTROL_REG);
17141d54945dSmrg   streams[1] = INREG(COL_CHROMA_KEY_CONTROL_REG);
17151d54945dSmrg   streams[2] = INREG(SSTREAM_CONTROL_REG);
17161d54945dSmrg   streams[3] = INREG(CHROMA_KEY_UPPER_BOUND_REG);
17171d54945dSmrg   streams[4] = INREG(SSTREAM_STRETCH_REG);
17181d54945dSmrg   streams[5] = INREG(BLEND_CONTROL_REG);
17191d54945dSmrg   streams[6] = INREG(PSTREAM_FBADDR0_REG);
17201d54945dSmrg   streams[7] = INREG(PSTREAM_FBADDR1_REG);
17211d54945dSmrg   streams[8] = INREG(PSTREAM_STRIDE_REG);
17221d54945dSmrg   streams[9] = INREG(DOUBLE_BUFFER_REG);
17231d54945dSmrg   streams[10] = INREG(SSTREAM_FBADDR0_REG);
17241d54945dSmrg   streams[11] = INREG(SSTREAM_FBADDR1_REG);
17251d54945dSmrg   streams[12] = INREG(SSTREAM_STRIDE_REG);
17261d54945dSmrg   streams[13] = INREG(OPAQUE_OVERLAY_CONTROL_REG);
17271d54945dSmrg   streams[14] = INREG(K1_VSCALE_REG);
17281d54945dSmrg   streams[15] = INREG(K2_VSCALE_REG);
17291d54945dSmrg   streams[16] = INREG(DDA_VERT_REG);
17301d54945dSmrg   streams[17] = INREG(STREAMS_FIFO_REG);
17311d54945dSmrg   streams[18] = INREG(PSTREAM_START_REG);
17321d54945dSmrg   streams[19] = INREG(PSTREAM_WINDOW_SIZE_REG);
17331d54945dSmrg   streams[20] = INREG(SSTREAM_START_REG);
17341d54945dSmrg   streams[21] = INREG(SSTREAM_WINDOW_SIZE_REG);
17351d54945dSmrg
17361d54945dSmrg}
17371d54945dSmrg
17381d54945dSmrg
17391d54945dSmrg/*
17401d54945dSmrg * This function is used to restore a video mode. It writes out all
17411d54945dSmrg * of the standard VGA and extended S3 registers needed to setup a
17421d54945dSmrg * video mode.
17431d54945dSmrg *
17441d54945dSmrg * Note that our life is made more difficult because of the STREAMS
17451d54945dSmrg * processor which must be used for 24bpp. We need to disable STREAMS
17461d54945dSmrg * before we switch video modes, or we risk locking up the machine.
17471d54945dSmrg * We also have to follow a certain order when reenabling it.
17481d54945dSmrg */
17491d54945dSmrg/* let's try restoring in the same order as in the 3.3.2.3 driver */
17501d54945dSmrgstatic void
17511d54945dSmrgS3VWriteMode (ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr, S3VRegPtr restore)
17521d54945dSmrg{
17531d54945dSmrg  unsigned char tmp, cr3a=0, cr66, cr67;
17541d54945dSmrg
17551d54945dSmrg  vgaHWPtr hwp = VGAHWPTR(pScrn);
17561d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
17571d54945dSmrg  int vgaCRIndex, vgaCRReg, vgaIOBase;
17581d54945dSmrg  vgaIOBase = hwp->IOBase;
17591d54945dSmrg  vgaCRIndex = vgaIOBase + 4;
17601d54945dSmrg  vgaCRReg = vgaIOBase + 5;
17611d54945dSmrg
17621d54945dSmrg    PVERB5("	S3VWriteMode\n");
17631d54945dSmrg
17641d54945dSmrg  vgaHWProtect(pScrn, TRUE);
17651d54945dSmrg
17660b7217d9Smrg   /* Are we going to re-enable STREAMS in this new mode? */
17671d54945dSmrg   ps3v->STREAMSRunning = restore->CR67 & 0x0c;
17681d54945dSmrg
17691d54945dSmrg   /* First reset GE to make sure nothing is going on */
17701d54945dSmrg   if(ps3v->Chipset == S3_ViRGE_VX) {
17711d54945dSmrg      VGAOUT8(vgaCRIndex, 0x63);
17721d54945dSmrg      if(VGAIN8(vgaCRReg) & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__);
17731d54945dSmrg      }
17741d54945dSmrg   else {
17751d54945dSmrg      VGAOUT8(vgaCRIndex, 0x66);
17761d54945dSmrg      if(VGAIN8(vgaCRReg) & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__);
17771d54945dSmrg      }
17781d54945dSmrg
17791d54945dSmrg   /* As per databook, always disable STREAMS before changing modes */
17801d54945dSmrg   VGAOUT8(vgaCRIndex, 0x67);
17811d54945dSmrg   cr67 = VGAIN8(vgaCRReg);
17821d54945dSmrg   if ((cr67 & 0x0c) == 0x0c) {
17831d54945dSmrg      S3VDisableSTREAMS(pScrn);     /* If STREAMS was running, disable it */
17841d54945dSmrg      }
17851d54945dSmrg
17861d54945dSmrg   /* Restore S3 extended regs */
17871d54945dSmrg   VGAOUT8(vgaCRIndex, 0x63);
17881d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR63);
17891d54945dSmrg   VGAOUT8(vgaCRIndex, 0x66);
17901d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR66);
17911d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3a);
17921d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR3A);
17931d54945dSmrg   VGAOUT8(vgaCRIndex, 0x31);
17941d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR31);
17951d54945dSmrg   VGAOUT8(vgaCRIndex, 0x58);
17961d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR58);
17971d54945dSmrg   VGAOUT8(vgaCRIndex, 0x55);
17981d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR55);
17991d54945dSmrg
18001d54945dSmrg   /* Extended mode timings registers */
18011d54945dSmrg   VGAOUT8(vgaCRIndex, 0x53);
18021d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR53);
18031d54945dSmrg   VGAOUT8(vgaCRIndex, 0x5d);
18041d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR5D);
18051d54945dSmrg   VGAOUT8(vgaCRIndex, 0x5e);
18061d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR5E);
18071d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3b);
18081d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR3B);
18091d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3c);
18101d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR3C);
18111d54945dSmrg   VGAOUT8(vgaCRIndex, 0x43);
18121d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR43);
18131d54945dSmrg   VGAOUT8(vgaCRIndex, 0x65);
18141d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR65);
18151d54945dSmrg   VGAOUT8(vgaCRIndex, 0x6d);
18161d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR6D);
18171d54945dSmrg
18181d54945dSmrg   /* Restore the desired video mode with CR67 */
18191d54945dSmrg
18201d54945dSmrg   VGAOUT8(vgaCRIndex, 0x67);
18211d54945dSmrg   cr67 = VGAIN8(vgaCRReg) & 0xf; /* Possible hardware bug on VX? */
18221d54945dSmrg   VGAOUT8(vgaCRReg, 0x50 | cr67);
18231d54945dSmrg   usleep(10000);
18241d54945dSmrg   VGAOUT8(vgaCRIndex, 0x67);
18251d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c); /* Don't enable STREAMS yet */
18261d54945dSmrg
18271d54945dSmrg   /* Other mode timing and extended regs */
18281d54945dSmrg   VGAOUT8(vgaCRIndex, 0x34);
18291d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR34);
18301d54945dSmrg   if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
18311d54945dSmrg	/* S3_ViRGE_MX_SERIES(ps3v->Chipset) || CR40 reserved on MX */
18321d54945dSmrg	S3_ViRGE_MXP_SERIES(ps3v->Chipset) ||
18331d54945dSmrg	S3_ViRGE_VX_SERIES(ps3v->Chipset) ||
18341d54945dSmrg	/* S3_TRIO_3D_2X_SERIES(ps3v->Chipset) * included in GX2 series */
18351d54945dSmrg	ps3v->Chipset == S3_ViRGE_DXGX ||
18361d54945dSmrg	ps3v->Chipset == S3_ViRGE
18371d54945dSmrg	)
18381d54945dSmrg     {
18391d54945dSmrg       VGAOUT8(vgaCRIndex, 0x40);
18401d54945dSmrg       VGAOUT8(vgaCRReg, restore->CR40);
18411d54945dSmrg     }
18421d54945dSmrg   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
18431d54945dSmrg     VGAOUT8(vgaCRIndex, 0x41);
18441d54945dSmrg     VGAOUT8(vgaCRReg, restore->CR41);
18451d54945dSmrg   }
18461d54945dSmrg   VGAOUT8(vgaCRIndex, 0x42);
18471d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR42);
18481d54945dSmrg   VGAOUT8(vgaCRIndex, 0x45);
18491d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR45);
18501d54945dSmrg   VGAOUT8(vgaCRIndex, 0x51);
18511d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR51);
18521d54945dSmrg   VGAOUT8(vgaCRIndex, 0x54);
18531d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR54);
18541d54945dSmrg
18551d54945dSmrg   /* Memory timings */
18561d54945dSmrg   VGAOUT8(vgaCRIndex, 0x36);
18571d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR36);
18581d54945dSmrg   VGAOUT8(vgaCRIndex, 0x68);
18591d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR68);
18601d54945dSmrg   VGAOUT8(vgaCRIndex, 0x69);
18611d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR69);
18621d54945dSmrg
18631d54945dSmrg   VGAOUT8(vgaCRIndex, 0x33);
18641d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR33);
18651d54945dSmrg   if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) || S3_ViRGE_GX2_SERIES(ps3v->Chipset)
18661d54945dSmrg       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
18671d54945dSmrg   {
18681d54945dSmrg      VGAOUT8(vgaCRIndex, 0x85);
18691d54945dSmrg      VGAOUT8(vgaCRReg, restore->CR85);
18701d54945dSmrg   }
18711d54945dSmrg   if (ps3v->Chipset == S3_ViRGE_DXGX) {
18721d54945dSmrg      VGAOUT8(vgaCRIndex, 0x86);
18731d54945dSmrg      VGAOUT8(vgaCRReg, restore->CR86);
18741d54945dSmrg   }
18751d54945dSmrg   if ( (ps3v->Chipset == S3_ViRGE_GX2) ||
18761d54945dSmrg	S3_ViRGE_MX_SERIES(ps3v->Chipset) ) {
18771d54945dSmrg      VGAOUT8(vgaCRIndex, 0x7B);
18781d54945dSmrg      VGAOUT8(vgaCRReg, restore->CR7B);
18791d54945dSmrg      VGAOUT8(vgaCRIndex, 0x7D);
18801d54945dSmrg      VGAOUT8(vgaCRReg, restore->CR7D);
18811d54945dSmrg      VGAOUT8(vgaCRIndex, 0x87);
18821d54945dSmrg      VGAOUT8(vgaCRReg, restore->CR87);
18831d54945dSmrg      VGAOUT8(vgaCRIndex, 0x92);
18841d54945dSmrg      VGAOUT8(vgaCRReg, restore->CR92);
18851d54945dSmrg      VGAOUT8(vgaCRIndex, 0x93);
18861d54945dSmrg      VGAOUT8(vgaCRReg, restore->CR93);
18871d54945dSmrg   }
18881d54945dSmrg   if (ps3v->Chipset == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
18891d54945dSmrg       S3_ViRGE_MX_SERIES(ps3v->Chipset) || S3_TRIO_3D_SERIES(ps3v->Chipset)) {
18901d54945dSmrg      VGAOUT8(vgaCRIndex, 0x90);
18911d54945dSmrg      VGAOUT8(vgaCRReg, restore->CR90);
18921d54945dSmrg      VGAOUT8(vgaCRIndex, 0x91);
18931d54945dSmrg      VGAOUT8(vgaCRReg, restore->CR91);
18941d54945dSmrg   }
18951d54945dSmrg
18961d54945dSmrg   /* Unlock extended sequencer regs */
18971d54945dSmrg   VGAOUT8(0x3c4, 0x08);
18981d54945dSmrg   VGAOUT8(0x3c5, 0x06);
18991d54945dSmrg
19001d54945dSmrg
19011d54945dSmrg   /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates that
19021d54945dSmrg    * we should leave the default SR10 and SR11 values there.
19031d54945dSmrg    */
19041d54945dSmrg
19051d54945dSmrg   if (restore->SR10 != 255) {
19061d54945dSmrg       VGAOUT8(0x3c4, 0x10);
19071d54945dSmrg       VGAOUT8(0x3c5, restore->SR10);
19081d54945dSmrg       VGAOUT8(0x3c4, 0x11);
19091d54945dSmrg       VGAOUT8(0x3c5, restore->SR11);
19101d54945dSmrg       }
19111d54945dSmrg
19121d54945dSmrg   /* Restore extended sequencer regs for DCLK */
19131d54945dSmrg   VGAOUT8(0x3c4, 0x12);
19141d54945dSmrg   VGAOUT8(0x3c5, restore->SR12);
19151d54945dSmrg   VGAOUT8(0x3c4, 0x13);
19161d54945dSmrg   VGAOUT8(0x3c5, restore->SR13);
19171d54945dSmrg   if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
19181d54945dSmrg     VGAOUT8(0x3c4, 0x29);
19191d54945dSmrg     VGAOUT8(0x3c5, restore->SR29);
19201d54945dSmrg   }
19211d54945dSmrg   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
19221d54945dSmrg     VGAOUT8(0x3c4, 0x54);
19231d54945dSmrg     VGAOUT8(0x3c5, restore->SR54);
19241d54945dSmrg     VGAOUT8(0x3c4, 0x55);
19251d54945dSmrg     VGAOUT8(0x3c5, restore->SR55);
19261d54945dSmrg     VGAOUT8(0x3c4, 0x56);
19271d54945dSmrg     VGAOUT8(0x3c5, restore->SR56);
19281d54945dSmrg     VGAOUT8(0x3c4, 0x57);
19291d54945dSmrg     VGAOUT8(0x3c5, restore->SR57);
19301d54945dSmrg   }
19311d54945dSmrg
19321d54945dSmrg   VGAOUT8(0x3c4, 0x18);
19331d54945dSmrg   VGAOUT8(0x3c5, restore->SR18);
19341d54945dSmrg
19351d54945dSmrg   /* Load new m,n PLL values for DCLK & MCLK */
19361d54945dSmrg   VGAOUT8(0x3c4, 0x15);
19371d54945dSmrg   tmp = VGAIN8(0x3c5) & ~0x21;
19381d54945dSmrg
19391d54945dSmrg   /* databook either 0x3 or 0x20, but not both?? */
19401d54945dSmrg   VGAOUT8(0x3c5, tmp | 0x03);
19411d54945dSmrg   VGAOUT8(0x3c5, tmp | 0x23);
19421d54945dSmrg   VGAOUT8(0x3c5, tmp | 0x03);
19431d54945dSmrg   VGAOUT8(0x3c5, restore->SR15);
19441d54945dSmrg   if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
19451d54945dSmrg     VGAOUT8(0x3c4, 0x0a);
19461d54945dSmrg     VGAOUT8(0x3c5, restore->SR0A);
19471d54945dSmrg     VGAOUT8(0x3c4, 0x0f);
19481d54945dSmrg     VGAOUT8(0x3c5, restore->SR0F);
19491d54945dSmrg   }
19501d54945dSmrg
19511d54945dSmrg   VGAOUT8(0x3c4, 0x08);
19521d54945dSmrg   VGAOUT8(0x3c5, restore->SR08);
19531d54945dSmrg
19541d54945dSmrg
19551d54945dSmrg   /* Now write out CR67 in full, possibly starting STREAMS */
19561d54945dSmrg
19571d54945dSmrg   VerticalRetraceWait();
19581d54945dSmrg   VGAOUT8(vgaCRIndex, 0x67);
19591d54945dSmrg   VGAOUT8(vgaCRReg, 0x50);   /* For possible bug on VX?! */
19601d54945dSmrg   usleep(10000);
19611d54945dSmrg   VGAOUT8(vgaCRIndex, 0x67);
19621d54945dSmrg   VGAOUT8(vgaCRReg, restore->CR67);
19631d54945dSmrg
19641d54945dSmrg   VGAOUT8(vgaCRIndex, 0x66);
19651d54945dSmrg   cr66 = VGAIN8(vgaCRReg);
19661d54945dSmrg   VGAOUT8(vgaCRReg, cr66 | 0x80);
19671d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3a);
19681d54945dSmrg
19691d54945dSmrg   /* workaround cr3a corruption */
19701d54945dSmrg   if( ps3v->mx_cr3a_fix )
19711d54945dSmrg     {
19721d54945dSmrg       VGAOUT8(vgaCRReg, restore->CR3A | 0x80);
19731d54945dSmrg     }
19741d54945dSmrg   else
19751d54945dSmrg     {
19761d54945dSmrg       cr3a = VGAIN8(vgaCRReg);
19771d54945dSmrg       VGAOUT8(vgaCRReg, cr3a | 0x80);
19781d54945dSmrg     }
19791d54945dSmrg
19801d54945dSmrg   /* And finally, we init the STREAMS processor if we have CR67 indicate 24bpp
19811d54945dSmrg    * We also restore FIFO and TIMEOUT memory controller registers. (later...)
19821d54945dSmrg    */
19831d54945dSmrg
19841d54945dSmrg   if (ps3v->NeedSTREAMS) {
19851d54945dSmrg      if(ps3v->STREAMSRunning) S3VRestoreSTREAMS(pScrn, restore->STREAMS);
19861d54945dSmrg      }
19871d54945dSmrg
19881d54945dSmrg   /* Now, before we continue, check if this mode has the graphic engine ON
19891d54945dSmrg    * If yes, then we reset it.
19901d54945dSmrg    * This fixes some problems with corruption at 24bpp with STREAMS
19911d54945dSmrg    * Also restore the MIU registers.
19921d54945dSmrg    */
19931d54945dSmrg
19941d54945dSmrg#ifndef MetroLink
19951d54945dSmrg   if(ps3v->Chipset == S3_ViRGE_VX) {
19961d54945dSmrg      if(restore->CR63 & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__);
19971d54945dSmrg      }
19981d54945dSmrg   else {
19991d54945dSmrg      if(restore->CR66 & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__);
20001d54945dSmrg      }
20011d54945dSmrg#else
20021d54945dSmrg   S3VGEReset(pScrn,0,__LINE__,__FILE__);
20031d54945dSmrg#endif
20041d54945dSmrg
20051d54945dSmrg   VerticalRetraceWait();
20061d54945dSmrg   if (S3_ViRGE_GX2_SERIES(ps3v->Chipset)
20071d54945dSmrg       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
20081d54945dSmrg     {
20091d54945dSmrg      VGAOUT8(vgaCRIndex, 0x85);
20101d54945dSmrg      /* primary stream threshold */
20111d54945dSmrg      VGAOUT8(vgaCRReg, 0x1f );
20121d54945dSmrg     }
20131d54945dSmrg   else
20141d54945dSmrg     {
20151d54945dSmrg       OUTREG(FIFO_CONTROL_REG, restore->MMPR0);
20161d54945dSmrg     }
20171d54945dSmrg   if( !( S3_ViRGE_GX2_SERIES(ps3v->Chipset)
20181d54945dSmrg	  /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) ))
20191d54945dSmrg   {
20201d54945dSmrg     WaitIdle();                  /* Don't ask... */
20211d54945dSmrg     OUTREG(MIU_CONTROL_REG, restore->MMPR1);
20221d54945dSmrg     WaitIdle();
20231d54945dSmrg     OUTREG(STREAMS_TIMEOUT_REG, restore->MMPR2);
20241d54945dSmrg     WaitIdle();
20251d54945dSmrg     OUTREG(MISC_TIMEOUT_REG, restore->MMPR3);
20261d54945dSmrg   }
20271d54945dSmrg
20281d54945dSmrg   /* Restore the standard VGA registers */
20291d54945dSmrg   /* False indicates no fontinfo restore. */
20301d54945dSmrg   /* VGA_SR_MODE restores mode info only, no font, no colormap */
20311d54945dSmrg   					/* Do all for primary video */
20321d54945dSmrg   if (xf86IsPrimaryPci(ps3v->PciInfo))
20331d54945dSmrg     vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
20341d54945dSmrg   					/* Mode only for non-primary? */
20351d54945dSmrg   else
20361d54945dSmrg     vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE);
20371d54945dSmrg 		/* moved from before vgaHWRestore, to prevent segfault? */
20381d54945dSmrg   VGAOUT8(vgaCRIndex, 0x66);
20391d54945dSmrg   VGAOUT8(vgaCRReg, cr66);
20401d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3a);
20411d54945dSmrg
20421d54945dSmrg   /* workaround cr3a corruption */
20431d54945dSmrg   if( ps3v->mx_cr3a_fix )
20441d54945dSmrg     VGAOUT8(vgaCRReg, restore->CR3A);
20451d54945dSmrg   else
20461d54945dSmrg     VGAOUT8(vgaCRReg, cr3a);
20471d54945dSmrg
20481d54945dSmrg   if (xf86GetVerbosity() > 1) {
20491d54945dSmrg      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
20501d54945dSmrg         "ViRGE driver: done restoring mode, dumping CR registers:\n");
20511d54945dSmrg      S3VPrintRegs(pScrn);
20521d54945dSmrg   }
20531d54945dSmrg
20541d54945dSmrg   vgaHWProtect(pScrn, FALSE);
20551d54945dSmrg
20561d54945dSmrg   return;
20571d54945dSmrg
20581d54945dSmrg}
20591d54945dSmrg
20601d54945dSmrg
20611d54945dSmrg/* This function restores the saved STREAMS registers */
20621d54945dSmrg
20631d54945dSmrgstatic void
20641d54945dSmrgS3VRestoreSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams)
20651d54945dSmrg{
20661d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
20671d54945dSmrg
20681d54945dSmrg
20691d54945dSmrg/* For now, set most regs to their default values for 24bpp
20701d54945dSmrg * Restore only those that are needed for width/height/stride
20711d54945dSmrg * Otherwise, we seem to get lockups because some registers
20721d54945dSmrg * when saved have some reserved bits set.
20731d54945dSmrg */
20741d54945dSmrg
20751d54945dSmrg  OUTREG(PSTREAM_CONTROL_REG, streams[0] & 0x77000000);
20761d54945dSmrg  OUTREG(COL_CHROMA_KEY_CONTROL_REG, 0x00);
20771d54945dSmrg  OUTREG(SSTREAM_CONTROL_REG, 0x03000000);
20781d54945dSmrg  OUTREG(CHROMA_KEY_UPPER_BOUND_REG, 0x00);
20791d54945dSmrg  OUTREG(SSTREAM_STRETCH_REG, 0x00);
20801d54945dSmrg  OUTREG(BLEND_CONTROL_REG, 0x01000000);
20811d54945dSmrg  OUTREG(PSTREAM_FBADDR0_REG, 0x00);
20821d54945dSmrg  OUTREG(PSTREAM_FBADDR1_REG, 0x00);
20831d54945dSmrg  OUTREG(PSTREAM_STRIDE_REG, streams[8] & 0x0fff);
20841d54945dSmrg  OUTREG(DOUBLE_BUFFER_REG, 0x00);
20851d54945dSmrg  OUTREG(SSTREAM_FBADDR0_REG, 0x00);
20861d54945dSmrg  OUTREG(SSTREAM_FBADDR1_REG, 0x00);
20871d54945dSmrg  OUTREG(SSTREAM_STRIDE_REG, 0x01);
20881d54945dSmrg  OUTREG(OPAQUE_OVERLAY_CONTROL_REG, 0x40000000);
20891d54945dSmrg  OUTREG(K1_VSCALE_REG, 0x00);
20901d54945dSmrg  OUTREG(K2_VSCALE_REG, 0x00);
20911d54945dSmrg  OUTREG(DDA_VERT_REG, 0x00);
20921d54945dSmrg  OUTREG(PSTREAM_START_REG, 0x00010001);
20931d54945dSmrg  OUTREG(PSTREAM_WINDOW_SIZE_REG, streams[19] & 0x07ff07ff);
20941d54945dSmrg  OUTREG(SSTREAM_START_REG, 0x07ff07ff);
20951d54945dSmrg  OUTREG(SSTREAM_WINDOW_SIZE_REG, 0x00010001);
20961d54945dSmrg
20971d54945dSmrg
20981d54945dSmrg}
20991d54945dSmrg
21001d54945dSmrg
21011d54945dSmrg
21021d54945dSmrg
21031d54945dSmrg/* And this function disables the STREAMS processor as per databook.
21040b7217d9Smrg * This is useful before we do a mode change
21051d54945dSmrg */
21061d54945dSmrg
21071d54945dSmrgstatic void
21081d54945dSmrgS3VDisableSTREAMS(ScrnInfoPtr pScrn)
21091d54945dSmrg{
21101d54945dSmrgunsigned char tmp;
21111d54945dSmrg  vgaHWPtr hwp = VGAHWPTR(pScrn);
21121d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
21131d54945dSmrg  int vgaCRIndex, vgaCRReg, vgaIOBase;
21141d54945dSmrg  vgaIOBase = hwp->IOBase;
21151d54945dSmrg  vgaCRIndex = vgaIOBase + 4;
21161d54945dSmrg  vgaCRReg = vgaIOBase + 5;
21171d54945dSmrg
21181d54945dSmrg   VerticalRetraceWait();
21191d54945dSmrg   OUTREG(FIFO_CONTROL_REG, 0xC000);
21201d54945dSmrg   VGAOUT8(vgaCRIndex, 0x67);
21211d54945dSmrg   tmp = VGAIN8(vgaCRReg);
21221d54945dSmrg                         /* Disable STREAMS processor */
21231d54945dSmrg   VGAOUT8( vgaCRReg, tmp & ~0x0C );
21241d54945dSmrg
21251d54945dSmrg   return;
21261d54945dSmrg}
21271d54945dSmrg
21281d54945dSmrg
21291d54945dSmrg
21301d54945dSmrg/* MapMem - contains half of pre-4.0 EnterLeave function */
21311d54945dSmrg/* The EnterLeave function which en/dis access to IO ports and ext. regs */
21321d54945dSmrg                /********************************************************/
21331d54945dSmrg		/* Aaagh...  So many locations!  On my machine (KJB) the*/
21341d54945dSmrg		/* following is true. 					*/
21351d54945dSmrg		/* PciInfo->memBase[0] returns e400 0000 		*/
21361d54945dSmrg		/* From my ViRGE manual, the memory map looks like 	*/
21371d54945dSmrg		/* Linear mem - 16M  	000 0000 - 0ff ffff 		*/
21381d54945dSmrg		/* Image xfer - 32k  	100 0000 - 100 7fff 		*/
21391d54945dSmrg		/* PCI cnfg    		100 8000 - 100 8043 		*/
21401d54945dSmrg		/* ...				   			*/
21411d54945dSmrg		/* CRT VGA 3b? reg	100 83b0 - 			*/
21421d54945dSmrg		/* And S3_NEWMMIO_VGABASE = S3_NEWMMIO_REGBASE + 0x8000	*/
21431d54945dSmrg		/* where S3_NEWMMIO_REGBASE = 0x100 0000  ( 16MB )      */
21441d54945dSmrg		/* S3_NEWMMIO_REGSIZE = 0x1 0000  ( 64KB )		*/
21451d54945dSmrg		/* S3V_MMIO_REGSIZE = 0x8000 ( 32KB ) - above includes	*/
21461d54945dSmrg		/* the image transfer area, so this one is used instead.*/
21470b7217d9Smrg		/* ps3v->IOBase is assigned the virtual address returned*/
21481d54945dSmrg		/* from MapPciMem, it is the address to base all 	*/
21491d54945dSmrg		/* register access. (It is a pointer.)  		*/
21501d54945dSmrg		/* hwp->MemBase is a CARD32, containing the register	*/
21511d54945dSmrg		/* base. (It's a conversion from IOBase above.) 	*/
21521d54945dSmrg                /********************************************************/
21531d54945dSmrg
21541d54945dSmrg
21551d54945dSmrgstatic Bool
21561d54945dSmrgS3VMapMem(ScrnInfoPtr pScrn)
21571d54945dSmrg{
21581d54945dSmrg  S3VPtr ps3v;
21591d54945dSmrg  vgaHWPtr hwp;
21601d54945dSmrg
21611d54945dSmrg    PVERB5("	S3VMapMem\n");
21621d54945dSmrg
21631d54945dSmrg  ps3v = S3VPTR(pScrn);
21641d54945dSmrg
21651d54945dSmrg    					/* Map the ViRGE register space */
21661d54945dSmrg					/* Starts with Image Transfer area */
21671d54945dSmrg					/* so that we can use registers map */
21681d54945dSmrg					/* structure - see newmmio.h */
21691d54945dSmrg					/* around 0x10000 from MemBase */
2170ba85709eSmrg#ifndef XSERVER_LIBPCIACCESS
21711d54945dSmrg  ps3v->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, ps3v->PciTag,
2172ba85709eSmrg				PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) + S3_NEWMMIO_REGBASE,
2173ba85709eSmrg				S3_NEWMMIO_REGSIZE);
21741d54945dSmrg
21751d54945dSmrg  ps3v->MapBaseDense = xf86MapPciMem(pScrn->scrnIndex,
2176ba85709eSmrg				     VIDMEM_MMIO_32BIT,
2177ba85709eSmrg				     ps3v->PciTag,
2178ba85709eSmrg				     PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) + S3_NEWMMIO_REGBASE,
2179ba85709eSmrg				     0x8000);
2180ba85709eSmrg#else
2181ba85709eSmrg  {
2182ba85709eSmrg    void** result = (void**)&ps3v->MapBase;
2183ba85709eSmrg    int err = pci_device_map_range(ps3v->PciInfo,
2184ba85709eSmrg				   PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) + S3_NEWMMIO_REGBASE,
2185ba85709eSmrg				   S3_NEWMMIO_REGSIZE,
2186ba85709eSmrg				   PCI_DEV_MAP_FLAG_WRITABLE,
2187ba85709eSmrg				   result);
2188ba85709eSmrg
2189ba85709eSmrg    if (err)
2190ba85709eSmrg      return FALSE;
2191ba85709eSmrg  }
2192ba85709eSmrg  ps3v->MapBaseDense = ps3v->MapBase;
2193ba85709eSmrg#endif
21941d54945dSmrg
21951d54945dSmrg  if( !ps3v->MapBase ) {
21961d54945dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
21971d54945dSmrg	"Internal error: could not map registers.\n");
21981d54945dSmrg    return FALSE;
21991d54945dSmrg  }
22001d54945dSmrg					/* Map the framebuffer */
22011d54945dSmrg  if (ps3v->videoRambytes) { /* not set in PreInit() */
2202ba85709eSmrg#ifndef XSERVER_LIBPCIACCESS
22031d54945dSmrg      ps3v->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2204ba85709eSmrg				   ps3v->PciTag, PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM),
22051d54945dSmrg				   ps3v->videoRambytes );
22061d54945dSmrg
2207ba85709eSmrg#else
2208ba85709eSmrg      {
2209ba85709eSmrg	void** result = (void**)&ps3v->FBBase;
2210ba85709eSmrg	int err = pci_device_map_range(ps3v->PciInfo,
2211ba85709eSmrg				       PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM),
2212ba85709eSmrg				       ps3v->videoRambytes,
2213ba85709eSmrg				       PCI_DEV_MAP_FLAG_WRITABLE |
2214ba85709eSmrg				       PCI_DEV_MAP_FLAG_WRITE_COMBINE,
2215ba85709eSmrg				       result);
2216ba85709eSmrg
2217ba85709eSmrg	if (err)
2218ba85709eSmrg	  return FALSE;
2219ba85709eSmrg      }
2220ba85709eSmrg#endif
2221ba85709eSmrg
22221d54945dSmrg      if( !ps3v->FBBase ) {
22231d54945dSmrg	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
22241d54945dSmrg		     "Internal error: could not map framebuffer.\n");
22251d54945dSmrg	  return FALSE;
22261d54945dSmrg      }
22271d54945dSmrg  		       		/* Initially the visual display start */
22281d54945dSmrg				/* is the same as the mapped start. */
22291d54945dSmrg      ps3v->FBStart = ps3v->FBBase;
22301d54945dSmrg  }
22311d54945dSmrg
2232ba85709eSmrg  pScrn->memPhysBase = PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM);
22331d54945dSmrg  pScrn->fbOffset = 0;
22341d54945dSmrg
22351d54945dSmrg  				/* Set up offset to hwcursor memory area */
22361d54945dSmrg  				/* It's a 1K chunk at the end of the frame buffer */
22371d54945dSmrg  ps3v->FBCursorOffset = ps3v->videoRambytes - 1024;
22381d54945dSmrg  S3VEnableMmio( pScrn);
22391d54945dSmrg   					/* Assign hwp->MemBase & IOBase here */
22401d54945dSmrg  hwp = VGAHWPTR(pScrn);
22411d54945dSmrg					/* Sets MMIOBase and Offset, assigns */
22421d54945dSmrg					/* functions. Offset from map area   */
22431d54945dSmrg					/* to VGA reg area is 0x8000. */
22441d54945dSmrg  vgaHWSetMmioFuncs( hwp, ps3v->MapBase, S3V_MMIO_REGSIZE );
22451d54945dSmrg  					/* assigns hwp->IOBase to 3D0 or 3B0 */
22461d54945dSmrg					/* needs hwp->MMIOBase to work */
22471d54945dSmrg  vgaHWGetIOBase(hwp);
22481d54945dSmrg
22491d54945dSmrg    					/* Map the VGA memory when the */
22501d54945dSmrg					/* primary video */
22511d54945dSmrg
22521d54945dSmrg  if (xf86IsPrimaryPci(ps3v->PciInfo)) {
22531d54945dSmrg    hwp->MapSize = 0x10000;
22541d54945dSmrg    if (!vgaHWMapMem(pScrn))
22551d54945dSmrg      return FALSE;
22561d54945dSmrg    ps3v->PrimaryVidMapped = TRUE;
22571d54945dSmrg  }
22581d54945dSmrg
22591d54945dSmrg  return TRUE;
22601d54945dSmrg}
22611d54945dSmrg
22621d54945dSmrg
22631d54945dSmrg
22641d54945dSmrg/* UnMapMem - contains half of pre-4.0 EnterLeave function */
22651d54945dSmrg/* The EnterLeave function which en/dis access to IO ports and ext. regs */
22661d54945dSmrg
22671d54945dSmrgstatic void
22681d54945dSmrgS3VUnmapMem(ScrnInfoPtr pScrn)
22691d54945dSmrg{
22701d54945dSmrg  S3VPtr ps3v;
22711d54945dSmrg
22721d54945dSmrg  ps3v = S3VPTR(pScrn);
22731d54945dSmrg					/* Unmap VGA mem if mapped. */
22741d54945dSmrg  if( ps3v->PrimaryVidMapped ) {
22751d54945dSmrg    vgaHWUnmapMem( pScrn );
22761d54945dSmrg    ps3v->PrimaryVidMapped = FALSE;
22771d54945dSmrg  }
22781d54945dSmrg
2279ba85709eSmrg#ifndef XSERVER_LIBPCIACCESS
22801d54945dSmrg  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)ps3v->MapBase,
22811d54945dSmrg		  S3_NEWMMIO_REGSIZE);
2282ba85709eSmrg#else
2283ba85709eSmrg  pci_device_unmap_range(ps3v->PciInfo, ps3v->MapBase,
2284ba85709eSmrg			 S3_NEWMMIO_REGSIZE);
2285ba85709eSmrg#endif
2286ba85709eSmrg
2287ba85709eSmrg#ifndef XSERVER_LIBPCIACCESS
22881d54945dSmrg  if (ps3v->FBBase)
22891d54945dSmrg      xf86UnMapVidMem(pScrn->scrnIndex, (pointer)ps3v->FBBase,
22901d54945dSmrg		      ps3v->videoRambytes);
22911d54945dSmrg  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)ps3v->MapBaseDense,
22921d54945dSmrg		  0x8000);
2293ba85709eSmrg#else
2294ba85709eSmrg  pci_device_unmap_range(ps3v->PciInfo, ps3v->FBBase,
2295ba85709eSmrg			 ps3v->videoRambytes);
2296ba85709eSmrg#endif
22971d54945dSmrg  return;
22981d54945dSmrg}
22991d54945dSmrg
23001d54945dSmrg
23011d54945dSmrg
23021d54945dSmrg/* Mandatory */
23031d54945dSmrg
23041d54945dSmrg/* This gets called at the start of each server generation */
23051d54945dSmrg
23061d54945dSmrgstatic Bool
23075788ca14SmrgS3VScreenInit(SCREEN_INIT_ARGS_DECL)
23081d54945dSmrg{
23091d54945dSmrg  ScrnInfoPtr pScrn;
23101d54945dSmrg  S3VPtr ps3v;
23111d54945dSmrg  int ret;
23121d54945dSmrg
23131d54945dSmrg  PVERB5("	S3VScreenInit\n");
23141d54945dSmrg                                        /* First get the ScrnInfoRec */
23155788ca14Smrg  pScrn = xf86ScreenToScrn(pScreen);
23161d54945dSmrg  					/* Get S3V rec */
23171d54945dSmrg  ps3v = S3VPTR(pScrn);
23181d54945dSmrg   					/* Map MMIO regs and framebuffer */
23191d54945dSmrg  if( !S3VMapMem(pScrn) )
23201d54945dSmrg    return FALSE;
23211d54945dSmrg    					/* Save the chip/graphics state */
23221d54945dSmrg  S3VSave(pScrn);
23231d54945dSmrg				 	/* Blank the screen during init */
23241d54945dSmrg  vgaHWBlankScreen(pScrn, TRUE );
23251d54945dSmrg    					/* Initialise the first mode */
23261d54945dSmrg  if (!S3VModeInit(pScrn, pScrn->currentMode))
23271d54945dSmrg    return FALSE;
23281d54945dSmrg
23291d54945dSmrg    /*
23301d54945dSmrg     * The next step is to setup the screen's visuals, and initialise the
23311d54945dSmrg     * framebuffer code.  In cases where the framebuffer's default
23321d54945dSmrg     * choices for things like visual layouts and bits per RGB are OK,
23331d54945dSmrg     * this may be as simple as calling the framebuffer's ScreenInit()
23341d54945dSmrg     * function.  If not, the visuals will need to be setup before calling
23351d54945dSmrg     * a fb ScreenInit() function and fixed up after.
23361d54945dSmrg     *
23371d54945dSmrg     * For most PC hardware at depths >= 8, the defaults that fb uses
23381d54945dSmrg     * are not appropriate.  In this driver, we fixup the visuals after.
23391d54945dSmrg     */
23401d54945dSmrg
23411d54945dSmrg    /*
23421d54945dSmrg     * Reset the visual list.
23431d54945dSmrg     */
23441d54945dSmrg  miClearVisualTypes();
23451d54945dSmrg
23461d54945dSmrg    /* Setup the visuals we support. */
23471d54945dSmrg
23481d54945dSmrg    /*
23491d54945dSmrg     * For bpp > 8, the default visuals are not acceptable because we only
23501d54945dSmrg     * support TrueColor and not DirectColor.  To deal with this, call
23511d54945dSmrg     * miSetVisualTypes with the appropriate visual mask.
23521d54945dSmrg     */
23531d54945dSmrg
23541d54945dSmrg  if (pScrn->bitsPerPixel > 8) {
23551d54945dSmrg	if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits,
23561d54945dSmrg				pScrn->defaultVisual))
23571d54945dSmrg	    return FALSE;
23581d54945dSmrg
23591d54945dSmrg	if (!miSetPixmapDepths ())
23601d54945dSmrg	    return FALSE;
23611d54945dSmrg  } else {
23621d54945dSmrg	if (!miSetVisualTypes(pScrn->depth,
23631d54945dSmrg			      miGetDefaultVisualMask(pScrn->depth),
23641d54945dSmrg			      pScrn->rgbBits, pScrn->defaultVisual))
23651d54945dSmrg	    return FALSE;
23661d54945dSmrg
23671d54945dSmrg	if (!miSetPixmapDepths ())
23681d54945dSmrg	    return FALSE;
23691d54945dSmrg  }
23701d54945dSmrg
23715788ca14Smrg  ret = S3VInternalScreenInit(pScrn, pScreen);
23721d54945dSmrg
23731d54945dSmrg  if (!ret)
23741d54945dSmrg    return FALSE;
23751d54945dSmrg
23761d54945dSmrg  xf86SetBlackWhitePixels(pScreen);
23771d54945dSmrg
23781d54945dSmrg  if (pScrn->bitsPerPixel > 8) {
23791d54945dSmrg    	VisualPtr visual;
23801d54945dSmrg					/* Fixup RGB ordering */
23811d54945dSmrg	visual = pScreen->visuals + pScreen->numVisuals;
23821d54945dSmrg	while (--visual >= pScreen->visuals) {
23831d54945dSmrg	    if ((visual->class | DynamicClass) == DirectColor) {
23841d54945dSmrg		visual->offsetRed = pScrn->offset.red;
23851d54945dSmrg		visual->offsetGreen = pScrn->offset.green;
23861d54945dSmrg		visual->offsetBlue = pScrn->offset.blue;
23871d54945dSmrg		visual->redMask = pScrn->mask.red;
23881d54945dSmrg		visual->greenMask = pScrn->mask.green;
23891d54945dSmrg		visual->blueMask = pScrn->mask.blue;
23901d54945dSmrg	    }
23911d54945dSmrg	}
23921d54945dSmrg  }
23931d54945dSmrg
23941d54945dSmrg  /* must be after RGB ordering fixed */
2395ba85709eSmrg  fbPictureInit (pScreen, 0, 0);
23961d54945dSmrg
23971d54945dSmrg  	      				/* Initialize acceleration layer */
23981d54945dSmrg  if (!ps3v->NoAccel) {
23991d54945dSmrg    if(pScrn->bitsPerPixel == 32) {
24001d54945dSmrg      /* 32 bit Accel currently broken
24011d54945dSmrg      if (!S3VAccelInit32(pScreen))
24021d54945dSmrg        return FALSE;
24031d54945dSmrg	*/
24041d54945dSmrg	;
24051d54945dSmrg    } else
24061d54945dSmrg      if (!S3VAccelInit(pScreen))
24071d54945dSmrg        return FALSE;
24081d54945dSmrg  }
24091d54945dSmrg
24101d54945dSmrg  xf86SetBackingStore(pScreen);
24111d54945dSmrg  xf86SetSilkenMouse(pScreen);
24121d54945dSmrg  						/* hardware cursor needs to wrap this layer */
24131d54945dSmrg  S3VDGAInit(pScreen);
24141d54945dSmrg
24151d54945dSmrg    					/* Initialise cursor functions */
24161d54945dSmrg  miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
24171d54945dSmrg
24181d54945dSmrg    /* Initialize HW cursor layer.
24191d54945dSmrg	Must follow software cursor initialization*/
24201d54945dSmrg  if (ps3v->hwcursor) {
24211d54945dSmrg  if(!S3VHWCursorInit(pScreen)) {
24221d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
24231d54945dSmrg		"Hardware cursor initialization failed\n");
24241d54945dSmrg		}
24251d54945dSmrg  }
24261d54945dSmrg
24271d54945dSmrg  if (ps3v->shadowFB) {
24281d54945dSmrg      RefreshAreaFuncPtr refreshArea = s3vRefreshArea;
24291d54945dSmrg
24301d54945dSmrg      if(ps3v->rotate) {
24311d54945dSmrg	  if (!ps3v->PointerMoved) {
24321d54945dSmrg	      ps3v->PointerMoved = pScrn->PointerMoved;
24331d54945dSmrg	      pScrn->PointerMoved = s3vPointerMoved;
24341d54945dSmrg	  }
24351d54945dSmrg
24361d54945dSmrg	  switch(pScrn->bitsPerPixel) {
24371d54945dSmrg	  case 8:	refreshArea = s3vRefreshArea8;	break;
24381d54945dSmrg	  case 16:	refreshArea = s3vRefreshArea16;	break;
24391d54945dSmrg	  case 24:	refreshArea = s3vRefreshArea24;	break;
24401d54945dSmrg	  case 32:	refreshArea = s3vRefreshArea32;	break;
24411d54945dSmrg	  }
24421d54945dSmrg      }
24431d54945dSmrg
24441d54945dSmrg      ShadowFBInit(pScreen, refreshArea);
24451d54945dSmrg  }
24461d54945dSmrg
24471d54945dSmrg    					/* Initialise default colourmap */
24481d54945dSmrg  if (!miCreateDefColormap(pScreen))
24491d54945dSmrg    return FALSE;
24501d54945dSmrg  					/* Initialize colormap layer.   */
24511d54945dSmrg					/* Must follow initialization   */
24521d54945dSmrg					/* of the default colormap. 	*/
24531d54945dSmrg					/* And SetGamma call, else it 	*/
24541d54945dSmrg					/* will load palette with solid */
24551d54945dSmrg					/* white. */
24561d54945dSmrg  if(!xf86HandleColormaps(pScreen, 256, 6, S3VLoadPalette, NULL,
24571d54945dSmrg			CMAP_RELOAD_ON_MODE_SWITCH ))
24581d54945dSmrg	return FALSE;
24591d54945dSmrg				    	/* All the ugly stuff is done, 	*/
24601d54945dSmrg					/* so re-enable the screen. 	*/
24611d54945dSmrg  vgaHWBlankScreen(pScrn, FALSE );
24621d54945dSmrg
24631d54945dSmrg#if 0
24641d54945dSmrg  pScrn->racMemFlags = RAC_COLORMAP | RAC_CURSOR | RAC_FB | RAC_VIEWPORT;
24651d54945dSmrg#endif
24661d54945dSmrg  pScreen->SaveScreen = S3VSaveScreen;
24671d54945dSmrg
24681d54945dSmrg    					/* Wrap the current CloseScreen function */
24691d54945dSmrg  ps3v->CloseScreen = pScreen->CloseScreen;
24701d54945dSmrg  pScreen->CloseScreen = S3VCloseScreen;
24711d54945dSmrg
24721d54945dSmrg  if(xf86DPMSInit(pScreen, S3VDisplayPowerManagementSet, 0) == FALSE)
24731d54945dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n");
24741d54945dSmrg
24751d54945dSmrg  S3VInitVideo(pScreen);
24761d54945dSmrg
24771d54945dSmrg    /* Report any unused options (only for the first generation) */
24781d54945dSmrg  if (serverGeneration == 1) {
24791d54945dSmrg    xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
24801d54945dSmrg  }
24811d54945dSmrg    					/* Done */
24821d54945dSmrg  return TRUE;
24831d54945dSmrg}
24841d54945dSmrg
24851d54945dSmrg
24861d54945dSmrg
24871d54945dSmrg/* Common init routines needed in EnterVT and ScreenInit */
24881d54945dSmrg
24891d54945dSmrgstatic int
24905788ca14SmrgS3VInternalScreenInit(ScrnInfoPtr pScrn, ScreenPtr pScreen)
24911d54945dSmrg{
24921d54945dSmrg  int ret = TRUE;
24931d54945dSmrg  S3VPtr ps3v;
24941d54945dSmrg  int width, height, displayWidth;
24951d54945dSmrg  unsigned char* FBStart;
24961d54945dSmrg
24971d54945dSmrg  ps3v = S3VPTR(pScrn);
24981d54945dSmrg
24991d54945dSmrg  displayWidth = pScrn->displayWidth;
25001d54945dSmrg  if (ps3v->rotate) {
25011d54945dSmrg      height = pScrn->virtualX;
25021d54945dSmrg      width = pScrn->virtualY;
25031d54945dSmrg  } else {
25041d54945dSmrg      width = pScrn->virtualX;
25051d54945dSmrg      height = pScrn->virtualY;
25061d54945dSmrg  }
25071d54945dSmrg
25081d54945dSmrg  if(ps3v->shadowFB) {
25091d54945dSmrg      ps3v->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
25105788ca14Smrg      ps3v->ShadowPtr = malloc(ps3v->ShadowPitch * height);
25111d54945dSmrg      displayWidth = ps3v->ShadowPitch / (pScrn->bitsPerPixel >> 3);
25121d54945dSmrg      FBStart = ps3v->ShadowPtr;
25131d54945dSmrg  } else {
25141d54945dSmrg      ps3v->ShadowPtr = NULL;
25151d54945dSmrg      FBStart = ps3v->FBStart;
25161d54945dSmrg  }
25171d54945dSmrg
25181d54945dSmrg    /*
25191d54945dSmrg     * Call the framebuffer layer's ScreenInit function, and fill in other
25201d54945dSmrg     * pScreen fields.
25211d54945dSmrg     */
25221d54945dSmrg
2523ba85709eSmrg    switch (pScrn->bitsPerPixel)
25241d54945dSmrg    {
25251d54945dSmrg	case 8:
25261d54945dSmrg	case 16:
25271d54945dSmrg	case 24:
2528ba85709eSmrg	case 32:
2529ba85709eSmrg	    ret = fbScreenInit(pScreen, FBStart, width,
2530ba85709eSmrg			       height, pScrn->xDpi, pScrn->yDpi,
2531ba85709eSmrg			       displayWidth, pScrn->bitsPerPixel);
2532ba85709eSmrg	    break;
25331d54945dSmrg	default:
25345788ca14Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2535ba85709eSmrg		       "Internal error: invalid bpp (%d) in S3VScreenInit\n",
2536ba85709eSmrg		       pScrn->bitsPerPixel);
2537ba85709eSmrg	    ret = FALSE;
2538ba85709eSmrg	    break;
25391d54945dSmrg    }
2540ba85709eSmrg
25411d54945dSmrg  return ret;
25421d54945dSmrg}
25431d54945dSmrg
25441d54945dSmrg
25451d54945dSmrg
25461d54945dSmrg/* Checks if a mode is suitable for the selected chipset. */
25471d54945dSmrg
25481d54945dSmrgstatic ModeStatus
25495788ca14SmrgS3VValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
25501d54945dSmrg{
25515788ca14Smrg   SCRN_INFO_PTR(arg);
2552ba85709eSmrg
2553ba85709eSmrg    if ((pScrn->bitsPerPixel + 7)/8 * mode->HDisplay > 4095)
2554ba85709eSmrg	return MODE_VIRTUAL_X;
25551d54945dSmrg
25560b7217d9Smrg    /* todo -  The virge limit is 2048 vertical & horizontal */
25570b7217d9Smrg    /* pixels, not clock register settings. */
25580b7217d9Smrg				/* true for all ViRGE? */
25590b7217d9Smrg    if (mode->HTotal > 2048)
25600b7217d9Smrg        return MODE_BAD_HVALUE;
25610b7217d9Smrg
25620b7217d9Smrg    if (mode->VTotal > 2048)
25630b7217d9Smrg        return MODE_BAD_VVALUE;
25640b7217d9Smrg
2565ba85709eSmrg    return MODE_OK;
25661d54945dSmrg}
25671d54945dSmrg
25681d54945dSmrg
25691d54945dSmrg
25701d54945dSmrgstatic Bool
25711d54945dSmrgS3VModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
25721d54945dSmrg{
25731d54945dSmrg  vgaHWPtr hwp = VGAHWPTR(pScrn);
25741d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
25751d54945dSmrg  int width, dclk;
25761d54945dSmrg  int i, j;
25771d54945dSmrg  unsigned char tmp = 0;
25781d54945dSmrg
25791d54945dSmrg  		      		/* Store values to current mode register structs */
25801d54945dSmrg  S3VRegPtr new = &ps3v->ModeReg;
25811d54945dSmrg  vgaRegPtr vganew = &hwp->ModeReg;
25821d54945dSmrg  int vgaCRIndex, vgaCRReg, vgaIOBase;
25831d54945dSmrg
25841d54945dSmrg  vgaIOBase = hwp->IOBase;
25851d54945dSmrg  vgaCRIndex = vgaIOBase + 4;
25861d54945dSmrg  vgaCRReg = vgaIOBase + 5;
25871d54945dSmrg
25881d54945dSmrg    PVERB5("	S3VModeInit\n");
25891d54945dSmrg
25901d54945dSmrg    /* Set scale factors for mode timings */
25911d54945dSmrg
25921d54945dSmrg    if (ps3v->Chipset == S3_ViRGE_VX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
25931d54945dSmrg	S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
25941d54945dSmrg      ps3v->HorizScaleFactor = 1;
25951d54945dSmrg    }
25961d54945dSmrg    else if (pScrn->bitsPerPixel == 8) {
25971d54945dSmrg      ps3v->HorizScaleFactor = 1;
25981d54945dSmrg    }
25991d54945dSmrg    else if (pScrn->bitsPerPixel == 16) {
26001d54945dSmrg      if (S3_TRIO_3D_SERIES(ps3v->Chipset) && mode->Clock > 115000)
26011d54945dSmrg	ps3v->HorizScaleFactor = 1;
26021d54945dSmrg      else
26031d54945dSmrg	ps3v->HorizScaleFactor = 2;
26041d54945dSmrg    }
26051d54945dSmrg    else {
26061d54945dSmrg      ps3v->HorizScaleFactor = 1;
26071d54945dSmrg    }
26081d54945dSmrg
26091d54945dSmrg
26101d54945dSmrg   /* First we adjust the horizontal timings if needed */
26111d54945dSmrg
26121d54945dSmrg   if(ps3v->HorizScaleFactor != 1)
26131d54945dSmrg      if (!mode->CrtcHAdjusted) {
26141d54945dSmrg             mode->CrtcHDisplay *= ps3v->HorizScaleFactor;
26151d54945dSmrg             mode->CrtcHSyncStart *= ps3v->HorizScaleFactor;
26161d54945dSmrg             mode->CrtcHSyncEnd *= ps3v->HorizScaleFactor;
26171d54945dSmrg             mode->CrtcHTotal *= ps3v->HorizScaleFactor;
26181d54945dSmrg             mode->CrtcHSkew *= ps3v->HorizScaleFactor;
26191d54945dSmrg             mode->CrtcHAdjusted = TRUE;
26201d54945dSmrg             }
26211d54945dSmrg
26221d54945dSmrg   if(!vgaHWInit (pScrn, mode))
26231d54945dSmrg      return FALSE;
26241d54945dSmrg
26251d54945dSmrg   /* Now we fill in the rest of the stuff we need for the virge */
26261d54945dSmrg   /* Start with MMIO, linear addr. regs */
26271d54945dSmrg
26281d54945dSmrg   VGAOUT8(vgaCRIndex, 0x3a);
26291d54945dSmrg   tmp = VGAIN8(vgaCRReg);
26301d54945dSmrg   if( S3_ViRGE_GX2_SERIES(ps3v->Chipset)
26311d54945dSmrg       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
26321d54945dSmrg     {
26331d54945dSmrg     if(ps3v->pci_burst)
26341d54945dSmrg       /*new->CR3A = (tmp & 0x38) | 0x10; / ENH 256, PCI burst */
26351d54945dSmrg       /* Don't clear reserved bits... */
26361d54945dSmrg        new->CR3A = (tmp & 0x7f) | 0x10; /* ENH 256, PCI burst */
26371d54945dSmrg     else
26381d54945dSmrg        new->CR3A = tmp | 0x90;      /* ENH 256, no PCI burst! */
26391d54945dSmrg     }
26401d54945dSmrg   else
26411d54945dSmrg     {
26421d54945dSmrg     if(ps3v->pci_burst)
26431d54945dSmrg        new->CR3A = (tmp & 0x7f) | 0x15; /* ENH 256, PCI burst */
26441d54945dSmrg     else
26451d54945dSmrg        new->CR3A = tmp | 0x95;      /* ENH 256, no PCI burst! */
26461d54945dSmrg     }
26471d54945dSmrg
26481d54945dSmrg
26491d54945dSmrg   VGAOUT8(vgaCRIndex, 0x55);
26501d54945dSmrg   new->CR55 = VGAIN8(vgaCRReg);
26511d54945dSmrg   if (ps3v->hwcursor)
26521d54945dSmrg     new->CR55 |= 0x10;  /* Enables X11 hw cursor mode */
26531d54945dSmrg   if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
26541d54945dSmrg     new->CR31 = 0x0c;               /* [trio3d] page 54 */
26551d54945dSmrg   } else {
26561d54945dSmrg     new->CR53 = 0x08;     /* Enables MMIO */
26571d54945dSmrg     new->CR31 = 0x8c;     /* Dis. 64k window, en. ENH maps */
26581d54945dSmrg   }
26591d54945dSmrg
26601d54945dSmrg   /* Enables S3D graphic engine and PCI disconnects */
26611d54945dSmrg   if(ps3v->Chipset == S3_ViRGE_VX){
26621d54945dSmrg      new->CR66 = 0x90;
26631d54945dSmrg      new->CR63 = 0x09;
26641d54945dSmrg      }
26651d54945dSmrg   else {
26661d54945dSmrg     new->CR66 = 0x89;
26671d54945dSmrg     /* Set display fifo */
26681d54945dSmrg     if( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
26691d54945dSmrg	 S3_ViRGE_MX_SERIES(ps3v->Chipset) )
26701d54945dSmrg       {
26711d54945dSmrg	 /* Changed from 0x08 based on reports that this */
26721d54945dSmrg	 /* prevents MX from running properly below 1024x768 */
26731d54945dSmrg	 new->CR63 = 0x10;
26741d54945dSmrg       }
26751d54945dSmrg     else
26761d54945dSmrg       {
26771d54945dSmrg	 new->CR63 = 0;
26781d54945dSmrg       }
26791d54945dSmrg      }
26801d54945dSmrg
26811d54945dSmrg  /* Now set linear addr. registers */
26821d54945dSmrg  /* LAW size: we have 2 cases, 2MB, 4MB or >= 4MB for VX */
26831d54945dSmrg   VGAOUT8(vgaCRIndex, 0x58);
26841d54945dSmrg   new->CR58 = VGAIN8(vgaCRReg) & 0x80;
26851d54945dSmrg   if(pScrn->videoRam == 2048){
26861d54945dSmrg      new->CR58 |= 0x02 | 0x10;
26871d54945dSmrg      }
26881d54945dSmrg   else if (pScrn->videoRam == 1024) {
26891d54945dSmrg      new->CR58 |= 0x01 | 0x10;
26901d54945dSmrg   }
26911d54945dSmrg   else {
26921d54945dSmrg     if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) && pScrn->videoRam == 8192)
26931d54945dSmrg       new->CR58 |= 0x07 | 0x10; /* 8MB window on Trio3D/2X */
26941d54945dSmrg     else
26951d54945dSmrg       new->CR58 |= 0x03 | 0x10; /* 4MB window on virge, 8MB on VX */
26961d54945dSmrg      }
26971d54945dSmrg   if(ps3v->Chipset == S3_ViRGE_VX)
26981d54945dSmrg      new->CR58 |= 0x40;
26991d54945dSmrg   if (ps3v->early_ras_precharge)
27001d54945dSmrg      new->CR58 |= 0x80;
27011d54945dSmrg   if (ps3v->late_ras_precharge)
27021d54945dSmrg      new->CR58 &= 0x7f;
27031d54945dSmrg
27041d54945dSmrg  /* ** On PCI bus, no need to reprogram the linear window base address */
27051d54945dSmrg
27061d54945dSmrg  /* Now do clock PLL programming. Use the s3gendac function to get m,n */
27071d54945dSmrg  /* Also determine if we need doubling etc. */
27081d54945dSmrg
27091d54945dSmrg   dclk = mode->Clock;
27101d54945dSmrg   new->CR67 = 0x00;             /* Defaults */
27111d54945dSmrg
27121d54945dSmrg   if (!S3_TRIO_3D_SERIES(ps3v->Chipset))
27131d54945dSmrg     new->SR15 = 0x03 | 0x80;
27141d54945dSmrg   else {
27151d54945dSmrg     VGAOUT8(0x3c4, 0x15);
27161d54945dSmrg     new->SR15 = VGAIN8(0x3c5);
27171d54945dSmrg     VGAOUT8(0x3c4, 0x0a);
27181d54945dSmrg     new->SR0A = VGAIN8(0x3c5);
27191d54945dSmrg     if (ps3v->slow_dram) {
27201d54945dSmrg       new->SR15 = 0x03;  /* 3 CYC MWR */
27211d54945dSmrg       new->SR0A &= 0x7F;
27221d54945dSmrg     } else if (ps3v->fast_dram) {
27231d54945dSmrg       new->SR15 = 0x03 | 0x80; /* 2 CYC MWR */
27241d54945dSmrg       new->SR0A |= 0x80;
27251d54945dSmrg     } else { /* keep BIOS init defaults */
27261d54945dSmrg       new->SR15 = (new->SR15 & 0x80) | 0x03;
27271d54945dSmrg     }
27281d54945dSmrg   }
27291d54945dSmrg   new->SR18 = 0x00;
27301d54945dSmrg   new->CR43 = 0x00;
27311d54945dSmrg   new->CR45 = 0x00;
27321d54945dSmrg   				/* Enable MMIO to RAMDAC registers */
27331d54945dSmrg   new->CR65 = 0x00;		/* CR65_2 must be zero, doc seems to be wrong */
27341d54945dSmrg   new->CR54 = 0x00;
27351d54945dSmrg
27361d54945dSmrg   if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
27371d54945dSmrg	/* S3_ViRGE_MX_SERIES(ps3v->Chipset) || CR40 reserved on MX */
27381d54945dSmrg	S3_ViRGE_MXP_SERIES(ps3v->Chipset) ||
27391d54945dSmrg	S3_ViRGE_VX_SERIES(ps3v->Chipset) ||
27401d54945dSmrg	/* S3_TRIO_3D_2X_SERIES(ps3v->Chipset) * included in GX2 series */
27411d54945dSmrg	ps3v->Chipset == S3_ViRGE_DXGX ||
27421d54945dSmrg	ps3v->Chipset == S3_ViRGE
27431d54945dSmrg	) {
27441d54945dSmrg     VGAOUT8(vgaCRIndex, 0x40);
27451d54945dSmrg     new->CR40 = VGAIN8(vgaCRReg) & ~0x01;
27461d54945dSmrg   }
27471d54945dSmrg
27481d54945dSmrg   if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
27491d54945dSmrg     /* fix problems with APM suspend/resume trashing CR90/91 */
27501d54945dSmrg     switch(pScrn->bitsPerPixel) {
27511d54945dSmrg       case  8: new->CR41 = 0x38; break;
27521d54945dSmrg       case 15: new->CR41 = 0x58; break;
27531d54945dSmrg       case 16: new->CR41 = 0x48; break;
27541d54945dSmrg       default: new->CR41 = 0x77;
27551d54945dSmrg     }
27561d54945dSmrg   }
27571d54945dSmrg
27581d54945dSmrg    xf86ErrorFVerb(VERBLEV, "	S3VModeInit dclk=%i \n",
27591d54945dSmrg   	dclk
27601d54945dSmrg	);
27611d54945dSmrg
27621d54945dSmrg   /* Memory controller registers. Optimize for better graphics engine
27631d54945dSmrg    * performance. These settings are adjusted/overridden below for other bpp/
27641d54945dSmrg    * XConfig options.The idea here is to give a longer number of contiguous
27651d54945dSmrg    * MCLK's to both refresh and the graphics engine, to diminish the
27661d54945dSmrg    * relative penalty of 3 or 4 mclk's needed to setup memory transfers.
27671d54945dSmrg    */
27681d54945dSmrg   new->MMPR0 = 0x010400; /* defaults */
27691d54945dSmrg   new->MMPR1 = 0x00;
27701d54945dSmrg   new->MMPR2 = 0x0808;
27711d54945dSmrg   new->MMPR3 = 0x08080810;
27721d54945dSmrg
27731d54945dSmrg   /*
27741d54945dSmrg    * These settings look like they ought to be better adjusted for depth,
27751d54945dSmrg    * so for problem modes running without any fifo_ option should be
27761d54945dSmrg    * usable.  Note that these adjust some memory timings and relate to
27771d54945dSmrg    * the boards MCLK setting.
27781d54945dSmrg    * */
27791d54945dSmrg    if( ps3v->fifo_aggressive || ps3v->fifo_moderate ||
27801d54945dSmrg       ps3v->fifo_conservative ) {
27811d54945dSmrg
27821d54945dSmrg         new->MMPR1 = 0x0200;   /* Low P. stream waits before filling */
27831d54945dSmrg         new->MMPR2 = 0x1808;   /* Let the FIFO refill itself */
27841d54945dSmrg         new->MMPR3 = 0x08081810; /* And let the GE hold the bus for a while */
27851d54945dSmrg      }
27861d54945dSmrg
27871d54945dSmrg   /* And setup here the new value for MCLK. We use the XConfig
27881d54945dSmrg    * option "set_mclk", whose value gets stored in ps3v->MCLK.
27891d54945dSmrg    * I'm not sure what the maximum "permitted" value should be, probably
27901d54945dSmrg    * 100 MHz is more than enough for now.
27911d54945dSmrg    */
27921d54945dSmrg
27931d54945dSmrg   if(ps3v->MCLK> 0) {
27941d54945dSmrg       if (S3_ViRGE_MX_SERIES(ps3v->Chipset))
27951d54945dSmrg	  S3VCommonCalcClock(pScrn, mode,
27961d54945dSmrg			     (int)(ps3v->MCLK / ps3v->refclk_fact),
27971d54945dSmrg			     1, 1, 31, 0, 3,
27981d54945dSmrg			     135000, 270000, &new->SR11, &new->SR10);
27991d54945dSmrg       else
28001d54945dSmrg	  S3VCommonCalcClock(pScrn, mode, ps3v->MCLK, 1, 1, 31, 0, 3,
28011d54945dSmrg			     135000, 270000, &new->SR11, &new->SR10);
28021d54945dSmrg       }
28031d54945dSmrg   else {
28041d54945dSmrg       new->SR10 = 255; /* This is a reserved value, so we use as flag */
28051d54945dSmrg       new->SR11 = 255;
28061d54945dSmrg       }
28071d54945dSmrg
28081d54945dSmrg   					/* most modes don't need STREAMS */
28091d54945dSmrg					/* processor, preset FALSE */
28101d54945dSmrg   /* support for XVideo needs streams, so added it to some modes */
28111d54945dSmrg   ps3v->NeedSTREAMS = FALSE;
28121d54945dSmrg
28131d54945dSmrg   if(ps3v->Chipset == S3_ViRGE_VX){
28141d54945dSmrg       if (pScrn->bitsPerPixel == 8) {
28151d54945dSmrg          if (dclk <= 110000) new->CR67 = 0x00; /* 8bpp, 135MHz */
28161d54945dSmrg          else new->CR67 = 0x10;                /* 8bpp, 220MHz */
28171d54945dSmrg          }
28181d54945dSmrg       else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) {
28191d54945dSmrg          if (dclk <= 110000) new->CR67 = 0x20; /* 15bpp, 135MHz */
28201d54945dSmrg          else new->CR67 = 0x30;                /* 15bpp, 220MHz */
28211d54945dSmrg          }
28221d54945dSmrg       else if (pScrn->bitsPerPixel == 16) {
28231d54945dSmrg          if (dclk <= 110000) new->CR67 = 0x40; /* 16bpp, 135MHz */
28241d54945dSmrg          else new->CR67 = 0x50;                /* 16bpp, 220MHz */
28251d54945dSmrg          }
28261d54945dSmrg       else if ((pScrn->bitsPerPixel == 24) || (pScrn->bitsPerPixel == 32)) {
28271d54945dSmrg          new->CR67 = 0xd0 | 0x0c;              /* 24bpp, 135MHz, STREAMS */
28281d54945dSmrg	  					/* Flag STREAMS proc. required */
28291d54945dSmrg          ps3v->NeedSTREAMS = TRUE;
28301d54945dSmrg          S3VInitSTREAMS(pScrn, new->STREAMS, mode);
28311d54945dSmrg          new->MMPR0 = 0xc098;            /* Adjust FIFO slots */
28321d54945dSmrg          }
28331d54945dSmrg       S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 4,
28341d54945dSmrg	   220000, 440000, &new->SR13, &new->SR12);
28351d54945dSmrg
28361d54945dSmrg      } /* end VX if() */
28371d54945dSmrg   else if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
28381d54945dSmrg       if (pScrn->bitsPerPixel == 8)
28391d54945dSmrg	  new->CR67 = 0x00;
28401d54945dSmrg       else if (pScrn->bitsPerPixel == 16) {
28411d54945dSmrg	 /* XV support needs STREAMS in depth 16 */
28421d54945dSmrg          ps3v->NeedSTREAMS = TRUE;
28431d54945dSmrg          S3VInitSTREAMS(pScrn, new->STREAMS, mode);
28441d54945dSmrg	  if (pScrn->weight.green == 5)
28451d54945dSmrg	     new->CR67 = 0x30 | 0x4;                  /* 15bpp */
28461d54945dSmrg	  else
28471d54945dSmrg	     new->CR67 = 0x50 | 0x4;                  /* 16bpp */
28481d54945dSmrg          }
28491d54945dSmrg       else if ((pScrn->bitsPerPixel == 24) ) {
28501d54945dSmrg	 new->CR67 = 0x74;              /* 24bpp, STREAMS */
28511d54945dSmrg	  					/* Flag STREAMS proc. required */
28521d54945dSmrg          ps3v->NeedSTREAMS = TRUE;
28531d54945dSmrg          S3VInitSTREAMS(pScrn, new->STREAMS, mode);
28541d54945dSmrg          }
28551d54945dSmrg       else if (pScrn->bitsPerPixel == 32) {
28561d54945dSmrg          new->CR67 = 0xd0;              /* 32bpp */
28571d54945dSmrg	  	/* Missing STREAMs and other stuff here? KJB */
28581d54945dSmrg          /* new->MMPR0 = 0xc098;            / Adjust FIFO slots */
28591d54945dSmrg          }
28601d54945dSmrg       {
28611d54945dSmrg         unsigned char ndiv;
28621d54945dSmrg	 if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
28631d54945dSmrg	   unsigned char sr8;
28641d54945dSmrg	   VGAOUT8(0x3c4, 0x08);  /* unlock extended SEQ regs */
28651d54945dSmrg	   sr8 = VGAIN8(0x3c5);
28661d54945dSmrg	   VGAOUT8(0x3c5, 0x06);
28671d54945dSmrg	   VGAOUT8(0x3c4, 0x31);
28681d54945dSmrg	   if (VGAIN8(0x3c5) & 0x10) { /* LCD on */
28691d54945dSmrg	     if (!ps3v->LCDClk) {  /* entered only once for first mode */
28701d54945dSmrg	       int h_lcd, v_lcd;
28711d54945dSmrg	       VGAOUT8(0x3c4, 0x61);
28721d54945dSmrg	       h_lcd = VGAIN8(0x3c5);
28731d54945dSmrg	       VGAOUT8(0x3c4, 0x66);
28741d54945dSmrg	       h_lcd |= ((VGAIN8(0x3c5) & 0x02) << 7);
28751d54945dSmrg	       h_lcd = (h_lcd+1) * 8;
28761d54945dSmrg	       VGAOUT8(0x3c4, 0x69);
28771d54945dSmrg	       v_lcd = VGAIN8(0x3c5);
28781d54945dSmrg	       VGAOUT8(0x3c4, 0x6e);
28791d54945dSmrg	       v_lcd |= ((VGAIN8(0x3c5) & 0x70) << 4);
28801d54945dSmrg	       v_lcd++;
28811d54945dSmrg
28821d54945dSmrg	       /* check if first mode has physical LCD resolution */
28831d54945dSmrg	       if (pScrn->modes->HDisplay == h_lcd && pScrn->modes->VDisplay == v_lcd)
28841d54945dSmrg		 ps3v->LCDClk = mode->Clock;
28851d54945dSmrg	       else {
28861d54945dSmrg		 int n1, n2, sr12, sr13, sr29;
28871d54945dSmrg		 VGAOUT8(0x3c4, 0x12);
28881d54945dSmrg		 sr12 = VGAIN8(0x3c5);
28891d54945dSmrg		 VGAOUT8(0x3c4, 0x13);
28901d54945dSmrg		 sr13 = VGAIN8(0x3c5) & 0x7f;
28911d54945dSmrg		 VGAOUT8(0x3c4, 0x29);
28921d54945dSmrg		 sr29 = VGAIN8(0x3c5);
28931d54945dSmrg		 n1 = sr12 & 0x1f;
28941d54945dSmrg		 n2 = ((sr12>>6) & 0x03) | ((sr29 & 0x01) << 2);
28951d54945dSmrg		 ps3v->LCDClk = ((int)(ps3v->refclk_fact * 1431818 * (sr13+2)) / (n1+2) / (1 << n2) + 50) / 100;
28961d54945dSmrg	       }
28971d54945dSmrg	     }
28981d54945dSmrg	     S3VCommonCalcClock(pScrn, mode,
28991d54945dSmrg			     (int)(ps3v->LCDClk / ps3v->refclk_fact),
29001d54945dSmrg			     1, 1, 31, 0, 4,
29011d54945dSmrg			     170000, 340000, &new->SR13, &ndiv);
29021d54945dSmrg	   }
29031d54945dSmrg	   else
29041d54945dSmrg	     S3VCommonCalcClock(pScrn, mode,
29051d54945dSmrg			     (int)(dclk / ps3v->refclk_fact),
29061d54945dSmrg			     1, 1, 31, 0, 4,
29071d54945dSmrg			     170000, 340000, &new->SR13, &ndiv);
29081d54945dSmrg	   VGAOUT8(0x3c4, 0x08);
29091d54945dSmrg	   VGAOUT8(0x3c5, sr8);
29101d54945dSmrg	 }
29111d54945dSmrg	 else  /* S3_ViRGE_GX2 */
29121d54945dSmrg	   S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 4,
29131d54945dSmrg			   170000, 340000, &new->SR13, &ndiv);
29141d54945dSmrg         new->SR29 = ndiv >> 7;
29151d54945dSmrg         new->SR12 = (ndiv & 0x1f) | ((ndiv & 0x60) << 1);
29161d54945dSmrg       }
29171d54945dSmrg   } /* end GX2 or MX if() */
29181d54945dSmrg   else if(S3_TRIO_3D_SERIES(ps3v->Chipset)) {
29191d54945dSmrg      new->SR0F = 0x00;
29201d54945dSmrg      if (pScrn->bitsPerPixel == 8) {
29211d54945dSmrg         if(dclk > 115000) {                     /* We need pixmux */
29221d54945dSmrg            new->CR67 = 0x10;
29231d54945dSmrg            new->SR15 |= 0x10;                   /* Set DCLK/2 bit */
29241d54945dSmrg            new->SR18 = 0x80;                   /* Enable pixmux */
29251d54945dSmrg        }
29261d54945dSmrg      }
29271d54945dSmrg      else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) {
29281d54945dSmrg        if(dclk > 115000) {
29291d54945dSmrg           new->CR67 = 0x20;
29301d54945dSmrg           new->SR15 |= 0x10;
29311d54945dSmrg           new->SR18 = 0x80;
29321d54945dSmrg	   new->SR0F = 0x10;
29331d54945dSmrg        } else {
29341d54945dSmrg           new->CR67 = 0x30;                       /* 15bpp */
29351d54945dSmrg        }
29361d54945dSmrg      }
29371d54945dSmrg      else if (pScrn->bitsPerPixel == 16) {
29381d54945dSmrg        if(dclk > 115000) {
29391d54945dSmrg            new->CR67 = 0x40;
29401d54945dSmrg            new->SR15 |= 0x10;
29411d54945dSmrg            new->SR18 = 0x80;
29421d54945dSmrg	    new->SR0F = 0x10;
29431d54945dSmrg        } else {
29441d54945dSmrg           new->CR67 = 0x50;
29451d54945dSmrg        }
29461d54945dSmrg      }
29471d54945dSmrg      else if (pScrn->bitsPerPixel == 24) {
29481d54945dSmrg         new->CR67 = 0xd0 | 0x0c;
29491d54945dSmrg	 ps3v->NeedSTREAMS = TRUE;
29501d54945dSmrg         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
29511d54945dSmrg         new->MMPR0 = 0xc000;            /* Adjust FIFO slots */
29521d54945dSmrg      }
29531d54945dSmrg      else if (pScrn->bitsPerPixel == 32) {
29541d54945dSmrg         new->CR67 = 0xd0 | 0x0c;
29551d54945dSmrg	 ps3v->NeedSTREAMS = TRUE;
29561d54945dSmrg         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
29571d54945dSmrg         new->MMPR0 = 0x10000;            /* Still more FIFO slots */
29581d54945dSmrg	 new->SR0F = 0x10;
29591d54945dSmrg      }
29601d54945dSmrg      S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 4,
29611d54945dSmrg                     230000, 460000, &new->SR13, &new->SR12);
29621d54945dSmrg   } /* end TRIO_3D if() */
29631d54945dSmrg   else if(ps3v->Chipset == S3_ViRGE_DXGX) {
29641d54945dSmrg      if (pScrn->bitsPerPixel == 8) {
29651d54945dSmrg         if(dclk > 80000) {                     /* We need pixmux */
29661d54945dSmrg            new->CR67 = 0x10;
29671d54945dSmrg            new->SR15 |= 0x10;                   /* Set DCLK/2 bit */
29681d54945dSmrg            new->SR18 = 0x80;                   /* Enable pixmux */
29691d54945dSmrg            }
29701d54945dSmrg         }
29711d54945dSmrg      else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) {
29721d54945dSmrg         new->CR67 = 0x30;                       /* 15bpp */
29731d54945dSmrg         }
29741d54945dSmrg      else if (pScrn->bitsPerPixel == 16) {
29751d54945dSmrg	if(mode->Flags & V_DBLSCAN)
29761d54945dSmrg	  {
29771d54945dSmrg	    new->CR67 = 0x50;
29781d54945dSmrg	  }
29791d54945dSmrg	else
29801d54945dSmrg	  {
29811d54945dSmrg	    new->CR67 = 0x50 | 0x0c;
29821d54945dSmrg	    /* Flag STREAMS proc. required */
29831d54945dSmrg	    /* XV support needs STREAMS in depth 16 */
29841d54945dSmrg	    ps3v->NeedSTREAMS = TRUE;
29851d54945dSmrg	    S3VInitSTREAMS(pScrn, new->STREAMS, mode);
29861d54945dSmrg	  }
29871d54945dSmrg	 if( ps3v->XVideo )
29881d54945dSmrg	   {
29891d54945dSmrg	     new->MMPR0 = 0x107c02;            /* Adjust FIFO slots, overlay */
29901d54945dSmrg	   }
29911d54945dSmrg	 else
29921d54945dSmrg	   {
29931d54945dSmrg	     new->MMPR0 = 0xc000;            /* Adjust FIFO slots */
29941d54945dSmrg	   }
29951d54945dSmrg         }
29961d54945dSmrg      else if (pScrn->bitsPerPixel == 24) {
29971d54945dSmrg         new->CR67 = 0xd0 | 0x0c;
29981d54945dSmrg	  					/* Flag STREAMS proc. required */
29991d54945dSmrg         ps3v->NeedSTREAMS = TRUE;
30001d54945dSmrg         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
30011d54945dSmrg	 if( ps3v->XVideo )
30021d54945dSmrg	   {
30031d54945dSmrg	     new->MMPR0 = 0x107c02;            /* Adjust FIFO slots, overlay */
30041d54945dSmrg	   }
30051d54945dSmrg	 else
30061d54945dSmrg	   {
30071d54945dSmrg	     new->MMPR0 = 0xc000;            /* Adjust FIFO slots */
30081d54945dSmrg	   }
30091d54945dSmrg         }
30101d54945dSmrg      else if (pScrn->bitsPerPixel == 32) {
30111d54945dSmrg         new->CR67 = 0xd0 | 0x0c;
30121d54945dSmrg	  					/* Flag STREAMS proc. required */
30131d54945dSmrg         ps3v->NeedSTREAMS = TRUE;
30141d54945dSmrg         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
30151d54945dSmrg         new->MMPR0 = 0x10000;            /* Still more FIFO slots */
30161d54945dSmrg         }
30171d54945dSmrg      S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 3,
30181d54945dSmrg	135000, 270000, &new->SR13, &new->SR12);
30191d54945dSmrg   } /* end DXGX if() */
30201d54945dSmrg   else {           /* Everything else ... (only ViRGE) */
30211d54945dSmrg      if (pScrn->bitsPerPixel == 8) {
30221d54945dSmrg         if(dclk > 80000) {                     /* We need pixmux */
30231d54945dSmrg            new->CR67 = 0x10;
30241d54945dSmrg            new->SR15 |= 0x10;                   /* Set DCLK/2 bit */
30251d54945dSmrg            new->SR18 = 0x80;                   /* Enable pixmux */
30261d54945dSmrg            }
30271d54945dSmrg         }
30281d54945dSmrg      else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) {
30291d54945dSmrg         new->CR67 = 0x30;                       /* 15bpp */
30301d54945dSmrg         }
30311d54945dSmrg      else if (pScrn->bitsPerPixel == 16) {
30321d54945dSmrg         new->CR67 = 0x50;
30331d54945dSmrg         }
30341d54945dSmrg      else if (pScrn->bitsPerPixel == 24) {
30351d54945dSmrg         new->CR67 = 0xd0 | 0x0c;
30361d54945dSmrg	  					/* Flag STREAMS proc. required */
30371d54945dSmrg         ps3v->NeedSTREAMS = TRUE;
30381d54945dSmrg         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
30391d54945dSmrg	 new->MMPR0 = 0xc000;            /* Adjust FIFO slots */
30401d54945dSmrg         }
30411d54945dSmrg      else if (pScrn->bitsPerPixel == 32) {
30421d54945dSmrg         new->CR67 = 0xd0 | 0x0c;
30431d54945dSmrg	  					/* Flag STREAMS proc. required */
30441d54945dSmrg         ps3v->NeedSTREAMS = TRUE;
30451d54945dSmrg         S3VInitSTREAMS(pScrn, new->STREAMS, mode);
30461d54945dSmrg         new->MMPR0 = 0x10000;            /* Still more FIFO slots */
30471d54945dSmrg         }
30481d54945dSmrg      S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 3,
30491d54945dSmrg	135000, 270000, &new->SR13, &new->SR12);
30501d54945dSmrg      } /* end great big if()... */
30511d54945dSmrg
30521d54945dSmrg
30531d54945dSmrg   /* Now adjust the value of the FIFO based upon options specified */
30541d54945dSmrg   if( ps3v->fifo_moderate ) {
30551d54945dSmrg      if(pScrn->bitsPerPixel < 24)
30561d54945dSmrg         new->MMPR0 -= 0x8000;
30571d54945dSmrg      else
30581d54945dSmrg         new->MMPR0 -= 0x4000;
30591d54945dSmrg      }
30601d54945dSmrg   else if( ps3v->fifo_aggressive ) {
30611d54945dSmrg      if(pScrn->bitsPerPixel < 24)
30621d54945dSmrg         new->MMPR0 -= 0xc000;
30631d54945dSmrg      else
30641d54945dSmrg         new->MMPR0 -= 0x6000;
30651d54945dSmrg      }
30661d54945dSmrg
30671d54945dSmrg   /* If we have an interlace mode, set the interlace bit. Note that mode
30681d54945dSmrg    * vertical timings are already adjusted by the standard VGA code
30691d54945dSmrg    */
30701d54945dSmrg   if(mode->Flags & V_INTERLACE) {
30711d54945dSmrg        new->CR42 = 0x20; /* Set interlace mode */
30721d54945dSmrg        }
30731d54945dSmrg   else {
30741d54945dSmrg        new->CR42 = 0x00;
30751d54945dSmrg        }
30761d54945dSmrg
30771d54945dSmrg   if(S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
30781d54945dSmrg      S3_ViRGE_MX_SERIES(ps3v->Chipset) )
30791d54945dSmrg     {
30801d54945dSmrg       new->CR34 = 0;
30811d54945dSmrg     }
30821d54945dSmrg   else
30831d54945dSmrg     {
30841d54945dSmrg       /* Set display fifo */
30851d54945dSmrg       new->CR34 = 0x10;
30861d54945dSmrg     }
30871d54945dSmrg   /* Now we adjust registers for extended mode timings */
30881d54945dSmrg   /* This is taken without change from the accel/s3_virge code */
30891d54945dSmrg
30901d54945dSmrg   i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) |
30911d54945dSmrg       ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) |
30921d54945dSmrg       ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) |
30931d54945dSmrg       ((mode->CrtcHSyncStart & 0x800) >> 7);
30941d54945dSmrg
30951d54945dSmrg   if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64)
30961d54945dSmrg      i |= 0x08;   /* add another 64 DCLKs to blank pulse width */
30971d54945dSmrg
30981d54945dSmrg   if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32)
30991d54945dSmrg      i |= 0x20;   /* add another 32 DCLKs to hsync pulse width */
31001d54945dSmrg
31011d54945dSmrg   /* video playback chokes if sync start and display end are equal */
31021d54945dSmrg   if (mode->CrtcHSyncStart - mode->CrtcHDisplay < ps3v->HorizScaleFactor) {
31031d54945dSmrg       int tmp = vganew->CRTC[4] + ((i&0x10)<<4) + ps3v->HorizScaleFactor;
31041d54945dSmrg       vganew->CRTC[4] = tmp & 0xff;
31051d54945dSmrg       i |= ((tmp >> 4) & 0x10);
31061d54945dSmrg   }
31071d54945dSmrg
31081d54945dSmrg   j = (  vganew->CRTC[0] + ((i&0x01)<<8)
31091d54945dSmrg        + vganew->CRTC[4] + ((i&0x10)<<4) + 1) / 2;
31101d54945dSmrg
31111d54945dSmrg   if (j-(vganew->CRTC[4] + ((i&0x10)<<4)) < 4) {
31121d54945dSmrg      if (vganew->CRTC[4] + ((i&0x10)<<4) + 4 <= vganew->CRTC[0]+ ((i&0x01)<<8))
31131d54945dSmrg         j = vganew->CRTC[4] + ((i&0x10)<<4) + 4;
31141d54945dSmrg      else
31151d54945dSmrg         j = vganew->CRTC[0]+ ((i&0x01)<<8) + 1;
31161d54945dSmrg   }
31171d54945dSmrg   new->CR3B = j & 0xFF;
31181d54945dSmrg   i |= (j & 0x100) >> 2;
31191d54945dSmrg   new->CR3C = (vganew->CRTC[0] + ((i&0x01)<<8))/2;
31201d54945dSmrg   new->CR5D = i;
31211d54945dSmrg
31221d54945dSmrg   new->CR5E = (((mode->CrtcVTotal - 2) & 0x400) >> 10)  |
31231d54945dSmrg               (((mode->CrtcVDisplay - 1) & 0x400) >> 9) |
31241d54945dSmrg               (((mode->CrtcVSyncStart) & 0x400) >> 8)   |
31251d54945dSmrg               (((mode->CrtcVSyncStart) & 0x400) >> 6)   | 0x40;
31261d54945dSmrg
31271d54945dSmrg
31281d54945dSmrg   width = (pScrn->displayWidth * (pScrn->bitsPerPixel / 8))>> 3;
31291d54945dSmrg   vganew->CRTC[19] = 0xFF & width;
31301d54945dSmrg   new->CR51 = (0x300 & width) >> 4; /* Extension bits */
31311d54945dSmrg
31321d54945dSmrg   /* Set doublescan */
31331d54945dSmrg   if( mode->Flags & V_DBLSCAN)
31341d54945dSmrg     vganew->CRTC[9] |= 0x80;
31351d54945dSmrg
31361d54945dSmrg   /* And finally, select clock source 2 for programmable PLL */
31371d54945dSmrg   vganew->MiscOutReg |= 0x0c;
31381d54945dSmrg
31391d54945dSmrg
31401d54945dSmrg   new->CR33 = 0x20;
31411d54945dSmrg   if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) || S3_ViRGE_GX2_SERIES(ps3v->Chipset)
31421d54945dSmrg       /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )
31431d54945dSmrg   {
31441d54945dSmrg     new->CR85 = 0x12;  /* avoid sreen flickering */
31451d54945dSmrg      /* by increasing FIFO filling, larger # fills FIFO from memory earlier */
31461d54945dSmrg      /* on GX2 this affects all depths, not just those running STREAMS. */
31471d54945dSmrg      /* new, secondary stream settings. */
31481d54945dSmrg      new->CR87 = 0x10;
31491d54945dSmrg      /* gx2 - set up in XV init code */
31501d54945dSmrg      new->CR92 = 0x00;
31511d54945dSmrg      new->CR93 = 0x00;
31521d54945dSmrg      /* gx2 primary mclk timeout, def=0xb */
31531d54945dSmrg      new->CR7B = 0xb;
31541d54945dSmrg      /* gx2 secondary mclk timeout, def=0xb */
31551d54945dSmrg      new->CR7D = 0xb;
31561d54945dSmrg   }
31571d54945dSmrg   if (ps3v->Chipset == S3_ViRGE_DXGX || S3_TRIO_3D_SERIES(ps3v->Chipset)) {
31581d54945dSmrg      new->CR86 = 0x80;  /* disable DAC power saving to avoid bright left edge */
31591d54945dSmrg   }
31601d54945dSmrg   if (ps3v->Chipset == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
31611d54945dSmrg       S3_ViRGE_MX_SERIES(ps3v->Chipset) || S3_TRIO_3D_SERIES(ps3v->Chipset)) {
31621d54945dSmrg      int dbytes = pScrn->displayWidth * ((pScrn->bitsPerPixel+7)/8);
31631d54945dSmrg      new->CR91 =   (dbytes + 7) / 8;
31641d54945dSmrg      new->CR90 = (((dbytes + 7) / 8) >> 8) | 0x80;
31651d54945dSmrg   }
31661d54945dSmrg
31671d54945dSmrg
31681d54945dSmrg   /* Now we handle various XConfig memory options and others */
31691d54945dSmrg
31701d54945dSmrg   VGAOUT8(vgaCRIndex, 0x36);
31711d54945dSmrg   new->CR36 = VGAIN8(vgaCRReg);
31721d54945dSmrg   /* option "slow_edodram" sets EDO to 2 cycle mode on ViRGE */
31731d54945dSmrg   if (ps3v->Chipset == S3_ViRGE) {
31741d54945dSmrg      if( ps3v->slow_edodram )
31751d54945dSmrg         new->CR36 = (new->CR36 & 0xf3) | 0x08;
31761d54945dSmrg      else
31771d54945dSmrg         new->CR36 &= 0xf3;
31781d54945dSmrg      }
31791d54945dSmrg
31801d54945dSmrg   /* Option "fpm_vram" for ViRGE_VX sets memory in fast page mode */
31811d54945dSmrg   if (ps3v->Chipset == S3_ViRGE_VX) {
31821d54945dSmrg      if( ps3v->fpm_vram )
31831d54945dSmrg         new->CR36 |=  0x0c;
31841d54945dSmrg      else
31851d54945dSmrg         new->CR36 &= ~0x0c;
31861d54945dSmrg   }
31871d54945dSmrg
31881d54945dSmrg   				/* S3_INVERT_VCLK was defaulted to 0 	*/
31891d54945dSmrg				/* in 3.3.3 and never changed. 		*/
31901d54945dSmrg				/* Also, bit 0 is never set in 3.9Nm,	*/
31911d54945dSmrg				/* so I left this out for 4.0.			*/
31921d54945dSmrg#if 0
31931d54945dSmrg      if (mode->Private[0] & (1 << S3_INVERT_VCLK)) {
31941d54945dSmrg	 if (mode->Private[S3_INVERT_VCLK])
31951d54945dSmrg	    new->CR67 |= 1;
31961d54945dSmrg	 else
31971d54945dSmrg	    new->CR67 &= ~1;
31981d54945dSmrg      }
31991d54945dSmrg#endif
32001d54945dSmrg      				/* S3_BLANK_DELAY settings based on 	*/
32011d54945dSmrg				/* defaults only. From 3.3.3 		*/
32021d54945dSmrg   {
32031d54945dSmrg      int blank_delay;
32041d54945dSmrg
32051d54945dSmrg      if(ps3v->Chipset == S3_ViRGE_VX)
32061d54945dSmrg	    /* these values need to be changed once CR67_1 is set
32071d54945dSmrg	       for gamma correction (see S3V server) ! */
32081d54945dSmrg	    if (pScrn->bitsPerPixel == 8)
32091d54945dSmrg	       blank_delay = 0x00;
32101d54945dSmrg	    else if (pScrn->bitsPerPixel == 16)
32111d54945dSmrg	       blank_delay = 0x00;
32121d54945dSmrg	    else
32131d54945dSmrg	       blank_delay = 0x51;
32141d54945dSmrg      else
32151d54945dSmrg	    if (pScrn->bitsPerPixel == 8)
32161d54945dSmrg	       blank_delay = 0x00;
32171d54945dSmrg	    else if (pScrn->bitsPerPixel == 16)
32181d54945dSmrg	       blank_delay = 0x02;
32191d54945dSmrg	    else
32201d54945dSmrg	       blank_delay = 0x04;
32211d54945dSmrg
32221d54945dSmrg      if (ps3v->Chipset == S3_ViRGE_VX)
32231d54945dSmrg	    new->CR6D = blank_delay;
32241d54945dSmrg      else {
32251d54945dSmrg	    new->CR65 = (new->CR65 & ~0x38)
32261d54945dSmrg	       | (blank_delay & 0x07) << 3;
32271d54945dSmrg	    VGAOUT8(vgaCRIndex, 0x6d);
32281d54945dSmrg	    new->CR6D = VGAIN8(vgaCRReg);
32291d54945dSmrg      }
32301d54945dSmrg   }
32311d54945dSmrg   				/* S3_EARLY_SC was defaulted to 0 	*/
32321d54945dSmrg				/* in 3.3.3 and never changed. 		*/
32331d54945dSmrg				/* Also, bit 1 is never set in 3.9Nm,	*/
32341d54945dSmrg				/* so I left this out for 4.0.			*/
32351d54945dSmrg#if 0
32361d54945dSmrg      if (mode->Private[0] & (1 << S3_EARLY_SC)) {
32371d54945dSmrg	 if (mode->Private[S3_EARLY_SC])
32381d54945dSmrg	    new->CR65 |= 2;
32391d54945dSmrg	 else
32401d54945dSmrg	    new->CR65 &= ~2;
32411d54945dSmrg      }
32421d54945dSmrg#endif
32431d54945dSmrg
32441d54945dSmrg   VGAOUT8(vgaCRIndex, 0x68);
32451d54945dSmrg   new->CR68 = VGAIN8(vgaCRReg);
32461d54945dSmrg   new->CR69 = 0;
32471d54945dSmrg
32481d54945dSmrg   /* Flat panel centering and expansion registers */
32491d54945dSmrg   if (S3_ViRGE_MX_SERIES(ps3v->Chipset) && (ps3v->lcd_center)) {
32501d54945dSmrg     new->SR54 = 0x10 ;
32511d54945dSmrg     new->SR55 = 0x80 ;
32521d54945dSmrg     new->SR56 = 0x10 ;
32531d54945dSmrg     new->SR57 = 0x80 ;
32541d54945dSmrg   } else {
32551d54945dSmrg     new->SR54 = 0x1f ;
32561d54945dSmrg     new->SR55 = 0x9f ;
32571d54945dSmrg     new->SR56 = 0x1f ;
32581d54945dSmrg     new->SR57 = 0xff ;
32591d54945dSmrg   }
32601d54945dSmrg
32611d54945dSmrg   pScrn->vtSema = TRUE;
32621d54945dSmrg
32631d54945dSmrg   					/* Do it!  Write the mode registers */
32641d54945dSmrg					/* to hardware, start STREAMS if    */
32651d54945dSmrg					/* needed, etc.		    	    */
32661d54945dSmrg   S3VWriteMode( pScrn, vganew, new );
32671d54945dSmrg   					/* Adjust the viewport */
32685788ca14Smrg   S3VAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
32691d54945dSmrg
32701d54945dSmrg   return TRUE;
32711d54945dSmrg}
32721d54945dSmrg
32731d54945dSmrg
32741d54945dSmrg/*
32751d54945dSmrg * This is called at the end of each server generation.  It restores the
32761d54945dSmrg * original (text) mode.  It should also unmap the video memory, and free
32771d54945dSmrg * any per-generation data allocated by the driver.  It should finish
32781d54945dSmrg * by unwrapping and calling the saved CloseScreen function.
32791d54945dSmrg */
32801d54945dSmrg
32811d54945dSmrg/* Mandatory */
32821d54945dSmrgstatic Bool
32835788ca14SmrgS3VCloseScreen(CLOSE_SCREEN_ARGS_DECL)
32841d54945dSmrg{
32855788ca14Smrg  ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
32861d54945dSmrg  vgaHWPtr hwp = VGAHWPTR(pScrn);
32871d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
32881d54945dSmrg  vgaRegPtr vgaSavePtr = &hwp->SavedReg;
32891d54945dSmrg  S3VRegPtr S3VSavePtr = &ps3v->SavedReg;
32901d54945dSmrg
32911d54945dSmrg    					/* Like S3VRestore, but uses passed */
32921d54945dSmrg					/* mode registers.		    */
32931d54945dSmrg  if (pScrn->vtSema) {
32941d54945dSmrg      S3VWriteMode(pScrn, vgaSavePtr, S3VSavePtr);
32951d54945dSmrg      vgaHWLock(hwp);
32961d54945dSmrg      S3VDisableMmio(pScrn);
32971d54945dSmrg      S3VUnmapMem(pScrn);
32981d54945dSmrg  }
32991d54945dSmrg
33005788ca14Smrg#ifdef HAVE_XAA_H
33011d54945dSmrg  if (ps3v->AccelInfoRec)
33021d54945dSmrg    XAADestroyInfoRec(ps3v->AccelInfoRec);
33035788ca14Smrg#endif
33041d54945dSmrg  if (ps3v->DGAModes)
33055788ca14Smrg  	free(ps3v->DGAModes);
33061d54945dSmrg
33071d54945dSmrg  pScrn->vtSema = FALSE;
33081d54945dSmrg
33091d54945dSmrg  pScreen->CloseScreen = ps3v->CloseScreen;
33101d54945dSmrg
33115788ca14Smrg  return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
33121d54945dSmrg}
33131d54945dSmrg
33141d54945dSmrg
33151d54945dSmrg
33161d54945dSmrg
33171d54945dSmrg/* Do screen blanking */
33181d54945dSmrg
33191d54945dSmrg/* Mandatory */
33201d54945dSmrgstatic Bool
33211d54945dSmrgS3VSaveScreen(ScreenPtr pScreen, int mode)
33221d54945dSmrg{
33231d54945dSmrg  return vgaHWSaveScreen(pScreen, mode);
33241d54945dSmrg}
33251d54945dSmrg
33261d54945dSmrg
33271d54945dSmrg
33281d54945dSmrg
33291d54945dSmrg
33301d54945dSmrg/* This function inits the STREAMS processor variables.
33311d54945dSmrg * This has essentially been taken from the accel/s3_virge code and the databook.
33321d54945dSmrg */
33331d54945dSmrgstatic void
33341d54945dSmrgS3VInitSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams, DisplayModePtr mode)
33351d54945dSmrg{
33361d54945dSmrg  PVERB5("	S3VInitSTREAMS\n");
33371d54945dSmrg
33381d54945dSmrg  switch (pScrn->bitsPerPixel)
33391d54945dSmrg    {
33401d54945dSmrg    case 16:
33411d54945dSmrg      streams[0] = 0x05000000;
33421d54945dSmrg      break;
33431d54945dSmrg    case 24:
33441d54945dSmrg                         /* data format 8.8.8 (24 bpp) */
33451d54945dSmrg      streams[0] = 0x06000000;
33461d54945dSmrg      break;
33471d54945dSmrg    case 32:
33481d54945dSmrg                         /* one more bit for X.8.8.8, 32 bpp */
33491d54945dSmrg      streams[0] = 0x07000000;
33501d54945dSmrg      break;
33511d54945dSmrg    }
33521d54945dSmrg                         /* NO chroma keying... */
33531d54945dSmrg   streams[1] = 0x0;
33541d54945dSmrg                         /* Secondary stream format KRGB-16 */
33551d54945dSmrg                         /* data book suggestion... */
33561d54945dSmrg   streams[2] = 0x03000000;
33571d54945dSmrg
33581d54945dSmrg   streams[3] = 0x0;
33591d54945dSmrg
33601d54945dSmrg   streams[4] = 0x0;
33611d54945dSmrg                         /* use 0x01000000 for primary over second. */
33621d54945dSmrg                         /* use 0x0 for second over prim. */
33631d54945dSmrg   streams[5] = 0x01000000;
33641d54945dSmrg
33651d54945dSmrg   streams[6] = 0x0;
33661d54945dSmrg
33671d54945dSmrg   streams[7] = 0x0;
33681d54945dSmrg                                /* Stride is 3 bytes for 24 bpp mode and */
33691d54945dSmrg                                /* 4 bytes for 32 bpp. */
33701d54945dSmrg   switch(pScrn->bitsPerPixel)
33711d54945dSmrg     {
33721d54945dSmrg     case 16:
33731d54945dSmrg       streams[8] =
33741d54945dSmrg	 pScrn->displayWidth * 2;
33751d54945dSmrg       break;
33761d54945dSmrg     case 24:
33771d54945dSmrg       streams[8] =
33781d54945dSmrg	 pScrn->displayWidth * 3;
33791d54945dSmrg      break;
33801d54945dSmrg     case 32:
33811d54945dSmrg       streams[8] =
33821d54945dSmrg	 pScrn->displayWidth * 4;
33831d54945dSmrg      break;
33841d54945dSmrg     }
33851d54945dSmrg                                /* Choose fbaddr0 as stream source. */
33861d54945dSmrg   streams[9] = 0x0;
33871d54945dSmrg   streams[10] = 0x0;
33881d54945dSmrg   streams[11] = 0x0;
33891d54945dSmrg   streams[12] = 0x1;
33901d54945dSmrg
33911d54945dSmrg                                /* Set primary stream on top of secondary */
33921d54945dSmrg                                /* stream. */
33931d54945dSmrg   streams[13] = 0xc0000000;
33941d54945dSmrg                               /* Vertical scale factor. */
33951d54945dSmrg   streams[14] = 0x0;
33961d54945dSmrg
33971d54945dSmrg   streams[15] = 0x0;
33981d54945dSmrg                                /* Vertical accum. initial value. */
33991d54945dSmrg   streams[16] = 0x0;
34001d54945dSmrg                                /* X and Y start coords + 1. */
34011d54945dSmrg   streams[18] =  0x00010001;
34021d54945dSmrg
34031d54945dSmrg         /* Specify window Width -1 and Height of */
34041d54945dSmrg         /* stream. */
34051d54945dSmrg   streams[19] =
34061d54945dSmrg         (mode->HDisplay - 1) << 16 |
34071d54945dSmrg         (mode->VDisplay);
34081d54945dSmrg
34091d54945dSmrg                                /* Book says 0x07ff07ff. */
34101d54945dSmrg   streams[20] = 0x07ff07ff;
34111d54945dSmrg
34121d54945dSmrg   streams[21] = 0x00010001;
34131d54945dSmrg
34141d54945dSmrg}
34151d54945dSmrg
34161d54945dSmrg
34171d54945dSmrg
34181d54945dSmrg
34191d54945dSmrg/* Used to adjust start address in frame buffer. We use the new
34201d54945dSmrg * CR69 reg for this purpose instead of the older CR31/CR51 combo.
34211d54945dSmrg * If STREAMS is running, we program the STREAMS start addr. registers.
34221d54945dSmrg */
34231d54945dSmrg
34241d54945dSmrgvoid
34255788ca14SmrgS3VAdjustFrame(ADJUST_FRAME_ARGS_DECL)
34261d54945dSmrg{
34275788ca14Smrg   SCRN_INFO_PTR(arg);
34281d54945dSmrg   vgaHWPtr hwp = VGAHWPTR(pScrn);
34291d54945dSmrg   S3VPtr ps3v = S3VPTR(pScrn);
34301d54945dSmrg   int Base;
34311d54945dSmrg   int vgaCRIndex, vgaCRReg, vgaIOBase;
34321d54945dSmrg   vgaIOBase = hwp->IOBase;
34331d54945dSmrg   vgaCRIndex = vgaIOBase + 4;
34341d54945dSmrg   vgaCRReg = vgaIOBase + 5;
34351d54945dSmrg
34361d54945dSmrg   if(ps3v->ShowCache && y)
34371d54945dSmrg	y += pScrn->virtualY - 1;
34381d54945dSmrg
34391d54945dSmrg   if( (ps3v->STREAMSRunning == FALSE) ||
34401d54945dSmrg      S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) {
34411d54945dSmrg      Base = ((y * pScrn->displayWidth + x)
34421d54945dSmrg		* (pScrn->bitsPerPixel / 8)) >> 2;
34431d54945dSmrg      if (pScrn->bitsPerPixel == 24)
34441d54945dSmrg	Base = Base+2 - (Base+2) % 3;
34451d54945dSmrg      if (pScrn->bitsPerPixel == 16)
34461d54945dSmrg	if (S3_TRIO_3D_SERIES(ps3v->Chipset) && pScrn->modes->Clock > 115000)
34471d54945dSmrg	  Base &= ~1;
34481d54945dSmrg
34491d54945dSmrg      /* Now program the start address registers */
34501d54945dSmrg      VGAOUT16(vgaCRIndex, (Base & 0x00FF00) | 0x0C);
34511d54945dSmrg      VGAOUT16(vgaCRIndex, ((Base & 0x00FF) << 8) | 0x0D);
34521d54945dSmrg      VGAOUT8(vgaCRIndex, 0x69);
34531d54945dSmrg      VGAOUT8(vgaCRReg, (Base & 0x0F0000) >> 16);
34541d54945dSmrg      }
34551d54945dSmrg   else {          /* Change start address for STREAMS case */
34561d54945dSmrg      VerticalRetraceWait();
34571d54945dSmrg      if(ps3v->Chipset == S3_ViRGE_VX)
34581d54945dSmrg	OUTREG(PSTREAM_FBADDR0_REG,
34591d54945dSmrg		   ((y * pScrn->displayWidth + (x & ~7)) *
34601d54945dSmrg		    pScrn->bitsPerPixel / 8));
34611d54945dSmrg      else
34621d54945dSmrg	OUTREG(PSTREAM_FBADDR0_REG,
34631d54945dSmrg		   ((y * pScrn->displayWidth + (x & ~3)) *
34641d54945dSmrg		    pScrn->bitsPerPixel / 8));
34651d54945dSmrg      }
34661d54945dSmrg
34671d54945dSmrg   return;
34681d54945dSmrg}
34691d54945dSmrg
34701d54945dSmrg
34711d54945dSmrg
34721d54945dSmrg
34731d54945dSmrg/* Usually mandatory */
34741d54945dSmrgBool
34755788ca14SmrgS3VSwitchMode(SWITCH_MODE_ARGS_DECL)
34761d54945dSmrg{
34775788ca14Smrg    SCRN_INFO_PTR(arg);
34785788ca14Smrg    return S3VModeInit(pScrn, mode);
34791d54945dSmrg}
34801d54945dSmrg
34811d54945dSmrg
34821d54945dSmrg
34831d54945dSmrgvoid S3VLoadPalette(
34841d54945dSmrg    ScrnInfoPtr pScrn,
34851d54945dSmrg    int numColors,
34860b7217d9Smrg    int *indices,
34871d54945dSmrg    LOCO *colors,
34881d54945dSmrg    VisualPtr pVisual
34891d54945dSmrg){
34901d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
34911d54945dSmrg    int i, index;
34921d54945dSmrg
34931d54945dSmrg    for(i = 0; i < numColors; i++) {
34940b7217d9Smrg	index = indices[i];
34951d54945dSmrg        VGAOUT8(0x3c8, index);
34961d54945dSmrg        VGAOUT8(0x3c9, colors[index].red);
34971d54945dSmrg        VGAOUT8(0x3c9, colors[index].green);
34981d54945dSmrg        VGAOUT8(0x3c9, colors[index].blue);
34991d54945dSmrg    }
35001d54945dSmrg}
35011d54945dSmrg
35021d54945dSmrg
35031d54945dSmrg/*
35041d54945dSmrg * Functions to support getting a ViRGE card into MMIO mode if it fails to
35051d54945dSmrg * default to MMIO enabled.
35061d54945dSmrg */
35071d54945dSmrg
35081d54945dSmrgvoid
35091d54945dSmrgS3VEnableMmio(ScrnInfoPtr pScrn)
35101d54945dSmrg{
35111d54945dSmrg  vgaHWPtr hwp;
35121d54945dSmrg  S3VPtr ps3v;
351344802259Smrg  unsigned int vgaCRIndex, vgaCRReg;
35141d54945dSmrg  unsigned char val;
35155788ca14Smrg  unsigned int PIOOffset = 0;
35165788ca14Smrg
35171d54945dSmrg  PVERB5("	S3VEnableMmio\n");
35181d54945dSmrg
35191d54945dSmrg  hwp = VGAHWPTR(pScrn);
35201d54945dSmrg  ps3v = S3VPTR(pScrn);
35215788ca14Smrg
35225788ca14Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
35235788ca14Smrg  PIOOffset = hwp->PIOOffset;
35245788ca14Smrg#endif
35255788ca14Smrg
35261d54945dSmrg  /*
35271d54945dSmrg   * enable chipset (seen on uninitialized secondary cards)
35281d54945dSmrg   * might not be needed once we use the VGA softbooter
35291d54945dSmrg   * (EE 05/04/99)
35301d54945dSmrg   */
35311d54945dSmrg  vgaHWSetStdFuncs(hwp);
35321d54945dSmrg  /*
35331d54945dSmrg   * any access to the legacy VGA ports is done here.
35340b7217d9Smrg   * If legacy VGA is inaccessible the MMIO base _has_
35351d54945dSmrg   * to be set correctly already and MMIO _has_ to be
35361d54945dSmrg   * enabled.
35371d54945dSmrg   */
35385788ca14Smrg  val = inb(PIOOffset + 0x3C3);               /*@@@EE*/
35395788ca14Smrg  outb(PIOOffset + 0x3C3, val | 0x01);
35401d54945dSmrg  /*
35411d54945dSmrg   * set CR registers to color mode
35421d54945dSmrg   * in mono mode extended CR registers
35431d54945dSmrg   * are not accessible. (EE 05/04/99)
35441d54945dSmrg   */
35455788ca14Smrg  val = inb(PIOOffset + VGA_MISC_OUT_R);      /*@@@EE*/
35465788ca14Smrg  outb(PIOOffset + VGA_MISC_OUT_W, val | 0x01);
35471d54945dSmrg  vgaHWGetIOBase(hwp);             	/* Get VGA I/O base */
35485788ca14Smrg  vgaCRIndex = PIOOffset + hwp->IOBase + 4;
35491d54945dSmrg  vgaCRReg = vgaCRIndex + 1;
35501d54945dSmrg#if 1
35511d54945dSmrg  /*
35521d54945dSmrg   * set linear base register to the PCI register values
35531d54945dSmrg   * some DX chipsets don't seem to do it automatically
35541d54945dSmrg   * (EE 06/03/99)
35551d54945dSmrg   */
35561d54945dSmrg  outb(vgaCRIndex, 0x59);         /*@@@EE*/
3557ba85709eSmrg  outb(vgaCRReg, PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) >> 24);
35581d54945dSmrg  outb(vgaCRIndex, 0x5A);
3559ba85709eSmrg  outb(vgaCRReg, PCI_REGION_BASE(ps3v->PciInfo, 0, REGION_MEM) >> 16);
35601d54945dSmrg  outb(vgaCRIndex, 0x53);
35611d54945dSmrg#endif
35621d54945dSmrg  /* Save register for restore */
35631d54945dSmrg  ps3v->EnableMmioCR53 = inb(vgaCRReg);
35641d54945dSmrg  			      	/* Enable new MMIO, if TRIO mmio is already */
35651d54945dSmrg				/* enabled, then it stays enabled. */
35661d54945dSmrg  outb(vgaCRReg, ps3v->EnableMmioCR53 | 0x08);
35675788ca14Smrg  outb(PIOOffset + VGA_MISC_OUT_W, val);
35681d54945dSmrg  if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
35691d54945dSmrg    outb(vgaCRIndex, 0x40);
35701d54945dSmrg    val = inb(vgaCRReg);
35711d54945dSmrg    outb(vgaCRReg, val | 1);
35721d54945dSmrg  }
35731d54945dSmrg}
35741d54945dSmrg
35751d54945dSmrg
35761d54945dSmrg
35771d54945dSmrgvoid
35781d54945dSmrgS3VDisableMmio(ScrnInfoPtr pScrn)
35791d54945dSmrg{
35801d54945dSmrg  vgaHWPtr hwp;
35811d54945dSmrg  S3VPtr ps3v;
358244802259Smrg  unsigned int vgaCRIndex, vgaCRReg;
35831d54945dSmrg
35841d54945dSmrg  PVERB5("	S3VDisableMmio\n");
35851d54945dSmrg
35861d54945dSmrg  hwp = VGAHWPTR(pScrn);
35871d54945dSmrg  ps3v = S3VPTR(pScrn);
35881d54945dSmrg
35895788ca14Smrg  vgaCRIndex = hwp->IOBase + 4;
35905788ca14Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
35915788ca14Smrg  vgaCRIndex += hwp->PIOOffset;
35925788ca14Smrg#endif
35931d54945dSmrg  vgaCRReg = vgaCRIndex + 1;
35941d54945dSmrg  outb(vgaCRIndex, 0x53);
35951d54945dSmrg				/* Restore register's original state */
35961d54945dSmrg  outb(vgaCRReg, ps3v->EnableMmioCR53);
35971d54945dSmrg  if (S3_TRIO_3D_SERIES(ps3v->Chipset)) {
35981d54945dSmrg    unsigned char val;
35991d54945dSmrg    outb(vgaCRIndex, 0x40);
36001d54945dSmrg    val = inb(vgaCRReg);
36011d54945dSmrg    outb(vgaCRReg, val | 1);
36021d54945dSmrg  }
36031d54945dSmrg}
36041d54945dSmrg
36051d54945dSmrg
36061d54945dSmrg
36071d54945dSmrg/* This function is used to debug, it prints out the contents of s3 regs */
36081d54945dSmrg
36091d54945dSmrgstatic void
36101d54945dSmrgS3VPrintRegs(ScrnInfoPtr pScrn)
36111d54945dSmrg{
36121d54945dSmrg    unsigned char tmp1, tmp2;
36131d54945dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
36141d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
36151d54945dSmrg    int vgaCRIndex, vgaCRReg, vgaIOBase, vgaIR;
36161d54945dSmrg    vgaIOBase = hwp->IOBase;
36171d54945dSmrg    vgaCRIndex = vgaIOBase + 4;
36181d54945dSmrg    vgaCRReg = vgaIOBase + 5;
36191d54945dSmrg    vgaIR = vgaIOBase + 0xa;
36201d54945dSmrg
36211d54945dSmrg/* All registers */
36221d54945dSmrg/* New formatted registers, matches s3rc (sort of) */
36231d54945dSmrg    xf86DrvMsgVerb( pScrn->scrnIndex, X_INFO, VERBLEV, "START register dump ------------------\n");
36241d54945dSmrg    xf86ErrorFVerb(VERBLEV, "Misc Out[3CC]\n  ");
36251d54945dSmrg    xf86ErrorFVerb(VERBLEV, "%02x\n",VGAIN8(0x3cc));
36261d54945dSmrg
36271d54945dSmrg    xf86ErrorFVerb(VERBLEV, "\nCR[00-2f]\n  ");
36281d54945dSmrg    for(tmp1=0x0;tmp1<=0x2f;tmp1++){
36291d54945dSmrg	VGAOUT8(vgaCRIndex, tmp1);
36301d54945dSmrg	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(vgaCRReg));
36311d54945dSmrg	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
36321d54945dSmrg	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
36331d54945dSmrg    }
36341d54945dSmrg
36351d54945dSmrg    xf86ErrorFVerb(VERBLEV, "\nSR[00-27]\n  ");
36361d54945dSmrg    for(tmp1=0x0;tmp1<=0x27;tmp1++){
36371d54945dSmrg	VGAOUT8(0x3c4, tmp1);
36381d54945dSmrg	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(0x3c5));
36391d54945dSmrg	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
36401d54945dSmrg	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
36411d54945dSmrg    }
36421d54945dSmrg    xf86ErrorFVerb(VERBLEV, "\n"); /* odd hex number of digits... */
36431d54945dSmrg
36441d54945dSmrg    xf86ErrorFVerb(VERBLEV, "\nGr Cont GR[00-0f]\n  ");
36451d54945dSmrg    for(tmp1=0x0;tmp1<=0x0f;tmp1++){
36461d54945dSmrg	VGAOUT8(0x3ce, tmp1);
36471d54945dSmrg	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(0x3cf));
36481d54945dSmrg	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
36491d54945dSmrg	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
36501d54945dSmrg    }
36511d54945dSmrg
36521d54945dSmrg    xf86ErrorFVerb(VERBLEV, "\nAtt Cont AR[00-1f]\n  ");
36531d54945dSmrg    VGAIN8(vgaIR); /* preset AR flip-flop by reading 3DA, ignore return value */
36541d54945dSmrg    tmp2=VGAIN8(0x3c0) & 0x20;
36551d54945dSmrg    for(tmp1=0x0;tmp1<=0x1f;tmp1++){
36561d54945dSmrg    VGAIN8(vgaIR); /* preset AR flip-flop by reading 3DA, ignore return value */
36571d54945dSmrg	VGAOUT8(0x3c0, (tmp1 & ~0x20) | tmp2);
36581d54945dSmrg	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(0x3c1));
36591d54945dSmrg	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
36601d54945dSmrg	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
36611d54945dSmrg    }
36621d54945dSmrg
36631d54945dSmrg    xf86ErrorFVerb(VERBLEV, "\nCR[30-6f]\n  ");
36641d54945dSmrg    for(tmp1=0x30;tmp1<=0x6f;tmp1++){
36651d54945dSmrg	VGAOUT8(vgaCRIndex, tmp1);
36661d54945dSmrg	xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(vgaCRReg));
36671d54945dSmrg	if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " ");
36681d54945dSmrg	if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n  ");
36691d54945dSmrg    }
36701d54945dSmrg
36711d54945dSmrg    xf86ErrorFVerb(VERBLEV, "\n");
36721d54945dSmrg    xf86DrvMsgVerb( pScrn->scrnIndex, X_INFO, VERBLEV, "END register dump --------------------\n");
36731d54945dSmrg}
36741d54945dSmrg
36751d54945dSmrg/* this is just a debugger hook */
36761d54945dSmrg/*
36771d54945dSmrgvoid print_subsys_stat(void *s3vMmioMem);
36781d54945dSmrgvoid
36791d54945dSmrgprint_subsys_stat(void *s3vMmioMem)
36801d54945dSmrg{
36811d54945dSmrg  ErrorF("IN_SUBSYS_STAT() = %x\n", IN_SUBSYS_STAT());
36821d54945dSmrg  return;
36831d54945dSmrg}
36841d54945dSmrg*/
36851d54945dSmrg
36861d54945dSmrg/*
36871d54945dSmrg * S3VDisplayPowerManagementSet --
36881d54945dSmrg *
36891d54945dSmrg * Sets VESA Display Power Management Signaling (DPMS) Mode.
36901d54945dSmrg */
36911d54945dSmrgstatic void
36921d54945dSmrgS3VDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
36931d54945dSmrg			     int flags)
36941d54945dSmrg{
36951d54945dSmrg  S3VPtr ps3v;
36961d54945dSmrg  unsigned char sr8 = 0x0, srd = 0x0;
36971d54945dSmrg  char modestr[][40] = { "On","Standby","Suspend","Off" };
36981d54945dSmrg
36991d54945dSmrg  ps3v = S3VPTR(pScrn);
37001d54945dSmrg
37011d54945dSmrg  /* unlock extended sequence registers */
37021d54945dSmrg
37031d54945dSmrg  VGAOUT8(0x3c4, 0x08);
37041d54945dSmrg  sr8 = VGAIN8(0x3c5);
37051d54945dSmrg  sr8 |= 0x6;
37061d54945dSmrg  VGAOUT8(0x3c5, sr8);
37071d54945dSmrg
37081d54945dSmrg  /* load SRD */
37091d54945dSmrg  VGAOUT8(0x3c4, 0x0d);
37101d54945dSmrg  srd = VGAIN8(0x3c5);
37111d54945dSmrg
37121d54945dSmrg  srd &= 0x03; /* clear the sync control bits of srd */
37131d54945dSmrg
37141d54945dSmrg  switch (PowerManagementMode) {
37151d54945dSmrg  case DPMSModeOn:
37161d54945dSmrg    /* Screen: On; HSync: On, VSync: On */
37171d54945dSmrg    break;
37181d54945dSmrg  case DPMSModeStandby:
37191d54945dSmrg    /* Screen: Off; HSync: Off, VSync: On */
37201d54945dSmrg    srd |= 0x10;
37211d54945dSmrg    break;
37221d54945dSmrg  case DPMSModeSuspend:
37231d54945dSmrg    /* Screen: Off; HSync: On, VSync: Off */
37241d54945dSmrg    srd |= 0x40;
37251d54945dSmrg    break;
37261d54945dSmrg  case DPMSModeOff:
37271d54945dSmrg    /* Screen: Off; HSync: Off, VSync: Off */
37281d54945dSmrg    srd |= 0x50;
37291d54945dSmrg    break;
37301d54945dSmrg  default:
37311d54945dSmrg    xf86ErrorFVerb(VERBLEV, "Invalid PowerManagementMode %d passed to S3VDisplayPowerManagementSet\n", PowerManagementMode);
37321d54945dSmrg    break;
37331d54945dSmrg  }
37341d54945dSmrg
37351d54945dSmrg  VGAOUT8(0x3c4, 0x0d);
37361d54945dSmrg  VGAOUT8(0x3c5, srd);
37371d54945dSmrg
37381d54945dSmrg  xf86ErrorFVerb(VERBLEV, "Power Manag: set:%s\n",
37391d54945dSmrg		 modestr[PowerManagementMode]);
37401d54945dSmrg
37411d54945dSmrg  return;
37421d54945dSmrg}
37431d54945dSmrg
37441d54945dSmrgstatic unsigned int
37451d54945dSmrgS3Vddc1Read(ScrnInfoPtr pScrn)
37461d54945dSmrg{
37471d54945dSmrg    register vgaHWPtr hwp = VGAHWPTR(pScrn);
37481d54945dSmrg    register CARD32 tmp;
37491d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
37501d54945dSmrg
37511d54945dSmrg    while (hwp->readST01(hwp)&0x8) {};
37521d54945dSmrg    while (!(hwp->readST01(hwp)&0x8)) {};
37531d54945dSmrg
37541d54945dSmrg    tmp = (INREG(DDC_REG));
37551d54945dSmrg    return ((unsigned int) (tmp & 0x08));
37561d54945dSmrg}
37571d54945dSmrg
375844802259Smrgstatic void
375944802259SmrgS3Vddc1SetSpeed(ScrnInfoPtr pScrn, xf86ddcSpeed speed)
376044802259Smrg{
376144802259Smrg    vgaHWddc1SetSpeed(pScrn, speed);
376244802259Smrg}
376344802259Smrg
37641d54945dSmrgstatic Bool
37655788ca14SmrgS3Vddc1(ScrnInfoPtr pScrn)
37661d54945dSmrg{
37671d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
37681d54945dSmrg    CARD32 tmp;
37691d54945dSmrg    Bool success = FALSE;
37701d54945dSmrg    xf86MonPtr pMon;
37711d54945dSmrg
37721d54945dSmrg    /* initialize chipset */
37731d54945dSmrg    tmp = INREG(DDC_REG);
37741d54945dSmrg    OUTREG(DDC_REG,(tmp | 0x12));
37751d54945dSmrg
37761d54945dSmrg    if ((pMon = xf86PrintEDID(
377744802259Smrg		xf86DoEDID_DDC1(XF86_SCRN_ARG(pScrn), S3Vddc1SetSpeed,
37781d54945dSmrg	                S3Vddc1Read))) != NULL)
37791d54945dSmrg	success = TRUE;
37801d54945dSmrg    xf86SetDDCproperties(pScrn,pMon);
37811d54945dSmrg
37821d54945dSmrg    /* undo initialization */
37831d54945dSmrg    OUTREG(DDC_REG,(tmp));
37841d54945dSmrg    return success;
37851d54945dSmrg}
37861d54945dSmrg
37871d54945dSmrgstatic Bool
37885788ca14SmrgS3Vddc2(ScrnInfoPtr pScrn)
37891d54945dSmrg{
37901d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
37911d54945dSmrg
37921d54945dSmrg    if ( xf86LoadSubModule(pScrn, "i2c") ) {
37931d54945dSmrg	if (S3V_I2CInit(pScrn)) {
37941d54945dSmrg	    CARD32 tmp = (INREG(DDC_REG));
37951d54945dSmrg	    OUTREG(DDC_REG,(tmp | 0x13));
37961d54945dSmrg	    xf86SetDDCproperties(pScrn,xf86PrintEDID(
37975788ca14Smrg			     xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn),ps3v->I2C)));
37981d54945dSmrg	    OUTREG(DDC_REG,tmp);
37991d54945dSmrg	    return TRUE;
38001d54945dSmrg	}
38011d54945dSmrg    }
38021d54945dSmrg    return FALSE;
38031d54945dSmrg}
38041d54945dSmrg
38051d54945dSmrgstatic void
38061d54945dSmrgS3VProbeDDC(ScrnInfoPtr pScrn, int index)
38071d54945dSmrg{
38081d54945dSmrg    vbeInfoPtr pVbe;
38091d54945dSmrg    if (xf86LoadSubModule(pScrn, "vbe")) {
38101d54945dSmrg        pVbe = VBEInit(NULL,index);
38111d54945dSmrg        ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
38121d54945dSmrg	vbeFree(pVbe);
38131d54945dSmrg    }
38141d54945dSmrg}
38151d54945dSmrg
38161d54945dSmrg/*EOF*/
38171d54945dSmrg
38181d54945dSmrg
3819