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