diff options
Diffstat (limited to 'src/s3v_driver.c')
-rw-r--r-- | src/s3v_driver.c | 3953 |
1 files changed, 3953 insertions, 0 deletions
diff --git a/src/s3v_driver.c b/src/s3v_driver.c new file mode 100644 index 0000000..b2d92fc --- /dev/null +++ b/src/s3v_driver.c @@ -0,0 +1,3953 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/s3virge/s3v_driver.c,v 1.93 2003/11/06 18:38:05 tsi Exp $ */ + +/* +Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the XFree86 Project shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from the XFree86 Project. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86Resources.h" +/* Needed by Resources Access Control (RAC) */ +#include "xf86RAC.h" + +#include "xf86DDC.h" +#include "vbe.h" + +/* Needed by the Shadow Framebuffer */ +#include "shadowfb.h" + +/* + * s3v_driver.c + * Port to 4.0 design level + * + * S3 ViRGE driver + * + * 10/98 - 3/99 Kevin Brosius + * based largely on the SVGA ViRGE driver from 3.3.3x, + * Started 09/03/97 by S. Marineau + * + * + */ + + + /* Most xf86 commons are already in s3v.h */ +#include "s3v.h" + + +#include "globals.h" +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#ifndef USE_INT10 +#define USE_INT10 0 +#endif + +/* + * Internals + */ +static void S3VEnableMmio(ScrnInfoPtr pScrn); +static void S3VDisableMmio(ScrnInfoPtr pScrn); + +/* + * Forward definitions for the functions that make up the driver. + */ + +/* Mandatory functions */ +static const OptionInfoRec * S3VAvailableOptions(int chipid, int busid); +static void S3VIdentify(int flags); +static Bool S3VProbe(DriverPtr drv, int flags); +static Bool S3VPreInit(ScrnInfoPtr pScrn, int flags); + +static Bool S3VEnterVT(int scrnIndex, int flags); +static void S3VLeaveVT(int scrnIndex, int flags); +static void S3VSave (ScrnInfoPtr pScrn); +static void S3VWriteMode (ScrnInfoPtr pScrn, vgaRegPtr, S3VRegPtr); + +static void S3VSaveSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams); +static void S3VRestoreSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams); +static void S3VDisableSTREAMS(ScrnInfoPtr pScrn); +static Bool S3VScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv); +static int S3VInternalScreenInit( int scrnIndex, ScreenPtr pScreen); +static void S3VPrintRegs(ScrnInfoPtr); +static ModeStatus S3VValidMode(int index, DisplayModePtr mode, Bool verbose, int flags); + +static Bool S3VMapMem(ScrnInfoPtr pScrn); +static void S3VUnmapMem(ScrnInfoPtr pScrn); +static Bool S3VModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); +static Bool S3VCloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool S3VSaveScreen(ScreenPtr pScreen, int mode); +static void S3VInitSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams, DisplayModePtr mode); +/* s3v.h - static void S3VAdjustFrame(int scrnIndex, int x, int y, int flags); */ +/* s3v.h - static Bool S3VSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); */ +static void S3VLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, LOCO *colors, VisualPtr pVisual); + +static void S3VDisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, + int flags); +static Bool S3Vddc1(int scrnIndex); +static Bool S3Vddc2(int scrnIndex); + +static unsigned int S3Vddc1Read(ScrnInfoPtr pScrn); +static void S3VProbeDDC(ScrnInfoPtr pScrn, int index); + +/* + * This is intentionally screen-independent. It indicates the binding + * choice made in the first PreInit. + */ +static int pix24bpp = 0; + +#define S3VIRGE_NAME "S3VIRGE" +#define S3VIRGE_DRIVER_NAME "s3virge" +#define S3VIRGE_VERSION_NAME "1.8.6" +#define S3VIRGE_VERSION_MAJOR 1 +#define S3VIRGE_VERSION_MINOR 8 +#define S3VIRGE_PATCHLEVEL 6 +#define S3VIRGE_DRIVER_VERSION ((S3VIRGE_VERSION_MAJOR << 24) | \ + (S3VIRGE_VERSION_MINOR << 16) | \ + S3VIRGE_PATCHLEVEL) + +/* + * This contains the functions needed by the server after loading the + * driver module. It must be supplied, and gets added the driver list by + * the Module Setup funtion in the dynamic case. In the static case a + * reference to this is compiled in, and this requires that the name of + * this DriverRec be an upper-case version of the driver name. + */ + +_X_EXPORT DriverRec S3VIRGE = +{ + S3VIRGE_DRIVER_VERSION, + S3VIRGE_DRIVER_NAME, + S3VIdentify, + S3VProbe, + S3VAvailableOptions, + NULL, + 0 +}; + + +/* Supported chipsets */ +static SymTabRec S3VChipsets[] = { + /* base (86C325) */ + { PCI_CHIP_VIRGE, "virge" }, + { PCI_CHIP_VIRGE, "86C325" }, + /* VX (86C988) */ + { PCI_CHIP_VIRGE_VX, "virge vx" }, + { PCI_CHIP_VIRGE_VX, "86C988" }, + /* DX (86C375) GX (86C385) */ + { PCI_CHIP_VIRGE_DXGX, "virge dx" }, + { PCI_CHIP_VIRGE_DXGX, "virge gx" }, + { PCI_CHIP_VIRGE_DXGX, "86C375" }, + { PCI_CHIP_VIRGE_DXGX, "86C385" }, + /* GX2 (86C357) */ + { PCI_CHIP_VIRGE_GX2, "virge gx2" }, + { PCI_CHIP_VIRGE_GX2, "86C357" }, + /* MX (86C260) */ + { PCI_CHIP_VIRGE_MX, "virge mx" }, + { PCI_CHIP_VIRGE_MX, "86C260" }, + /* MX+ (86C280) */ + { PCI_CHIP_VIRGE_MXP, "virge mx+" }, + { PCI_CHIP_VIRGE_MXP, "86C280" }, + /* Trio3D (86C365) */ + { PCI_CHIP_Trio3D, "trio 3d" }, + { PCI_CHIP_Trio3D, "86C365" }, + /* Trio3D/2x (86C362/86C368) */ + { PCI_CHIP_Trio3D_2X, "trio 3d/2x" }, + { PCI_CHIP_Trio3D_2X, "86C362" }, + { PCI_CHIP_Trio3D_2X, "86C368" }, + {-1, NULL } +}; + +static PciChipsets S3VPciChipsets[] = { + /* numChipset, PciID, Resource */ + { PCI_CHIP_VIRGE, PCI_CHIP_VIRGE, RES_SHARED_VGA }, + { PCI_CHIP_VIRGE_VX, PCI_CHIP_VIRGE_VX, RES_SHARED_VGA }, + { PCI_CHIP_VIRGE_DXGX, PCI_CHIP_VIRGE_DXGX, RES_SHARED_VGA }, + { PCI_CHIP_VIRGE_GX2, PCI_CHIP_VIRGE_GX2, RES_SHARED_VGA }, + { PCI_CHIP_VIRGE_MX, PCI_CHIP_VIRGE_MX, RES_SHARED_VGA }, + { PCI_CHIP_VIRGE_MXP, PCI_CHIP_VIRGE_MXP, RES_SHARED_VGA }, + { PCI_CHIP_Trio3D, PCI_CHIP_Trio3D, RES_SHARED_VGA }, + { PCI_CHIP_Trio3D_2X, PCI_CHIP_Trio3D_2X, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED } +}; + +typedef enum { + OPTION_SLOW_EDODRAM, + OPTION_SLOW_DRAM, + OPTION_FAST_DRAM, + OPTION_FPM_VRAM, + OPTION_PCI_BURST, + OPTION_FIFO_CONSERV, + OPTION_FIFO_MODERATE, + OPTION_FIFO_AGGRESSIVE, + OPTION_PCI_RETRY, + OPTION_NOACCEL, + OPTION_ACCELMETHOD, + OPTION_EARLY_RAS_PRECHARGE, + OPTION_LATE_RAS_PRECHARGE, + OPTION_LCD_CENTER, + OPTION_LCDCLOCK, + OPTION_MCLK, + OPTION_REFCLK, + OPTION_SHOWCACHE, + OPTION_SWCURSOR, + OPTION_HWCURSOR, + OPTION_SHADOW_FB, + OPTION_ROTATE, + OPTION_FB_DRAW, + OPTION_MX_CR3A_FIX, + OPTION_XVIDEO +} S3VOpts; + +static const OptionInfoRec S3VOptions[] = +{ + /* int token, const char* name, OptionValueType type, + ValueUnion value, Bool found. + */ + { OPTION_SLOW_EDODRAM, "slow_edodram", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SLOW_DRAM, "slow_dram", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FAST_DRAM, "fast_dram", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FPM_VRAM, "fpm_vram", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FIFO_CONSERV, "fifo_conservative", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FIFO_MODERATE, "fifo_moderate", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FIFO_AGGRESSIVE, "fifo_aggressive", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_PCI_RETRY, "pci_retry", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ACCELMETHOD, "AccelMethod", OPTV_STRING, {0}, FALSE }, + { OPTION_EARLY_RAS_PRECHARGE, "early_ras_precharge", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_LATE_RAS_PRECHARGE, "late_ras_precharge", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_LCD_CENTER, "lcd_center", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_LCDCLOCK, "set_lcdclk", OPTV_INTEGER, {0}, FALSE }, + { OPTION_MCLK, "set_mclk", OPTV_FREQ, {0}, FALSE }, + { OPTION_REFCLK, "set_refclk", OPTV_FREQ, {0}, FALSE }, + { OPTION_SHOWCACHE, "show_cache", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_HWCURSOR, "HWCursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SWCURSOR, "SWCursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_FB_DRAW, "UseFB", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_MX_CR3A_FIX, "mxcr3afix", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_XVIDEO, "XVideo", OPTV_BOOLEAN, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE} +}; + + +/* + * Lists of symbols that may/may not be required by this driver. + * This allows the loader to know which ones to issue warnings for. + * + * Note that vgahwSymbols and xaaSymbols are referenced outside the + * XFree86LOADER define in later code, so are defined outside of that + * define here also. + */ + +static const char *vgahwSymbols[] = { + "vgaHWBlankScreen", + "vgaHWCopyReg", + "vgaHWGetHWRec", + "vgaHWGetIOBase", + "vgaHWGetIndex", + "vgaHWInit", + "vgaHWLock", + "vgaHWMapMem", + "vgaHWProtect", + "vgaHWRestore", + "vgaHWSave", + "vgaHWSaveScreen", + "vgaHWSetMmioFuncs", + "vgaHWSetStdFuncs", + "vgaHWUnmapMem", + "vgaHWddc1SetSpeedWeak", + /* not used by ViRGE (at the moment :( ) */ + /* + "vgaHWUnlock", + "vgaHWFreeHWRec", + */ + NULL +}; + +static const char *xaaSymbols[] = { + "XAAGetCopyROP", + "XAAGetCopyROP_PM", + "XAADestroyInfoRec", + "XAACreateInfoRec", + "XAAHelpPatternROP", + "XAAHelpSolidROP", + "XAAInit", + NULL +}; + +static const char *exaSymbols[] = { + "exaDriverAlloc", + "exaDriverInit", + "exaDriverFini", + "exaOffscreenAlloc", + "exaOffscreenFree", + "exaGetPixmapOffset", + "exaGetPixmapPitch", + "exaGetPixmapSize", + NULL +}; + +static const char *ramdacSymbols[] = { + "xf86CreateCursorInfoRec", + "xf86InitCursor", +#if 0 + "xf86DestroyCursorInfoRec", +#endif + NULL +}; + +static const char *ddcSymbols[] = { + "xf86PrintEDID", + "xf86DoEDID_DDC1", + "xf86DoEDID_DDC2", + "xf86SetDDCproperties", + NULL +}; + +static const char *i2cSymbols[] = { + "xf86CreateI2CBusRec", + "xf86I2CBusInit", + NULL +}; + +static const char *shadowSymbols[] = { + "ShadowFBInit", + NULL +}; + +static const char *vbeSymbols[] = { + "VBEInit", + "vbeDoEDID", + "vbeFree", + NULL +}; + +static const char *fbSymbols[] = { + "fbPictureInit", + "fbScreenInit", + NULL +}; + +#if USE_INT10 +static const char *int10Symbols[] = { + "xf86InitInt10", + "xf86FreeInt10", + NULL +}; +#endif + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(s3virgeSetup); + +static XF86ModuleVersionInfo S3VVersRec = +{ + "s3virge", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + S3VIRGE_VERSION_MAJOR, S3VIRGE_VERSION_MINOR, S3VIRGE_PATCHLEVEL, + ABI_CLASS_VIDEODRV, /* This is a video driver */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0, 0, 0, 0} +}; + + +/* + * This is the module init data for XFree86 modules. + * + * Its name has to be the driver name followed by ModuleData. + */ +_X_EXPORT XF86ModuleData s3virgeModuleData = { + &S3VVersRec, + s3virgeSetup, + NULL +}; + +static pointer +s3virgeSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + if (!setupDone) { + setupDone = TRUE; + xf86AddDriver(&S3VIRGE, module, 0); + + /* + * Modules that this driver always requires can be loaded here + * by calling LoadSubModule(). + */ + + /* + * Tell the loader about symbols from other modules that this module + * might refer to. + */ + LoaderRefSymLists(vgahwSymbols, xaaSymbols, exaSymbols, ramdacSymbols, + ddcSymbols, i2cSymbols, +#if USE_INT10 + int10Symbols, +#endif + vbeSymbols, shadowSymbols, fbSymbols, NULL); + + /* + * The return value must be non-NULL on success even though there + * is no TearDownProc. + */ + return (pointer) 1; + } else { + if (errmaj) + *errmaj = LDR_ONCEONLY; + return NULL; + } +} + +#endif /* XFree86LOADER */ + + +static unsigned char *find_bios_string(PCITAG Tag, int BIOSbase, char *match1, char *match2) +{ +#define BIOS_BSIZE 1024 +#define BIOS_BASE 0xc0000 + + static unsigned char bios[BIOS_BSIZE]; + static int init=0; + int i,j,l1,l2; + + if (!init) { + init = 1; + if (xf86ReadDomainMemory(Tag, BIOSbase, BIOS_BSIZE, bios) != BIOS_BSIZE) + return NULL; + if ((bios[0] != 0x55) || (bios[1] != 0xaa)) + return NULL; + } + if (match1 == NULL) + return NULL; + + l1 = strlen(match1); + if (match2 != NULL) + l2 = strlen(match2); + else /* for compiler-warnings */ + l2 = 0; + + for (i=0; i<BIOS_BSIZE-l1; i++) + if (bios[i] == match1[0] && !memcmp(&bios[i],match1,l1)) { + if (match2 == NULL) + return &bios[i+l1]; + else + for(j=i+l1; (j<BIOS_BSIZE-l2) && bios[j]; j++) + if (bios[j] == match2[0] && !memcmp(&bios[j],match2,l2)) + return &bios[j+l2]; + } + + return NULL; +} + + +static Bool +S3VGetRec(ScrnInfoPtr pScrn) +{ + PVERB5(" S3VGetRec\n"); + /* + * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate. + * pScrn->driverPrivate is initialised to NULL, so we can check if + * the allocation has already been done. + */ + if (pScrn->driverPrivate != NULL) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(S3VRec), 1); + /* Initialise it here when needed (or possible) */ + + return TRUE; +} + +static void +S3VFreeRec(ScrnInfoPtr pScrn) +{ + PVERB5(" S3VFreeRec\n"); + if (pScrn->driverPrivate == NULL) + return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + +static const OptionInfoRec * +S3VAvailableOptions(int chipid, int busid) +{ + return S3VOptions; +} + +static void +S3VIdentify(int flags) +{ + PVERB5(" S3VIdentify\n"); + xf86PrintChipsets(S3VIRGE_NAME, + "driver (version " S3VIRGE_VERSION_NAME ") for S3 ViRGE chipsets", + S3VChipsets); +} + + +static Bool +S3VProbe(DriverPtr drv, int flags) +{ + int i; + GDevPtr *devSections; + int *usedChips; + int numDevSections; + int numUsed; + Bool foundScreen = FALSE; + + PVERB5(" S3VProbe begin\n"); + + if ((numDevSections = xf86MatchDevice(S3VIRGE_DRIVER_NAME, + &devSections)) <= 0) { + /* + * There's no matching device section in the config file, so quit + * now. + */ + return FALSE; + } + if (xf86GetPciVideoInfo() == NULL) { + return FALSE; + } + + numUsed = xf86MatchPciInstances(S3VIRGE_NAME, PCI_S3_VENDOR_ID, + S3VChipsets, S3VPciChipsets, devSections, + numDevSections, drv, &usedChips); + + /* Free it since we don't need that list after this */ + xfree(devSections); + if (numUsed <= 0) + return FALSE; + + if (flags & PROBE_DETECT) + foundScreen = TRUE; + else for (i = 0; i < numUsed; i++) { + /* Allocate a ScrnInfoRec and claim the slot */ + ScrnInfoPtr pScrn = NULL; + if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i], + S3VPciChipsets,NULL,NULL, NULL, + NULL,NULL))) { + /* Fill in what we can of the ScrnInfoRec */ + pScrn->driverVersion = S3VIRGE_DRIVER_VERSION; + pScrn->driverName = S3VIRGE_DRIVER_NAME; + pScrn->name = S3VIRGE_NAME; + pScrn->Probe = S3VProbe; + pScrn->PreInit = S3VPreInit; + pScrn->ScreenInit = S3VScreenInit; + pScrn->SwitchMode = S3VSwitchMode; + pScrn->AdjustFrame = S3VAdjustFrame; + pScrn->EnterVT = S3VEnterVT; + pScrn->LeaveVT = S3VLeaveVT; + pScrn->FreeScreen = NULL; /*S3VFreeScreen;*/ + pScrn->ValidMode = S3VValidMode; + foundScreen = TRUE; + } + } + xfree(usedChips); + PVERB5(" S3VProbe end\n"); + return foundScreen; +} + + +/* Mandatory */ +static Bool +S3VPreInit(ScrnInfoPtr pScrn, int flags) +{ + EntityInfoPtr pEnt; + S3VPtr ps3v; + MessageType from; + int i; + double real; + ClockRangePtr clockRanges; + char *mod = NULL; + const char *reqSym = NULL; + char *s; + + unsigned char config1, config2, m, n, n1, n2, cr66 = 0; + int mclk; + + vgaHWPtr hwp; + int vgaCRIndex, vgaCRReg, vgaIOBase; + + PVERB5(" S3VPreInit 1\n"); + + if (flags & PROBE_DETECT) { + S3VProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index ); + return TRUE; + } + + /* + * Note: This function is only called once at server startup, and + * not at the start of each server generation. This means that + * only things that are persistent across server generations can + * be initialised here. xf86Screens[] is (pScrn is a pointer to one + * of these). Privates allocated using xf86AllocateScrnInfoPrivateIndex() + * are too, and should be used for data that must persist across + * server generations. + * + * Per-generation data should be allocated with + * AllocateScreenPrivateIndex() from the ScreenInit() function. + */ + + /* The vgahw module should be loaded here when needed */ + + if (!xf86LoadSubModule(pScrn, "vgahw")) + return FALSE; + + xf86LoaderReqSymLists(vgahwSymbols, NULL); + + /* + * Allocate a vgaHWRec + */ + if (!vgaHWGetHWRec(pScrn)) + return FALSE; + + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + /* + * The first thing we should figure out is the depth, bpp, etc. + * We support both 24bpp and 32bpp layouts, so indicate that. + */ + if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb | + SupportConvert32to24 | PreferConvert32to24)) { + return FALSE; + } else { + /* Check that the returned depth is one we support */ + switch (pScrn->depth) { + case 8: + case 15: + case 16: + case 24: + /* OK */ + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by this driver\n", + pScrn->depth); + return FALSE; + } + } + xf86PrintDepthBpp(pScrn); + + /* Get the depth24 pixmap format */ + if (pScrn->depth == 24 && pix24bpp == 0) + pix24bpp = xf86GetBppFromDepth(pScrn, 24); + + /* + * This must happen after pScrn->display has been set because + * xf86SetWeight references it. + */ + if (pScrn->depth > 8) { + /* The defaults are OK for us */ + rgb zeros = {0, 0, 0}; + + if (!xf86SetWeight(pScrn, zeros, zeros)) { + return FALSE; + } else { + /* XXX check that weight returned is supported */ + ; + } + } + + if (!xf86SetDefaultVisual(pScrn, -1)) { + return FALSE; + } else { /* editme - from MGA, does ViRGE? */ + /* We don't currently support DirectColor at > 8bpp */ + if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual" + " (%s) is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + return FALSE; + } + } + + /* We use a programmable clock */ + pScrn->progClock = TRUE; + + /* Allocate the S3VRec driverPrivate */ + if (!S3VGetRec(pScrn)) { + return FALSE; + } + ps3v = S3VPTR(pScrn); + + /* Collect all of the relevant option flags (fill in pScrn->options) */ + xf86CollectOptions(pScrn, NULL); + + /* Set the bits per RGB for 8bpp mode */ + if (pScrn->depth == 8) { + /* ViRGE supports 6 RGB bits in depth 8 */ + /* modes (with 256 entry LUT) */ + pScrn->rgbBits = 6; + } + + /* Process the options */ + if (!(ps3v->Options = xalloc(sizeof(S3VOptions)))) + return FALSE; + memcpy(ps3v->Options, S3VOptions, sizeof(S3VOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ps3v->Options); + + + if (xf86ReturnOptValBool(ps3v->Options, OPTION_PCI_BURST, FALSE)) { + ps3v->pci_burst = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_burst - PCI burst read enabled\n"); + } else + ps3v->pci_burst = FALSE; + /* default */ + ps3v->NoPCIRetry = 1; + /* Set option */ + if (xf86ReturnOptValBool(ps3v->Options, OPTION_PCI_RETRY, FALSE)) { + if (xf86ReturnOptValBool(ps3v->Options, OPTION_PCI_BURST, FALSE)) { + ps3v->NoPCIRetry = 0; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n"); + } + else { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "\"pci_retry\" option requires \"pci_burst\".\n"); + } + } + if (xf86IsOptionSet(ps3v->Options, OPTION_FIFO_CONSERV)) { + ps3v->fifo_conservative = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_conservative set\n"); + } else + ps3v->fifo_conservative = FALSE; + + if (xf86IsOptionSet(ps3v->Options, OPTION_FIFO_MODERATE)) { + ps3v->fifo_moderate = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_moderate set\n"); + } else + ps3v->fifo_moderate = FALSE; + + if (xf86IsOptionSet(ps3v->Options, OPTION_FIFO_AGGRESSIVE)) { + ps3v->fifo_aggressive = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_aggressive set\n"); + } else + ps3v->fifo_aggressive = FALSE; + + if (xf86IsOptionSet(ps3v->Options, OPTION_SLOW_EDODRAM)) { + ps3v->slow_edodram = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: slow_edodram set\n"); + } else + ps3v->slow_edodram = FALSE; + + if (xf86IsOptionSet(ps3v->Options, OPTION_SLOW_DRAM)) { + ps3v->slow_dram = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: slow_dram set\n"); + } else + ps3v->slow_dram = FALSE; + + if (xf86IsOptionSet(ps3v->Options, OPTION_FAST_DRAM)) { + ps3v->fast_dram = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fast_dram set\n"); + } else + ps3v->fast_dram = FALSE; + + if (xf86IsOptionSet(ps3v->Options, OPTION_FPM_VRAM)) { + ps3v->fpm_vram = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fpm_vram set\n"); + } else + ps3v->fpm_vram = FALSE; + + if (xf86ReturnOptValBool(ps3v->Options, OPTION_NOACCEL, FALSE)) { + ps3v->NoAccel = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: NoAccel - Acceleration disabled\n"); + } else + ps3v->NoAccel = FALSE; + + if (xf86ReturnOptValBool(ps3v->Options, OPTION_EARLY_RAS_PRECHARGE, FALSE)) { + ps3v->early_ras_precharge = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: early_ras_precharge set\n"); + } else + ps3v->early_ras_precharge = FALSE; + + if (xf86ReturnOptValBool(ps3v->Options, OPTION_LATE_RAS_PRECHARGE, FALSE)) { + ps3v->late_ras_precharge = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: late_ras_precharge set\n"); + } else + ps3v->late_ras_precharge = FALSE; + + if (xf86ReturnOptValBool(ps3v->Options, OPTION_LCD_CENTER, FALSE)) { + ps3v->lcd_center = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: lcd_center set\n"); + } else + ps3v->lcd_center = FALSE; + + if (xf86ReturnOptValBool(ps3v->Options, OPTION_SHOWCACHE, FALSE)) { + ps3v->ShowCache = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: show_cache set\n"); + } else + ps3v->ShowCache = FALSE; + + if (xf86GetOptValInteger(ps3v->Options, OPTION_LCDCLOCK, &ps3v->LCDClk)) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: lcd_setclk set to %1.3f Mhz\n", + ps3v->LCDClk / 1000.0 ); + } else + ps3v->LCDClk = 0; + + if (xf86GetOptValFreq(ps3v->Options, OPTION_MCLK, OPTUNITS_MHZ, &real)) { + ps3v->MCLK = (int)(real * 1000.0); + if (ps3v->MCLK <= 100000) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_mclk set to %1.3f Mhz\n", + ps3v->MCLK / 1000.0 ); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING + , "Memory Clock value of %1.3f MHz is larger than limit of 100 MHz\n" + , ps3v->MCLK/1000.0); + ps3v->MCLK = 0; + } + } else + ps3v->MCLK = 0; + + if (xf86GetOptValFreq(ps3v->Options, OPTION_REFCLK, OPTUNITS_MHZ, &real)) { + ps3v->REFCLK = (int)(real * 1000.0); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_refclk set to %1.3f Mhz\n", + ps3v->REFCLK / 1000.0 ); + } else + ps3v->REFCLK = 0; + + from = X_DEFAULT; + ps3v->hwcursor = TRUE; + if (xf86GetOptValBool(ps3v->Options, OPTION_HWCURSOR, &ps3v->hwcursor)) + from = X_CONFIG; + if (xf86ReturnOptValBool(ps3v->Options, OPTION_SWCURSOR, FALSE)) { + ps3v->hwcursor = FALSE; + from = X_CONFIG; + } + xf86DrvMsg(pScrn->scrnIndex, from, "Using %s Cursor\n", + ps3v->hwcursor ? "HW" : "SW"); + + if (xf86GetOptValBool(ps3v->Options, OPTION_SHADOW_FB,&ps3v->shadowFB)) + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n", + ps3v->shadowFB ? "enabled" : "disabled"); + + if ((s = xf86GetOptValString(ps3v->Options, OPTION_ROTATE))) { + if(!xf86NameCmp(s, "CW")) { + /* accel is disabled below for shadowFB */ + ps3v->shadowFB = TRUE; + ps3v->rotate = 1; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Rotating screen clockwise - acceleration disabled\n"); + } else if(!xf86NameCmp(s, "CCW")) { + ps3v->shadowFB = TRUE; + ps3v->rotate = -1; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen" + "counter clockwise - acceleration disabled\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid" + "value for Option \"Rotate\"\n", s); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid options are \"CW\" or \"CCW\"\n"); + } + } + + if (ps3v->shadowFB && !ps3v->NoAccel) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "HW acceleration not supported with \"shadowFB\".\n"); + ps3v->NoAccel = TRUE; + } + + if(!ps3v->NoAccel) { + from = X_DEFAULT; + char *strptr; + if((strptr = (char *)xf86GetOptValString(ps3v->Options, OPTION_ACCELMETHOD))) { + if(!xf86NameCmp(strptr,"XAA")) { + from = X_CONFIG; + ps3v->useEXA = FALSE; + } else if(!xf86NameCmp(strptr,"EXA")) { + from = X_CONFIG; + ps3v->useEXA = TRUE; + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration architecture\n", + ps3v->useEXA ? "EXA" : "XAA"); + } + + if (ps3v->rotate && ps3v->hwcursor) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "HW cursor not supported with \"rotate\".\n"); + ps3v->hwcursor = FALSE; + } + + ps3v->UseFB = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Using fb.\n"); + if (xf86IsOptionSet(ps3v->Options, OPTION_FB_DRAW)) + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "UseFB option is deprecated.\n"); + + if (xf86IsOptionSet(ps3v->Options, OPTION_MX_CR3A_FIX)) + { + if (xf86GetOptValBool(ps3v->Options, OPTION_MX_CR3A_FIX ,&ps3v->mx_cr3a_fix)) + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "%s mx_cr3a_fix.\n", + ps3v->mx_cr3a_fix ? "Enabling (default)" : "Disabling"); + } + else + { + ps3v->mx_cr3a_fix = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "mx_cr3a_fix.\n"); + } + + /* Find the PCI slot for this screen */ + /* + * XXX Ignoring the Type list for now. It might be needed when + * multiple cards are supported. + */ + if (pScrn->numEntities > 1) { + S3VFreeRec(pScrn); + return FALSE; + } + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + if (pEnt->resources) { + xfree(pEnt); + S3VFreeRec(pScrn); + return FALSE; + } + +#if USE_INT10 + if (xf86LoadSubModule(pScrn, "int10")) { + xf86Int10InfoPtr pInt; + xf86LoaderReqSymLists(int10Symbols, NULL); +#if 1 + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); + pInt = xf86InitInt10(pEnt->index); + xf86FreeInt10(pInt); +#endif + } +#endif + if (xf86LoadSubModule(pScrn, "vbe")) { + xf86LoaderReqSymLists(vbeSymbols, NULL); + ps3v->pVbe = VBEInit(NULL,pEnt->index); + } + + ps3v->PciInfo = xf86GetPciInfoForEntity(pEnt->index); + xf86RegisterResources(pEnt->index,NULL,ResNone); + xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr); + xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr); + + /* + * Set the Chipset and ChipRev, allowing config file entries to + * override. + */ + if (pEnt->device->chipset && *pEnt->device->chipset) { + pScrn->chipset = pEnt->device->chipset; + ps3v->Chipset = xf86StringToToken(S3VChipsets, pScrn->chipset); + from = X_CONFIG; + } else if (pEnt->device->chipID >= 0) { + ps3v->Chipset = pEnt->device->chipID; + pScrn->chipset = (char *)xf86TokenToString(S3VChipsets, ps3v->Chipset); + from = X_CONFIG; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", + ps3v->Chipset); + } else { + from = X_PROBED; + ps3v->Chipset = ps3v->PciInfo->chipType; + pScrn->chipset = (char *)xf86TokenToString(S3VChipsets, ps3v->Chipset); + } + + if (pEnt->device->chipRev >= 0) { + ps3v->ChipRev = pEnt->device->chipRev; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + ps3v->ChipRev); + } else { + ps3v->ChipRev = ps3v->PciInfo->chipRev; + } + xfree(pEnt); + + /* + * This shouldn't happen because such problems should be caught in + * S3VProbe(), but check it just in case. + */ + if (pScrn->chipset == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ChipID 0x%04X is not recognised\n", ps3v->Chipset); + vbeFree(ps3v->pVbe); + ps3v->pVbe = NULL; + return FALSE; + } + if (ps3v->Chipset < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Chipset \"%s\" is not recognised\n", pScrn->chipset); + vbeFree(ps3v->pVbe); + ps3v->pVbe = NULL; + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset); + + ps3v->PciTag = pciTag(ps3v->PciInfo->bus, ps3v->PciInfo->device, + ps3v->PciInfo->func); + + /* Handle XVideo after we know chipset, so we can give an */ + /* intelligent comment about support */ + if (xf86IsOptionSet(ps3v->Options, OPTION_XVIDEO)) + { + if(S3VQueryXvCapable(pScrn)) + { + if (xf86GetOptValBool(ps3v->Options, OPTION_XVIDEO ,&ps3v->XVideo)) + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "%s XVideo.\n", + ps3v->XVideo ? "Enabling (default)" : "Disabling"); + } + else + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "XVideo not supported.\n"); + } + else + { + ps3v->XVideo = S3VQueryXvCapable(pScrn); + if(ps3v->XVideo) + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "XVideo supported.\n"); + else + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "XVideo not supported.\n"); + } + + + S3VMapMem(pScrn); + hwp = VGAHWPTR(pScrn); + vgaIOBase = hwp->IOBase; + vgaCRIndex = vgaIOBase + 4; + vgaCRReg = vgaIOBase + 5; + + xf86ErrorFVerb(VERBLEV, + " S3VPreInit vgaCRIndex=%x, vgaIOBase=%x, MMIOBase=%p\n", + vgaCRIndex, vgaIOBase, hwp->MMIOBase ); + + +#if 0 /* Not needed in 4.0 flavors */ + /* Unlock sys regs */ + VGAOUT8(vgaCRIndex, 0x38); + VGAOUT8(vgaCRReg, 0x48); +#endif + + /* Next go on to detect amount of installed ram */ + + VGAOUT8(vgaCRIndex, 0x36); /* for register CR36 (CONFG_REG1),*/ + config1 = VGAIN8(vgaCRReg); /* get amount of vram installed */ + + VGAOUT8(vgaCRIndex, 0x37); /* for register CR37 (CONFG_REG2),*/ + config2 = VGAIN8(vgaCRReg); /* get amount of off-screen ram */ + + if (xf86LoadSubModule(pScrn, "ddc")) { + xf86MonPtr pMon = NULL; + + xf86LoaderReqSymLists(ddcSymbols, NULL); + if ((ps3v->pVbe) + && ((pMon = xf86PrintEDID(vbeDoEDID(ps3v->pVbe, NULL))) != NULL)) + xf86SetDDCproperties(pScrn,pMon); + else if (!S3Vddc1(pScrn->scrnIndex)) { + S3Vddc2(pScrn->scrnIndex); + } + } + if (ps3v->pVbe) { + vbeFree(ps3v->pVbe); + ps3v->pVbe = NULL; + } + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() + * here. (from MGA, no ViRGE gamma support yet, but needed for + * xf86HandleColormaps support.) + */ + { + Gamma zeros = {0.0, 0.0, 0.0}; + + if (!xf86SetGamma(pScrn, zeros)) { + return FALSE; + } + } + + /* And compute the amount of video memory and offscreen memory */ + ps3v->MemOffScreen = 0; + + if (!pScrn->videoRam) { + if (ps3v->Chipset == S3_ViRGE_VX) { + switch((config2 & 0x60) >> 5) { + case 1: + ps3v->MemOffScreen = 4 * 1024; + break; + case 2: + ps3v->MemOffScreen = 2 * 1024; + break; + } + switch ((config1 & 0x60) >> 5) { + case 0: + ps3v->videoRamKbytes = 2 * 1024; + break; + case 1: + ps3v->videoRamKbytes = 4 * 1024; + break; + case 2: + ps3v->videoRamKbytes = 6 * 1024; + break; + case 3: + ps3v->videoRamKbytes = 8 * 1024; + break; + } + ps3v->videoRamKbytes -= ps3v->MemOffScreen; + } + else if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset)) { + switch((config1 & 0xE0) >> 5) { + case 0: /* 8MB -- only 4MB usable for display/cursor */ + ps3v->videoRamKbytes = 4 * 1024; + ps3v->MemOffScreen = 4 * 1024; + break; + case 1: /* 32 bit interface -- yuck */ + xf86ErrorFVerb(VERBLEV, + " found 32 bit interface for video memory -- yuck:(\n"); + case 2: + ps3v->videoRamKbytes = 4 * 1024; + break; + case 6: + ps3v->videoRamKbytes = 2 * 1024; + break; + } + } + else if (S3_TRIO_3D_SERIES(ps3v->Chipset)) { + switch((config1 & 0xE0) >> 5) { + case 0: + case 2: + ps3v->videoRamKbytes = 4 * 1024; + break; + case 4: + ps3v->videoRamKbytes = 2 * 1024; + break; + } + } + else if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + switch((config1 & 0xC0) >> 6) { + case 1: + ps3v->videoRamKbytes = 4 * 1024; + break; + case 3: + ps3v->videoRamKbytes = 2 * 1024; + break; + } + } + else { + switch((config1 & 0xE0) >> 5) { + case 0: + ps3v->videoRamKbytes = 4 * 1024; + break; + case 4: + ps3v->videoRamKbytes = 2 * 1024; + break; + case 6: + ps3v->videoRamKbytes = 1 * 1024; + break; + } + } + /* And save a byte value also */ + ps3v->videoRambytes = ps3v->videoRamKbytes * 1024; + /* Make sure the screen also */ + /* has correct videoRam setting */ + pScrn->videoRam = ps3v->videoRamKbytes; + + if (ps3v->MemOffScreen) + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "videoram: %dk (plus %dk off-screen)\n", + ps3v->videoRamKbytes, ps3v->MemOffScreen); + else + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "videoram: %dk\n", + ps3v->videoRamKbytes); + } else { + /* Note: if ram is not probed then */ + /* ps3v->videoRamKbytes will not be init'd */ + /* should we? can do it here... */ + + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "videoram: %dk\n", + ps3v->videoRamKbytes); + } + + /* reset S3 graphics engine to avoid memory corruption */ + if (ps3v->Chipset != S3_ViRGE_VX) { + VGAOUT8(vgaCRIndex, 0x66); + cr66 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRReg, cr66 | 0x02); + usleep(10000); /* wait a little bit... */ + } + + /* + * There was a lot of plainly wrong code here. pScrn->clock is just a list + * of supported _dotclocks_ used when you don't have a programmable clock. + * + * S3V and Savage seem to think that this is the max ramdac speed. This + * driver just ignores the whole mess done before and sets + * clockRange->maxClock differently slightly later. + * + * In order to not ditch information, here is a table of what the dacspeeds + * "were" before the cleanup. + * + * Chipset ### >= 24bpp ### lower + * + * S3_ViRGE_VX 135000 220000 + * S3_TRIO_3D_2X_SERIES 135000 230000 + * S3_ViRGE_DXGX 135000 170000 + * S3_ViRGE_GX2_SERIES 135000 170000 + * S3_ViRGE_MX_SERIES 100000 135000 + * + * Others devices get: + * > 24bpp: 57000 + * = 24bpp: 95000 + * < 24bpp: 135000 + * + * Special case is the MELCO BIOS: + * > 24bpp: 83500 + * = 24bpp: 111500 + * > 8bpp: 162500 + * <= 8bpp: 191500 + */ + + if (find_bios_string(ps3v->PciTag, BIOS_BASE, "S3 86C325", + "MELCO WGP-VG VIDEO BIOS") != NULL) { + if (xf86GetVerbosity()) + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MELCO BIOS found\n"); + if (ps3v->MCLK <= 0) + ps3v->MCLK = 74000; + } + + if (ps3v->Chipset != S3_ViRGE_VX) { + VGAOUT8(vgaCRIndex, 0x66); + VGAOUT8(vgaCRReg, cr66 & ~0x02); /* clear reset flag */ + usleep(10000); /* wait a little bit... */ + } + + /* Detect current MCLK and print it for user */ + VGAOUT8(0x3c4, 0x08); + VGAOUT8(0x3c5, 0x06); + VGAOUT8(0x3c4, 0x10); + n = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x11); + m = VGAIN8(0x3c5); + m &= 0x7f; + n1 = n & 0x1f; + n2 = (n>>5) & 0x03; + mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100; + if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + MessageType is_probed = X_PROBED; + /* + * try to figure out which reference clock is used: + * Toshiba Tecra 5x0/7x0 seems to use 28.636 MHz + * Compaq Armada 7x00 uses 14.318 MHz + */ + if (find_bios_string(ps3v->PciTag, BIOS_BASE, "COMPAQ M5 BIOS", NULL) != NULL) { + if (xf86GetVerbosity()) + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "COMPAQ M5 BIOS found\n"); + /* ps3v->refclk_fact = 1.0; */ + } + else if (find_bios_string(ps3v->PciTag, BIOS_BASE, "TOSHIBA Video BIOS", NULL) != NULL) { + if (xf86GetVerbosity()) + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "TOSHIBA Video BIOS found\n"); + /* ps3v->refclk_fact = 2.0; */ + } + /* else */ { /* always use guessed value... */ + if (mclk > 60000) + ps3v->refclk_fact = 1.0; + else + ps3v->refclk_fact = 2.0; /* don't know why ??? */ + } + if (ps3v->REFCLK != 0) { + ps3v->refclk_fact = ps3v->REFCLK / 14318.0; + is_probed = X_CONFIG; + } + else + ps3v->REFCLK = (int)(14318.18 * ps3v->refclk_fact); + + mclk = (int)(mclk * ps3v->refclk_fact); + xf86DrvMsg(pScrn->scrnIndex, is_probed, "assuming RefCLK value of %1.3f MHz\n", + ps3v->REFCLK / 1000.0); + } + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of %1.3f MHz\n", + mclk / 1000.0); + + if (S3_ViRGE_MX_SERIES(ps3v->Chipset) && xf86GetVerbosity()) { + int lcdclk, h_lcd, v_lcd; + if (ps3v->LCDClk) { + lcdclk = ps3v->LCDClk; + } else { + unsigned char sr12, sr13, sr29; + VGAOUT8(0x3c4, 0x12); + sr12 = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x13); + sr13 = VGAIN8(0x3c5) & 0x7f; + VGAOUT8(0x3c4, 0x29); + sr29 = VGAIN8(0x3c5); + n1 = sr12 & 0x1f; + n2 = ((sr12>>6) & 0x03) | ((sr29 & 0x01) << 2); + lcdclk = ((int)(ps3v->refclk_fact * 1431818 * (sr13+2)) / (n1+2) / (1 << n2) + 50) / 100; + } + VGAOUT8(0x3c4, 0x61); + h_lcd = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x66); + h_lcd |= ((VGAIN8(0x3c5) & 0x02) << 7); + h_lcd = (h_lcd+1) * 8; + VGAOUT8(0x3c4, 0x69); + v_lcd = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x6e); + v_lcd |= ((VGAIN8(0x3c5) & 0x70) << 4); + v_lcd++; + xf86DrvMsg(pScrn->scrnIndex + , ps3v->LCDClk ? X_CONFIG : X_PROBED + , "LCD size %dx%d, clock %1.3f MHz\n" + , h_lcd, v_lcd + , lcdclk / 1000.0); + } + + S3VDisableMmio(pScrn); + S3VUnmapMem(pScrn); + + /* And finally set various possible option flags */ + + ps3v->bankedMono = FALSE; + + +#if 0 + vga256InfoRec.directMode = XF86DGADirectPresent; +#endif + + /* + * xf86ValidateModes will check that the mode HTotal and VTotal values + * don't exceed the chipset's limit if pScrn->maxHValue and + * pScrn->maxVValue are set. + */ + + /* todo - The virge limit is 2048 vertical & horizontal */ + /* pixels, not clock register settings. */ + /* true for all ViRGE? */ + pScrn->maxHValue = 2048; + pScrn->maxVValue = 2048; + + /* Lower depths default to config file */ + pScrn->virtualX = pScrn->display->virtualX; + /* Adjust the virtualX to meet ViRGE hardware */ + /* limits for depth 24, bpp 24 & 32. This is */ + /* mostly for 32 bpp as 1024x768 is one pixel */ + /* larger than supported. */ + if (pScrn->depth == 24) + if ( ((pScrn->bitsPerPixel/8) * pScrn->display->virtualX) > 4095 ) { + pScrn->virtualX = 4095 / (pScrn->bitsPerPixel / 8); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Virtual width adjusted, max for this depth & bpp is %d.\n", + pScrn->virtualX ); + } + + /* + * Setup the ClockRanges, which describe what clock ranges are available, + * and what sort of modes they can be used for. + */ + clockRanges = xnfcalloc(sizeof(ClockRange), 1); + clockRanges->next = NULL; + clockRanges->minClock = 10000; + if (ps3v->Chipset == S3_ViRGE_VX ) + clockRanges->maxClock = 440000; + else + clockRanges->maxClock = 270000; + clockRanges->clockIndex = -1; /* programmable */ + clockRanges->interlaceAllowed = TRUE; /* yes, S3V SVGA 3.3.2 */ + clockRanges->doubleScanAllowed = TRUE; + + /* Screen pointer */ + i = xf86ValidateModes(pScrn, + /* Available monitor modes */ + /* (DisplayModePtr availModes) */ + pScrn->monitor->Modes, + /* req mode names for screen */ + /* (char **modesNames) */ + pScrn->display->modes, + /* list of clock ranges allowed */ + /* (ClockRangePtr clockRanges) */ + clockRanges, + /* list of driver line pitches, */ + /* supply or NULL and use min/ */ + /* max below */ + /* (int *linePitches) */ + NULL, + /* min lin pitch (width) */ + /* (int minPitch) */ + 256, + /* max line pitch (width) */ + /* (int maxPitch) */ + 2048, + /* bits of granularity for line */ + /* pitch (width) above, reguired*/ + /* (int pitchInc) */ + pScrn->bitsPerPixel, + /* min virt height, 0 no limit */ + /* (int minHeight) */ + 128, + /* max virt height, 0 no limit */ + /* (int maxHeight) */ + 2048, + /* force virtX, 0 for auto */ + /* (int VirtualX) */ + /* value is adjusted above for */ + /* hardware limits */ + pScrn->virtualX, + /* force virtY, 0 for auto */ + /* (int VirtualY) */ + pScrn->display->virtualY, + /* size (bytes) of aper used to */ + /* access video memory */ + /* (unsigned long apertureSize) */ + ps3v->videoRambytes, + /* how to pick mode */ + /* (LookupModeFlags strategy) */ + LOOKUP_BEST_REFRESH); + + if (i == -1) { + S3VFreeRec(pScrn); + return FALSE; + } + /* Prune the modes marked as invalid */ + xf86PruneDriverModes(pScrn); + + if (i == 0 || pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + S3VFreeRec(pScrn); + return FALSE; + } + + xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); + /*xf86SetCrtcForModes(pScrn, 0);*/ + + /* Set the current mode to the first in the list */ + pScrn->currentMode = pScrn->modes; + + /* Print the list of modes being used */ + xf86PrintModes(pScrn); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + /* When running the STREAMS processor */ + /* the max. stride is limited to 4096-1 */ + /* so this is the virtualX limit. */ + /* STREAMS is needed for 24 & 32 bpp, */ + /* (all depth 24 modes) */ + /* This should never happen... we */ + /* checked it before ValidateModes */ + if ( ((pScrn->depth == 24) || (pScrn->depth == 16)) && + ((pScrn->bitsPerPixel/8) * pScrn->virtualX > 4095) ) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Virtual width to large for ViRGE\n"); + S3VFreeRec(pScrn); + return FALSE; + } + + /* Load bpp-specific modules */ + if( ps3v->UseFB ) + { + if( xf86LoadSubModule(pScrn, "fb") == NULL ) + { + S3VFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(fbSymbols, NULL); + } + + /* Load XAA if needed */ + if (!ps3v->NoAccel || ps3v->hwcursor ) { + char *modName = NULL; + const char **symNames = NULL; + + if (ps3v->useEXA) { + modName = "exa"; + symNames = exaSymbols; + XF86ModReqInfo req; + int errmaj, errmin; + memset(&req, 0, sizeof(req)); + req.majorversion = 2; + req.minorversion = 0; + + if ( !LoadSubModule(pScrn->module, modName, + NULL, NULL, NULL, &req, &errmaj, &errmin) ) { + LoaderErrorMsg(NULL, modName, errmaj, errmin); + S3VFreeRec(pScrn); + return FALSE; + } + } else { + modName = "xaa"; + symNames = xaaSymbols; + if ( !xf86LoadSubModule(pScrn, "xaa") ) { + S3VFreeRec(pScrn); + return FALSE; + } + } + + xf86LoaderReqSymLists(symNames, NULL); + } + + /* Load ramdac if needed */ + if (ps3v->hwcursor) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + S3VFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + + if (ps3v->shadowFB) { + if (!xf86LoadSubModule(pScrn, "shadowfb")) { + S3VFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(shadowSymbols, NULL); + } + + /* Setup WAITFIFO() for accel and ModeInit() */ + /* Needs to be done prior to first ModeInit call */ + /* and any accel activity. */ + switch(ps3v->Chipset) + { + /* GX2_SERIES chips, GX2 & TRIO_3D_2X */ + case S3_ViRGE_GX2: + case S3_TRIO_3D_2X: + ps3v->pWaitFifo = S3VWaitFifoGX2; + ps3v->pWaitCmd = S3VWaitCmdGX2; + break; + case S3_ViRGE: + case S3_ViRGE_VX: + default: + ps3v->pWaitFifo = S3VWaitFifoMain; + /* Do nothing... */ + ps3v->pWaitCmd = S3VWaitDummy; + break; + } + + return TRUE; +} + + +/* + * This is called when VT switching back to the X server. Its job is + * to reinitialise the video mode. + * + * We may wish to unmap video/MMIO memory too. + */ + + +/* Mandatory */ +static Bool +S3VEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; +/* ScreenPtr pScreen = xf86Screens[scrnIndex]->pScreen; */ + /*vgaHWPtr hwp = VGAHWPTR(pScrn);*/ + + PVERB5(" S3VEnterVT\n"); + /*vgaHWUnlockMMIO(hwp);*/ + /* Enable MMIO and map memory */ +#ifdef unmap_always + S3VMapMem(pScrn); +#endif + S3VEnableMmio(pScrn); + + S3VSave(pScrn); + return S3VModeInit(pScrn, pScrn->currentMode); +} + + +/* + * This is called when VT switching away from the X server. Its job is + * to restore the previous (text) mode. + * + * We may wish to remap video/MMIO memory too. + * + */ + +/* Mandatory */ +static void +S3VLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + S3VPtr ps3v = S3VPTR(pScrn); + vgaRegPtr vgaSavePtr = &hwp->SavedReg; + S3VRegPtr S3VSavePtr = &ps3v->SavedReg; + + PVERB5(" S3VLeaveVT\n"); + /* Like S3VRestore, but uses passed */ + /* mode registers. */ + S3VWriteMode(pScrn, vgaSavePtr, S3VSavePtr); + /* Restore standard register access */ + /* and unmap memory. */ + S3VDisableMmio(pScrn); +#ifdef unmap_always + S3VUnmapMem(pScrn); +#endif + /*vgaHWLockMMIO(hwp);*/ + +} + + +/* + * This function performs the inverse of the restore function: It saves all + * the standard and extended registers that we are going to modify to set + * up a video mode. Again, we also save the STREAMS context if it is needed. + * + * prototype + * void ChipSave(ScrnInfoPtr pScrn) + * + */ + +static void +S3VSave (ScrnInfoPtr pScrn) +{ + unsigned char cr3a, cr66; + vgaHWPtr hwp = VGAHWPTR(pScrn); + vgaRegPtr vgaSavePtr = &hwp->SavedReg; + S3VPtr ps3v = S3VPTR(pScrn); + S3VRegPtr save = &ps3v->SavedReg; + int vgaCRIndex, vgaCRReg, vgaIOBase; + vgaIOBase = hwp->IOBase; + vgaCRIndex = 0; + + vgaCRReg = 0; + + vgaCRReg = vgaIOBase + 5; + vgaCRIndex = vgaIOBase + 4; + + PVERB5(" S3VSave\n"); + + /* + * This function will handle creating the data structure and filling + * in the generic VGA portion. + */ + + VGAOUT8(vgaCRIndex, 0x66); + cr66 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRReg, cr66 | 0x80); + VGAOUT8(vgaCRIndex, 0x3a); + cr3a = VGAIN8(vgaCRReg); + save->CR3A = cr3a; + + VGAOUT8(vgaCRReg, cr3a | 0x80); + + /* VGA_SR_MODE saves mode info only, no fonts, no colormap */ + /* Save all for primary, anything */ + /* for secondary cards?, do MODE */ + /* for the moment. */ + if (xf86IsPrimaryPci(ps3v->PciInfo)) + vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL); + else + vgaHWSave(pScrn, vgaSavePtr, VGA_SR_MODE); + + VGAOUT8(vgaCRIndex, 0x66); + VGAOUT8(vgaCRReg, cr66); + VGAOUT8(vgaCRIndex, 0x3a); + VGAOUT8(vgaCRReg, cr3a); + + /* First unlock extended sequencer regs */ + VGAOUT8(0x3c4, 0x08); + save->SR08 = VGAIN8(0x3c5); + VGAOUT8(0x3c5, 0x06); + + /* Now we save all the s3 extended regs we need */ + VGAOUT8(vgaCRIndex, 0x31); + save->CR31 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x34); + save->CR34 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x36); + save->CR36 = VGAIN8(vgaCRReg); + + /* workaround cr3a corruption */ + if( !(ps3v->mx_cr3a_fix)) + { + VGAOUT8(vgaCRIndex, 0x3a); + save->CR3A = VGAIN8(vgaCRReg); + } + + if (!S3_TRIO_3D_SERIES(ps3v->Chipset)) { + VGAOUT8(vgaCRIndex, 0x40); + save->CR40 = VGAIN8(vgaCRReg); + } + if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + VGAOUT8(vgaCRIndex, 0x41); + save->CR41 = VGAIN8(vgaCRReg); + } + VGAOUT8(vgaCRIndex, 0x42); + save->CR42 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x45); + save->CR45 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x51); + save->CR51 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x53); + save->CR53 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x54); + save->CR54 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x55); + save->CR55 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x58); + save->CR58 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x63); + save->CR63 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x66); + save->CR66 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x67); + save->CR67 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x68); + save->CR68 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x69); + save->CR69 = VGAIN8(vgaCRReg); + + VGAOUT8(vgaCRIndex, 0x33); + save->CR33 = VGAIN8(vgaCRReg); + if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) || S3_ViRGE_GX2_SERIES(ps3v->Chipset) + /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) ) + { + VGAOUT8(vgaCRIndex, 0x85); + save->CR85 = VGAIN8(vgaCRReg); + } + if (ps3v->Chipset == S3_ViRGE_DXGX) { + VGAOUT8(vgaCRIndex, 0x86); + save->CR86 = VGAIN8(vgaCRReg); + } + if ((ps3v->Chipset == S3_ViRGE_GX2) || + S3_ViRGE_MX_SERIES(ps3v->Chipset) ) { + VGAOUT8(vgaCRIndex, 0x7B); + save->CR7B = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x7D); + save->CR7D = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x87); + save->CR87 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x92); + save->CR92 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x93); + save->CR93 = VGAIN8(vgaCRReg); + } + if (ps3v->Chipset == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) || + S3_ViRGE_MX_SERIES(ps3v->Chipset) || S3_TRIO_3D_SERIES(ps3v->Chipset)) { + VGAOUT8(vgaCRIndex, 0x90); + save->CR90 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x91); + save->CR91 = VGAIN8(vgaCRReg); + } + + /* Extended mode timings regs */ + + VGAOUT8(vgaCRIndex, 0x3b); + save->CR3B = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x3c); + save->CR3C = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x43); + save->CR43 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x5d); + save->CR5D = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x5e); + save->CR5E = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x65); + save->CR65 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRIndex, 0x6d); + save->CR6D = VGAIN8(vgaCRReg); + + + /* Save sequencer extended regs for DCLK PLL programming */ + + VGAOUT8(0x3c4, 0x10); + save->SR10 = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x11); + save->SR11 = VGAIN8(0x3c5); + + VGAOUT8(0x3c4, 0x12); + save->SR12 = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x13); + save->SR13 = VGAIN8(0x3c5); + if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + VGAOUT8(0x3c4, 0x29); + save->SR29 = VGAIN8(0x3c5); + } + /* SR 54,55,56,57 undocumented for GX2. Was this supposed to be CR? */ + /* (These used to be part of the above if() */ + if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + VGAOUT8(0x3c4, 0x54); + save->SR54 = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x55); + save->SR55 = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x56); + save->SR56 = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x57); + save->SR57 = VGAIN8(0x3c5); + } + + VGAOUT8(0x3c4, 0x15); + save->SR15 = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x18); + save->SR18 = VGAIN8(0x3c5); + if (S3_TRIO_3D_SERIES(ps3v->Chipset)) { + VGAOUT8(0x3c4, 0x0a); + save->SR0A = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x0F); + save->SR0F = VGAIN8(0x3c5); + } + + VGAOUT8(vgaCRIndex, 0x66); + cr66 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRReg, cr66 | 0x80); + VGAOUT8(vgaCRIndex, 0x3a); + cr3a = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRReg, cr3a | 0x80); + + /* And if streams is to be used, save that as well */ + + if(ps3v->NeedSTREAMS) { + S3VSaveSTREAMS(pScrn, save->STREAMS); + } + + /* Now save Memory Interface Unit registers */ + if( S3_ViRGE_GX2_SERIES(ps3v->Chipset) + /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) ) + { + /* No MMPR regs on MX & GX2 */ + } + else + { + save->MMPR0 = INREG(FIFO_CONTROL_REG); + save->MMPR1 = INREG(MIU_CONTROL_REG); + save->MMPR2 = INREG(STREAMS_TIMEOUT_REG); + save->MMPR3 = INREG(MISC_TIMEOUT_REG); + } + + if (xf86GetVerbosity() > 1) { + /* Debug */ + /* Which chipsets? */ + if ( + /* virge */ + ps3v->Chipset == S3_ViRGE || + /* VX */ + S3_ViRGE_VX_SERIES(ps3v->Chipset) || + /* DX & GX */ + ps3v->Chipset == S3_ViRGE_DXGX || + /* GX2 & Trio3D_2X */ + /* S3_ViRGE_GX2_SERIES(ps3v->Chipset) || */ + /* Trio3D_2X */ + /* S3_TRIO_3D_2X_SERIES(ps3v->Chipset) */ + /* MX & MX+ */ + /* S3_ViRGE_MX_SERIES(ps3v->Chipset) || */ + /* MX+ only */ + /* S3_ViRGE_MXP_SERIES(ps3v->Chipset) || */ + /* Trio3D */ + ps3v->Chipset == S3_TRIO_3D + ) + { + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "MMPR regs: %08lx %08lx %08lx %08lx\n", + (unsigned long)INREG(FIFO_CONTROL_REG), + (unsigned long)INREG(MIU_CONTROL_REG), + (unsigned long)INREG(STREAMS_TIMEOUT_REG), + (unsigned long)INREG(MISC_TIMEOUT_REG)); + } + + PVERB5("\n\nViRGE driver: saved current video mode. Register dump:\n\n"); + } + + VGAOUT8(vgaCRIndex, 0x3a); + VGAOUT8(vgaCRReg, cr3a); + VGAOUT8(vgaCRIndex, 0x66); + VGAOUT8(vgaCRReg, cr66); + /* Dup the VGA & S3V state to the */ + /* new mode state, but only first time. */ + if( !ps3v->ModeStructInit ) { + /* XXX Should check the return value of vgaHWCopyReg() */ + vgaHWCopyReg( &hwp->ModeReg, vgaSavePtr ); + memcpy( &ps3v->ModeReg, save, sizeof(S3VRegRec) ); + ps3v->ModeStructInit = TRUE; + } + + if (xf86GetVerbosity() > 1) S3VPrintRegs(pScrn); + + return; +} + + +/* This function saves the STREAMS registers to our private structure */ + +static void +S3VSaveSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams) +{ + S3VPtr ps3v = S3VPTR(pScrn); + + streams[0] = INREG(PSTREAM_CONTROL_REG); + streams[1] = INREG(COL_CHROMA_KEY_CONTROL_REG); + streams[2] = INREG(SSTREAM_CONTROL_REG); + streams[3] = INREG(CHROMA_KEY_UPPER_BOUND_REG); + streams[4] = INREG(SSTREAM_STRETCH_REG); + streams[5] = INREG(BLEND_CONTROL_REG); + streams[6] = INREG(PSTREAM_FBADDR0_REG); + streams[7] = INREG(PSTREAM_FBADDR1_REG); + streams[8] = INREG(PSTREAM_STRIDE_REG); + streams[9] = INREG(DOUBLE_BUFFER_REG); + streams[10] = INREG(SSTREAM_FBADDR0_REG); + streams[11] = INREG(SSTREAM_FBADDR1_REG); + streams[12] = INREG(SSTREAM_STRIDE_REG); + streams[13] = INREG(OPAQUE_OVERLAY_CONTROL_REG); + streams[14] = INREG(K1_VSCALE_REG); + streams[15] = INREG(K2_VSCALE_REG); + streams[16] = INREG(DDA_VERT_REG); + streams[17] = INREG(STREAMS_FIFO_REG); + streams[18] = INREG(PSTREAM_START_REG); + streams[19] = INREG(PSTREAM_WINDOW_SIZE_REG); + streams[20] = INREG(SSTREAM_START_REG); + streams[21] = INREG(SSTREAM_WINDOW_SIZE_REG); + +} + + +/* + * This function is used to restore a video mode. It writes out all + * of the standard VGA and extended S3 registers needed to setup a + * video mode. + * + * Note that our life is made more difficult because of the STREAMS + * processor which must be used for 24bpp. We need to disable STREAMS + * before we switch video modes, or we risk locking up the machine. + * We also have to follow a certain order when reenabling it. + */ +/* let's try restoring in the same order as in the 3.3.2.3 driver */ +static void +S3VWriteMode (ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr, S3VRegPtr restore) +{ + unsigned char tmp, cr3a=0, cr66, cr67; + + vgaHWPtr hwp = VGAHWPTR(pScrn); + S3VPtr ps3v = S3VPTR(pScrn); + int vgaCRIndex, vgaCRReg, vgaIOBase; + vgaIOBase = hwp->IOBase; + vgaCRIndex = vgaIOBase + 4; + vgaCRReg = vgaIOBase + 5; + + PVERB5(" S3VWriteMode\n"); + + vgaHWProtect(pScrn, TRUE); + + /* Are we going to reenable STREAMS in this new mode? */ + ps3v->STREAMSRunning = restore->CR67 & 0x0c; + + /* First reset GE to make sure nothing is going on */ + if(ps3v->Chipset == S3_ViRGE_VX) { + VGAOUT8(vgaCRIndex, 0x63); + if(VGAIN8(vgaCRReg) & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__); + } + else { + VGAOUT8(vgaCRIndex, 0x66); + if(VGAIN8(vgaCRReg) & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__); + } + + /* As per databook, always disable STREAMS before changing modes */ + VGAOUT8(vgaCRIndex, 0x67); + cr67 = VGAIN8(vgaCRReg); + if ((cr67 & 0x0c) == 0x0c) { + S3VDisableSTREAMS(pScrn); /* If STREAMS was running, disable it */ + } + + /* Restore S3 extended regs */ + VGAOUT8(vgaCRIndex, 0x63); + VGAOUT8(vgaCRReg, restore->CR63); + VGAOUT8(vgaCRIndex, 0x66); + VGAOUT8(vgaCRReg, restore->CR66); + VGAOUT8(vgaCRIndex, 0x3a); + VGAOUT8(vgaCRReg, restore->CR3A); + VGAOUT8(vgaCRIndex, 0x31); + VGAOUT8(vgaCRReg, restore->CR31); + VGAOUT8(vgaCRIndex, 0x58); + VGAOUT8(vgaCRReg, restore->CR58); + VGAOUT8(vgaCRIndex, 0x55); + VGAOUT8(vgaCRReg, restore->CR55); + + /* Extended mode timings registers */ + VGAOUT8(vgaCRIndex, 0x53); + VGAOUT8(vgaCRReg, restore->CR53); + VGAOUT8(vgaCRIndex, 0x5d); + VGAOUT8(vgaCRReg, restore->CR5D); + VGAOUT8(vgaCRIndex, 0x5e); + VGAOUT8(vgaCRReg, restore->CR5E); + VGAOUT8(vgaCRIndex, 0x3b); + VGAOUT8(vgaCRReg, restore->CR3B); + VGAOUT8(vgaCRIndex, 0x3c); + VGAOUT8(vgaCRReg, restore->CR3C); + VGAOUT8(vgaCRIndex, 0x43); + VGAOUT8(vgaCRReg, restore->CR43); + VGAOUT8(vgaCRIndex, 0x65); + VGAOUT8(vgaCRReg, restore->CR65); + VGAOUT8(vgaCRIndex, 0x6d); + VGAOUT8(vgaCRReg, restore->CR6D); + + /* Restore the desired video mode with CR67 */ + + VGAOUT8(vgaCRIndex, 0x67); + cr67 = VGAIN8(vgaCRReg) & 0xf; /* Possible hardware bug on VX? */ + VGAOUT8(vgaCRReg, 0x50 | cr67); + usleep(10000); + VGAOUT8(vgaCRIndex, 0x67); + VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c); /* Don't enable STREAMS yet */ + + /* Other mode timing and extended regs */ + VGAOUT8(vgaCRIndex, 0x34); + VGAOUT8(vgaCRReg, restore->CR34); + if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) || + /* S3_ViRGE_MX_SERIES(ps3v->Chipset) || CR40 reserved on MX */ + S3_ViRGE_MXP_SERIES(ps3v->Chipset) || + S3_ViRGE_VX_SERIES(ps3v->Chipset) || + /* S3_TRIO_3D_2X_SERIES(ps3v->Chipset) * included in GX2 series */ + ps3v->Chipset == S3_ViRGE_DXGX || + ps3v->Chipset == S3_ViRGE + ) + { + VGAOUT8(vgaCRIndex, 0x40); + VGAOUT8(vgaCRReg, restore->CR40); + } + if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + VGAOUT8(vgaCRIndex, 0x41); + VGAOUT8(vgaCRReg, restore->CR41); + } + VGAOUT8(vgaCRIndex, 0x42); + VGAOUT8(vgaCRReg, restore->CR42); + VGAOUT8(vgaCRIndex, 0x45); + VGAOUT8(vgaCRReg, restore->CR45); + VGAOUT8(vgaCRIndex, 0x51); + VGAOUT8(vgaCRReg, restore->CR51); + VGAOUT8(vgaCRIndex, 0x54); + VGAOUT8(vgaCRReg, restore->CR54); + + /* Memory timings */ + VGAOUT8(vgaCRIndex, 0x36); + VGAOUT8(vgaCRReg, restore->CR36); + VGAOUT8(vgaCRIndex, 0x68); + VGAOUT8(vgaCRReg, restore->CR68); + VGAOUT8(vgaCRIndex, 0x69); + VGAOUT8(vgaCRReg, restore->CR69); + + VGAOUT8(vgaCRIndex, 0x33); + VGAOUT8(vgaCRReg, restore->CR33); + if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) || S3_ViRGE_GX2_SERIES(ps3v->Chipset) + /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) ) + { + VGAOUT8(vgaCRIndex, 0x85); + VGAOUT8(vgaCRReg, restore->CR85); + } + if (ps3v->Chipset == S3_ViRGE_DXGX) { + VGAOUT8(vgaCRIndex, 0x86); + VGAOUT8(vgaCRReg, restore->CR86); + } + if ( (ps3v->Chipset == S3_ViRGE_GX2) || + S3_ViRGE_MX_SERIES(ps3v->Chipset) ) { + VGAOUT8(vgaCRIndex, 0x7B); + VGAOUT8(vgaCRReg, restore->CR7B); + VGAOUT8(vgaCRIndex, 0x7D); + VGAOUT8(vgaCRReg, restore->CR7D); + VGAOUT8(vgaCRIndex, 0x87); + VGAOUT8(vgaCRReg, restore->CR87); + VGAOUT8(vgaCRIndex, 0x92); + VGAOUT8(vgaCRReg, restore->CR92); + VGAOUT8(vgaCRIndex, 0x93); + VGAOUT8(vgaCRReg, restore->CR93); + } + if (ps3v->Chipset == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) || + S3_ViRGE_MX_SERIES(ps3v->Chipset) || S3_TRIO_3D_SERIES(ps3v->Chipset)) { + VGAOUT8(vgaCRIndex, 0x90); + VGAOUT8(vgaCRReg, restore->CR90); + VGAOUT8(vgaCRIndex, 0x91); + VGAOUT8(vgaCRReg, restore->CR91); + } + + /* Unlock extended sequencer regs */ + VGAOUT8(0x3c4, 0x08); + VGAOUT8(0x3c5, 0x06); + + + /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates that + * we should leave the default SR10 and SR11 values there. + */ + + if (restore->SR10 != 255) { + VGAOUT8(0x3c4, 0x10); + VGAOUT8(0x3c5, restore->SR10); + VGAOUT8(0x3c4, 0x11); + VGAOUT8(0x3c5, restore->SR11); + } + + /* Restore extended sequencer regs for DCLK */ + VGAOUT8(0x3c4, 0x12); + VGAOUT8(0x3c5, restore->SR12); + VGAOUT8(0x3c4, 0x13); + VGAOUT8(0x3c5, restore->SR13); + if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + VGAOUT8(0x3c4, 0x29); + VGAOUT8(0x3c5, restore->SR29); + } + if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + VGAOUT8(0x3c4, 0x54); + VGAOUT8(0x3c5, restore->SR54); + VGAOUT8(0x3c4, 0x55); + VGAOUT8(0x3c5, restore->SR55); + VGAOUT8(0x3c4, 0x56); + VGAOUT8(0x3c5, restore->SR56); + VGAOUT8(0x3c4, 0x57); + VGAOUT8(0x3c5, restore->SR57); + } + + VGAOUT8(0x3c4, 0x18); + VGAOUT8(0x3c5, restore->SR18); + + /* Load new m,n PLL values for DCLK & MCLK */ + VGAOUT8(0x3c4, 0x15); + tmp = VGAIN8(0x3c5) & ~0x21; + + /* databook either 0x3 or 0x20, but not both?? */ + VGAOUT8(0x3c5, tmp | 0x03); + VGAOUT8(0x3c5, tmp | 0x23); + VGAOUT8(0x3c5, tmp | 0x03); + VGAOUT8(0x3c5, restore->SR15); + if (S3_TRIO_3D_SERIES(ps3v->Chipset)) { + VGAOUT8(0x3c4, 0x0a); + VGAOUT8(0x3c5, restore->SR0A); + VGAOUT8(0x3c4, 0x0f); + VGAOUT8(0x3c5, restore->SR0F); + } + + VGAOUT8(0x3c4, 0x08); + VGAOUT8(0x3c5, restore->SR08); + + + /* Now write out CR67 in full, possibly starting STREAMS */ + + VerticalRetraceWait(); + VGAOUT8(vgaCRIndex, 0x67); + VGAOUT8(vgaCRReg, 0x50); /* For possible bug on VX?! */ + usleep(10000); + VGAOUT8(vgaCRIndex, 0x67); + VGAOUT8(vgaCRReg, restore->CR67); + + VGAOUT8(vgaCRIndex, 0x66); + cr66 = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRReg, cr66 | 0x80); + VGAOUT8(vgaCRIndex, 0x3a); + + /* workaround cr3a corruption */ + if( ps3v->mx_cr3a_fix ) + { + VGAOUT8(vgaCRReg, restore->CR3A | 0x80); + } + else + { + cr3a = VGAIN8(vgaCRReg); + VGAOUT8(vgaCRReg, cr3a | 0x80); + } + + /* And finally, we init the STREAMS processor if we have CR67 indicate 24bpp + * We also restore FIFO and TIMEOUT memory controller registers. (later...) + */ + + if (ps3v->NeedSTREAMS) { + if(ps3v->STREAMSRunning) S3VRestoreSTREAMS(pScrn, restore->STREAMS); + } + + /* Now, before we continue, check if this mode has the graphic engine ON + * If yes, then we reset it. + * This fixes some problems with corruption at 24bpp with STREAMS + * Also restore the MIU registers. + */ + +#ifndef MetroLink + if(ps3v->Chipset == S3_ViRGE_VX) { + if(restore->CR63 & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__); + } + else { + if(restore->CR66 & 0x01) S3VGEReset(pScrn,0,__LINE__,__FILE__); + } +#else + S3VGEReset(pScrn,0,__LINE__,__FILE__); +#endif + + VerticalRetraceWait(); + if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) + /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) ) + { + VGAOUT8(vgaCRIndex, 0x85); + /* primary stream threshold */ + VGAOUT8(vgaCRReg, 0x1f ); + } + else + { + OUTREG(FIFO_CONTROL_REG, restore->MMPR0); + } + if( !( S3_ViRGE_GX2_SERIES(ps3v->Chipset) + /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) )) + { + WaitIdle(); /* Don't ask... */ + OUTREG(MIU_CONTROL_REG, restore->MMPR1); + WaitIdle(); + OUTREG(STREAMS_TIMEOUT_REG, restore->MMPR2); + WaitIdle(); + OUTREG(MISC_TIMEOUT_REG, restore->MMPR3); + } + + /* Restore the standard VGA registers */ + /* False indicates no fontinfo restore. */ + /* VGA_SR_MODE restores mode info only, no font, no colormap */ + /* Do all for primary video */ + if (xf86IsPrimaryPci(ps3v->PciInfo)) + vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL); + /* Mode only for non-primary? */ + else + vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE); + /* moved from before vgaHWRestore, to prevent segfault? */ + VGAOUT8(vgaCRIndex, 0x66); + VGAOUT8(vgaCRReg, cr66); + VGAOUT8(vgaCRIndex, 0x3a); + + /* workaround cr3a corruption */ + if( ps3v->mx_cr3a_fix ) + VGAOUT8(vgaCRReg, restore->CR3A); + else + VGAOUT8(vgaCRReg, cr3a); + + if (xf86GetVerbosity() > 1) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "ViRGE driver: done restoring mode, dumping CR registers:\n"); + S3VPrintRegs(pScrn); + } + + vgaHWProtect(pScrn, FALSE); + + return; + +} + + +/* This function restores the saved STREAMS registers */ + +static void +S3VRestoreSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams) +{ + S3VPtr ps3v = S3VPTR(pScrn); + + +/* For now, set most regs to their default values for 24bpp + * Restore only those that are needed for width/height/stride + * Otherwise, we seem to get lockups because some registers + * when saved have some reserved bits set. + */ + + OUTREG(PSTREAM_CONTROL_REG, streams[0] & 0x77000000); + OUTREG(COL_CHROMA_KEY_CONTROL_REG, 0x00); + OUTREG(SSTREAM_CONTROL_REG, 0x03000000); + OUTREG(CHROMA_KEY_UPPER_BOUND_REG, 0x00); + OUTREG(SSTREAM_STRETCH_REG, 0x00); + OUTREG(BLEND_CONTROL_REG, 0x01000000); + OUTREG(PSTREAM_FBADDR0_REG, 0x00); + OUTREG(PSTREAM_FBADDR1_REG, 0x00); + OUTREG(PSTREAM_STRIDE_REG, streams[8] & 0x0fff); + OUTREG(DOUBLE_BUFFER_REG, 0x00); + OUTREG(SSTREAM_FBADDR0_REG, 0x00); + OUTREG(SSTREAM_FBADDR1_REG, 0x00); + OUTREG(SSTREAM_STRIDE_REG, 0x01); + OUTREG(OPAQUE_OVERLAY_CONTROL_REG, 0x40000000); + OUTREG(K1_VSCALE_REG, 0x00); + OUTREG(K2_VSCALE_REG, 0x00); + OUTREG(DDA_VERT_REG, 0x00); + OUTREG(PSTREAM_START_REG, 0x00010001); + OUTREG(PSTREAM_WINDOW_SIZE_REG, streams[19] & 0x07ff07ff); + OUTREG(SSTREAM_START_REG, 0x07ff07ff); + OUTREG(SSTREAM_WINDOW_SIZE_REG, 0x00010001); + + +} + + + + +/* And this function disables the STREAMS processor as per databook. + * This is usefull before we do a mode change + */ + +static void +S3VDisableSTREAMS(ScrnInfoPtr pScrn) +{ +unsigned char tmp; + vgaHWPtr hwp = VGAHWPTR(pScrn); + S3VPtr ps3v = S3VPTR(pScrn); + int vgaCRIndex, vgaCRReg, vgaIOBase; + vgaIOBase = hwp->IOBase; + vgaCRIndex = vgaIOBase + 4; + vgaCRReg = vgaIOBase + 5; + + VerticalRetraceWait(); + OUTREG(FIFO_CONTROL_REG, 0xC000); + VGAOUT8(vgaCRIndex, 0x67); + tmp = VGAIN8(vgaCRReg); + /* Disable STREAMS processor */ + VGAOUT8( vgaCRReg, tmp & ~0x0C ); + + return; +} + + + +/* MapMem - contains half of pre-4.0 EnterLeave function */ +/* The EnterLeave function which en/dis access to IO ports and ext. regs */ + /********************************************************/ + /* Aaagh... So many locations! On my machine (KJB) the*/ + /* following is true. */ + /* PciInfo->memBase[0] returns e400 0000 */ + /* From my ViRGE manual, the memory map looks like */ + /* Linear mem - 16M 000 0000 - 0ff ffff */ + /* Image xfer - 32k 100 0000 - 100 7fff */ + /* PCI cnfg 100 8000 - 100 8043 */ + /* ... */ + /* CRT VGA 3b? reg 100 83b0 - */ + /* And S3_NEWMMIO_VGABASE = S3_NEWMMIO_REGBASE + 0x8000 */ + /* where S3_NEWMMIO_REGBASE = 0x100 0000 ( 16MB ) */ + /* S3_NEWMMIO_REGSIZE = 0x1 0000 ( 64KB ) */ + /* S3V_MMIO_REGSIZE = 0x8000 ( 32KB ) - above includes */ + /* the image transfer area, so this one is used instead.*/ + /* ps3v->IOBase is assinged the virtual address returned*/ + /* from MapPciMem, it is the address to base all */ + /* register access. (It is a pointer.) */ + /* hwp->MemBase is a CARD32, containing the register */ + /* base. (It's a conversion from IOBase above.) */ + /********************************************************/ + + +static Bool +S3VMapMem(ScrnInfoPtr pScrn) +{ + S3VPtr ps3v; + vgaHWPtr hwp; + + PVERB5(" S3VMapMem\n"); + + ps3v = S3VPTR(pScrn); + + /* Map the ViRGE register space */ + /* Starts with Image Transfer area */ + /* so that we can use registers map */ + /* structure - see newmmio.h */ + /* around 0x10000 from MemBase */ + ps3v->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, ps3v->PciTag, + ps3v->PciInfo->memBase[0] + S3_NEWMMIO_REGBASE, + S3_NEWMMIO_REGSIZE); + + ps3v->MapBaseDense = xf86MapPciMem(pScrn->scrnIndex, + VIDMEM_MMIO_32BIT, + ps3v->PciTag, + ps3v->PciInfo->memBase[0] + S3_NEWMMIO_REGBASE, + 0x8000); + + if( !ps3v->MapBase ) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Internal error: could not map registers.\n"); + return FALSE; + } + /* Map the framebuffer */ + if (ps3v->videoRambytes) { /* not set in PreInit() */ + ps3v->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, + ps3v->PciTag, ps3v->PciInfo->memBase[0], + ps3v->videoRambytes ); + + if( !ps3v->FBBase ) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Internal error: could not map framebuffer.\n"); + return FALSE; + } + /* Initially the visual display start */ + /* is the same as the mapped start. */ + ps3v->FBStart = ps3v->FBBase; + } + + pScrn->memPhysBase = ps3v->PciInfo->memBase[0]; + pScrn->fbOffset = 0; + + /* Set up offset to hwcursor memory area */ + /* It's a 1K chunk at the end of the frame buffer */ + ps3v->FBCursorOffset = ps3v->videoRambytes - 1024; + S3VEnableMmio( pScrn); + /* Assign hwp->MemBase & IOBase here */ + hwp = VGAHWPTR(pScrn); + /* Sets MMIOBase and Offset, assigns */ + /* functions. Offset from map area */ + /* to VGA reg area is 0x8000. */ + vgaHWSetMmioFuncs( hwp, ps3v->MapBase, S3V_MMIO_REGSIZE ); + /* assigns hwp->IOBase to 3D0 or 3B0 */ + /* needs hwp->MMIOBase to work */ + vgaHWGetIOBase(hwp); + + /* Map the VGA memory when the */ + /* primary video */ + + if (xf86IsPrimaryPci(ps3v->PciInfo)) { + hwp->MapSize = 0x10000; + if (!vgaHWMapMem(pScrn)) + return FALSE; + ps3v->PrimaryVidMapped = TRUE; + } + + return TRUE; +} + + + +/* UnMapMem - contains half of pre-4.0 EnterLeave function */ +/* The EnterLeave function which en/dis access to IO ports and ext. regs */ + +static void +S3VUnmapMem(ScrnInfoPtr pScrn) +{ + S3VPtr ps3v; + + ps3v = S3VPTR(pScrn); + /* Unmap VGA mem if mapped. */ + if( ps3v->PrimaryVidMapped ) { + vgaHWUnmapMem( pScrn ); + ps3v->PrimaryVidMapped = FALSE; + } + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer)ps3v->MapBase, + S3_NEWMMIO_REGSIZE); + if (ps3v->FBBase) + xf86UnMapVidMem(pScrn->scrnIndex, (pointer)ps3v->FBBase, + ps3v->videoRambytes); + xf86UnMapVidMem(pScrn->scrnIndex, (pointer)ps3v->MapBaseDense, + 0x8000); + + return; +} + + + +/* Mandatory */ + +/* This gets called at the start of each server generation */ + +static Bool +S3VScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn; + S3VPtr ps3v; + int ret; + + PVERB5(" S3VScreenInit\n"); + /* First get the ScrnInfoRec */ + pScrn = xf86Screens[pScreen->myNum]; + /* Get S3V rec */ + ps3v = S3VPTR(pScrn); + /* Make sure we have card access */ +/* xf86EnableAccess(pScrn);*/ + /* Map MMIO regs and framebuffer */ + if( !S3VMapMem(pScrn) ) + return FALSE; + /* Save the chip/graphics state */ + S3VSave(pScrn); + /* Blank the screen during init */ + vgaHWBlankScreen(pScrn, TRUE ); + /* Initialise the first mode */ + if (!S3VModeInit(pScrn, pScrn->currentMode)) + return FALSE; + + /* + * The next step is to setup the screen's visuals, and initialise the + * framebuffer code. In cases where the framebuffer's default + * choices for things like visual layouts and bits per RGB are OK, + * this may be as simple as calling the framebuffer's ScreenInit() + * function. If not, the visuals will need to be setup before calling + * a fb ScreenInit() function and fixed up after. + * + * For most PC hardware at depths >= 8, the defaults that fb uses + * are not appropriate. In this driver, we fixup the visuals after. + */ + + /* + * Reset the visual list. + */ + miClearVisualTypes(); + + /* Setup the visuals we support. */ + + /* + * For bpp > 8, the default visuals are not acceptable because we only + * support TrueColor and not DirectColor. To deal with this, call + * miSetVisualTypes with the appropriate visual mask. + */ + + if (pScrn->bitsPerPixel > 8) { + if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits, + pScrn->defaultVisual)) + return FALSE; + + if (!miSetPixmapDepths ()) + return FALSE; + } else { + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + + if (!miSetPixmapDepths ()) + return FALSE; + } + + ret = S3VInternalScreenInit(scrnIndex, pScreen); + + if (!ret) + return FALSE; + + xf86SetBlackWhitePixels(pScreen); + + if (pScrn->bitsPerPixel > 8) { + VisualPtr visual; + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + /* must be after RGB ordering fixed */ + if (ps3v->UseFB) + fbPictureInit (pScreen, 0, 0); + + /* Initialize acceleration layer */ + if (!ps3v->NoAccel) { + if(pScrn->bitsPerPixel == 32) { + /* 32 bit Accel currently broken + if (!S3VAccelInit32(pScreen)) + return FALSE; + */ + ; + } else + if (!S3VAccelInit(pScreen)) + return FALSE; + } + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + xf86SetSilkenMouse(pScreen); + /* hardware cursor needs to wrap this layer */ + if ( !ps3v->shadowFB && !ps3v->useEXA ) + S3VDGAInit(pScreen); + + /* Initialise cursor functions */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Initialize HW cursor layer. + Must follow software cursor initialization*/ + if (ps3v->hwcursor) { + if(!S3VHWCursorInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); + } + } + + if (ps3v->shadowFB) { + RefreshAreaFuncPtr refreshArea = s3vRefreshArea; + + if(ps3v->rotate) { + if (!ps3v->PointerMoved) { + ps3v->PointerMoved = pScrn->PointerMoved; + pScrn->PointerMoved = s3vPointerMoved; + } + + switch(pScrn->bitsPerPixel) { + case 8: refreshArea = s3vRefreshArea8; break; + case 16: refreshArea = s3vRefreshArea16; break; + case 24: refreshArea = s3vRefreshArea24; break; + case 32: refreshArea = s3vRefreshArea32; break; + } + } + + ShadowFBInit(pScreen, refreshArea); + } + + /* Initialise default colourmap */ + if (!miCreateDefColormap(pScreen)) + return FALSE; + /* Initialize colormap layer. */ + /* Must follow initialization */ + /* of the default colormap. */ + /* And SetGamma call, else it */ + /* will load palette with solid */ + /* white. */ + if(!xf86HandleColormaps(pScreen, 256, 6, S3VLoadPalette, NULL, + CMAP_RELOAD_ON_MODE_SWITCH )) + return FALSE; + /* All the ugly stuff is done, */ + /* so re-enable the screen. */ + vgaHWBlankScreen(pScrn, FALSE ); + +#if 0 + pScrn->racMemFlags = RAC_COLORMAP | RAC_CURSOR | RAC_FB | RAC_VIEWPORT; +#endif + pScreen->SaveScreen = S3VSaveScreen; + + /* Wrap the current CloseScreen function */ + ps3v->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = S3VCloseScreen; + + if(xf86DPMSInit(pScreen, S3VDisplayPowerManagementSet, 0) == FALSE) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n"); + + S3VInitVideo(pScreen); + + /* Report any unused options (only for the first generation) */ + if (serverGeneration == 1) { + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + } + /* Done */ + return TRUE; +} + + + +/* Common init routines needed in EnterVT and ScreenInit */ + +static int +S3VInternalScreenInit( int scrnIndex, ScreenPtr pScreen) +{ + int ret = TRUE; + ScrnInfoPtr pScrn; + S3VPtr ps3v; + int width, height, displayWidth; + unsigned char* FBStart; + + /* First get the ScrnInfoRec */ + pScrn = xf86Screens[pScreen->myNum]; + + ps3v = S3VPTR(pScrn); + + displayWidth = pScrn->displayWidth; + if (ps3v->rotate) { + height = pScrn->virtualX; + width = pScrn->virtualY; + } else { + width = pScrn->virtualX; + height = pScrn->virtualY; + } + + if(ps3v->shadowFB) { + ps3v->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width); + ps3v->ShadowPtr = xalloc(ps3v->ShadowPitch * height); + displayWidth = ps3v->ShadowPitch / (pScrn->bitsPerPixel >> 3); + FBStart = ps3v->ShadowPtr; + } else { + ps3v->ShadowPtr = NULL; + FBStart = ps3v->FBStart; + } + + /* + * Call the framebuffer layer's ScreenInit function, and fill in other + * pScreen fields. + */ + + if( ps3v->UseFB ) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using FB\n"); + + switch (pScrn->bitsPerPixel) + { + case 8: + case 16: + case 24: + ret = fbScreenInit(pScreen, FBStart, pScrn->virtualX, + pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, + displayWidth, pScrn->bitsPerPixel); + break; + default: + xf86DrvMsg(scrnIndex, X_ERROR, + "Internal error: invalid bpp (%d) in S3VScreenInit\n", + pScrn->bitsPerPixel); + ret = FALSE; + break; + } + } + return ret; +} + + + +/* Checks if a mode is suitable for the selected chipset. */ + +static ModeStatus +S3VValidMode(int index, DisplayModePtr mode, Bool verbose, int flags) +{ + + return MODE_OK; +} + + + +static Bool +S3VModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + S3VPtr ps3v = S3VPTR(pScrn); + int width, dclk; + int i, j; + unsigned char tmp = 0; + + /* Store values to current mode register structs */ + S3VRegPtr new = &ps3v->ModeReg; + vgaRegPtr vganew = &hwp->ModeReg; + int vgaCRIndex, vgaCRReg, vgaIOBase; + + vgaIOBase = hwp->IOBase; + vgaCRIndex = vgaIOBase + 4; + vgaCRReg = vgaIOBase + 5; + + PVERB5(" S3VModeInit\n"); + + /* Set scale factors for mode timings */ + + if (ps3v->Chipset == S3_ViRGE_VX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) || + S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + ps3v->HorizScaleFactor = 1; + } + else if (pScrn->bitsPerPixel == 8) { + ps3v->HorizScaleFactor = 1; + } + else if (pScrn->bitsPerPixel == 16) { + if (S3_TRIO_3D_SERIES(ps3v->Chipset) && mode->Clock > 115000) + ps3v->HorizScaleFactor = 1; + else + ps3v->HorizScaleFactor = 2; + } + else { + ps3v->HorizScaleFactor = 1; + } + + + /* First we adjust the horizontal timings if needed */ + + if(ps3v->HorizScaleFactor != 1) + if (!mode->CrtcHAdjusted) { + mode->CrtcHDisplay *= ps3v->HorizScaleFactor; + mode->CrtcHSyncStart *= ps3v->HorizScaleFactor; + mode->CrtcHSyncEnd *= ps3v->HorizScaleFactor; + mode->CrtcHTotal *= ps3v->HorizScaleFactor; + mode->CrtcHSkew *= ps3v->HorizScaleFactor; + mode->CrtcHAdjusted = TRUE; + } + + if(!vgaHWInit (pScrn, mode)) + return FALSE; + + /* Now we fill in the rest of the stuff we need for the virge */ + /* Start with MMIO, linear addr. regs */ + + VGAOUT8(vgaCRIndex, 0x3a); + tmp = VGAIN8(vgaCRReg); + if( S3_ViRGE_GX2_SERIES(ps3v->Chipset) + /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) ) + { + if(ps3v->pci_burst) + /*new->CR3A = (tmp & 0x38) | 0x10; / ENH 256, PCI burst */ + /* Don't clear reserved bits... */ + new->CR3A = (tmp & 0x7f) | 0x10; /* ENH 256, PCI burst */ + else + new->CR3A = tmp | 0x90; /* ENH 256, no PCI burst! */ + } + else + { + if(ps3v->pci_burst) + new->CR3A = (tmp & 0x7f) | 0x15; /* ENH 256, PCI burst */ + else + new->CR3A = tmp | 0x95; /* ENH 256, no PCI burst! */ + } + + + VGAOUT8(vgaCRIndex, 0x55); + new->CR55 = VGAIN8(vgaCRReg); + if (ps3v->hwcursor) + new->CR55 |= 0x10; /* Enables X11 hw cursor mode */ + if (S3_TRIO_3D_SERIES(ps3v->Chipset)) { + new->CR31 = 0x0c; /* [trio3d] page 54 */ + } else { + new->CR53 = 0x08; /* Enables MMIO */ + new->CR31 = 0x8c; /* Dis. 64k window, en. ENH maps */ + } + + /* Enables S3D graphic engine and PCI disconnects */ + if(ps3v->Chipset == S3_ViRGE_VX){ + new->CR66 = 0x90; + new->CR63 = 0x09; + } + else { + new->CR66 = 0x89; + /* Set display fifo */ + if( S3_ViRGE_GX2_SERIES(ps3v->Chipset) || + S3_ViRGE_MX_SERIES(ps3v->Chipset) ) + { + /* Changed from 0x08 based on reports that this */ + /* prevents MX from running properly below 1024x768 */ + new->CR63 = 0x10; + } + else + { + new->CR63 = 0; + } + } + + /* Now set linear addr. registers */ + /* LAW size: we have 2 cases, 2MB, 4MB or >= 4MB for VX */ + VGAOUT8(vgaCRIndex, 0x58); + new->CR58 = VGAIN8(vgaCRReg) & 0x80; + if(pScrn->videoRam == 2048){ + new->CR58 |= 0x02 | 0x10; + } + else if (pScrn->videoRam == 1024) { + new->CR58 |= 0x01 | 0x10; + } + else { + if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) && pScrn->videoRam == 8192) + new->CR58 |= 0x07 | 0x10; /* 8MB window on Trio3D/2X */ + else + new->CR58 |= 0x03 | 0x10; /* 4MB window on virge, 8MB on VX */ + } + if(ps3v->Chipset == S3_ViRGE_VX) + new->CR58 |= 0x40; + if (ps3v->early_ras_precharge) + new->CR58 |= 0x80; + if (ps3v->late_ras_precharge) + new->CR58 &= 0x7f; + + /* ** On PCI bus, no need to reprogram the linear window base address */ + + /* Now do clock PLL programming. Use the s3gendac function to get m,n */ + /* Also determine if we need doubling etc. */ + + dclk = mode->Clock; + new->CR67 = 0x00; /* Defaults */ + + if (!S3_TRIO_3D_SERIES(ps3v->Chipset)) + new->SR15 = 0x03 | 0x80; + else { + VGAOUT8(0x3c4, 0x15); + new->SR15 = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x0a); + new->SR0A = VGAIN8(0x3c5); + if (ps3v->slow_dram) { + new->SR15 = 0x03; /* 3 CYC MWR */ + new->SR0A &= 0x7F; + } else if (ps3v->fast_dram) { + new->SR15 = 0x03 | 0x80; /* 2 CYC MWR */ + new->SR0A |= 0x80; + } else { /* keep BIOS init defaults */ + new->SR15 = (new->SR15 & 0x80) | 0x03; + } + } + new->SR18 = 0x00; + new->CR43 = 0x00; + new->CR45 = 0x00; + /* Enable MMIO to RAMDAC registers */ + new->CR65 = 0x00; /* CR65_2 must be zero, doc seems to be wrong */ + new->CR54 = 0x00; + + if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) || + /* S3_ViRGE_MX_SERIES(ps3v->Chipset) || CR40 reserved on MX */ + S3_ViRGE_MXP_SERIES(ps3v->Chipset) || + S3_ViRGE_VX_SERIES(ps3v->Chipset) || + /* S3_TRIO_3D_2X_SERIES(ps3v->Chipset) * included in GX2 series */ + ps3v->Chipset == S3_ViRGE_DXGX || + ps3v->Chipset == S3_ViRGE + ) { + VGAOUT8(vgaCRIndex, 0x40); + new->CR40 = VGAIN8(vgaCRReg) & ~0x01; + } + + if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + /* fix problems with APM suspend/resume trashing CR90/91 */ + switch(pScrn->bitsPerPixel) { + case 8: new->CR41 = 0x38; break; + case 15: new->CR41 = 0x58; break; + case 16: new->CR41 = 0x48; break; + default: new->CR41 = 0x77; + } + } + + xf86ErrorFVerb(VERBLEV, " S3VModeInit dclk=%i \n", + dclk + ); + + /* Memory controller registers. Optimize for better graphics engine + * performance. These settings are adjusted/overridden below for other bpp/ + * XConfig options.The idea here is to give a longer number of contiguous + * MCLK's to both refresh and the graphics engine, to diminish the + * relative penalty of 3 or 4 mclk's needed to setup memory transfers. + */ + new->MMPR0 = 0x010400; /* defaults */ + new->MMPR1 = 0x00; + new->MMPR2 = 0x0808; + new->MMPR3 = 0x08080810; + + /* + * These settings look like they ought to be better adjusted for depth, + * so for problem modes running without any fifo_ option should be + * usable. Note that these adjust some memory timings and relate to + * the boards MCLK setting. + * */ + if( ps3v->fifo_aggressive || ps3v->fifo_moderate || + ps3v->fifo_conservative ) { + + new->MMPR1 = 0x0200; /* Low P. stream waits before filling */ + new->MMPR2 = 0x1808; /* Let the FIFO refill itself */ + new->MMPR3 = 0x08081810; /* And let the GE hold the bus for a while */ + } + + /* And setup here the new value for MCLK. We use the XConfig + * option "set_mclk", whose value gets stored in ps3v->MCLK. + * I'm not sure what the maximum "permitted" value should be, probably + * 100 MHz is more than enough for now. + */ + + if(ps3v->MCLK> 0) { + if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) + S3VCommonCalcClock(pScrn, mode, + (int)(ps3v->MCLK / ps3v->refclk_fact), + 1, 1, 31, 0, 3, + 135000, 270000, &new->SR11, &new->SR10); + else + S3VCommonCalcClock(pScrn, mode, ps3v->MCLK, 1, 1, 31, 0, 3, + 135000, 270000, &new->SR11, &new->SR10); + } + else { + new->SR10 = 255; /* This is a reserved value, so we use as flag */ + new->SR11 = 255; + } + + /* most modes don't need STREAMS */ + /* processor, preset FALSE */ + /* support for XVideo needs streams, so added it to some modes */ + ps3v->NeedSTREAMS = FALSE; + + if(ps3v->Chipset == S3_ViRGE_VX){ + if (pScrn->bitsPerPixel == 8) { + if (dclk <= 110000) new->CR67 = 0x00; /* 8bpp, 135MHz */ + else new->CR67 = 0x10; /* 8bpp, 220MHz */ + } + else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) { + if (dclk <= 110000) new->CR67 = 0x20; /* 15bpp, 135MHz */ + else new->CR67 = 0x30; /* 15bpp, 220MHz */ + } + else if (pScrn->bitsPerPixel == 16) { + if (dclk <= 110000) new->CR67 = 0x40; /* 16bpp, 135MHz */ + else new->CR67 = 0x50; /* 16bpp, 220MHz */ + } + else if ((pScrn->bitsPerPixel == 24) || (pScrn->bitsPerPixel == 32)) { + new->CR67 = 0xd0 | 0x0c; /* 24bpp, 135MHz, STREAMS */ + /* Flag STREAMS proc. required */ + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + new->MMPR0 = 0xc098; /* Adjust FIFO slots */ + } + S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 4, + 220000, 440000, &new->SR13, &new->SR12); + + } /* end VX if() */ + else if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + if (pScrn->bitsPerPixel == 8) + new->CR67 = 0x00; + else if (pScrn->bitsPerPixel == 16) { + /* XV support needs STREAMS in depth 16 */ + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + if (pScrn->weight.green == 5) + new->CR67 = 0x30 | 0x4; /* 15bpp */ + else + new->CR67 = 0x50 | 0x4; /* 16bpp */ + } + else if ((pScrn->bitsPerPixel == 24) ) { + new->CR67 = 0x74; /* 24bpp, STREAMS */ + /* Flag STREAMS proc. required */ + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + } + else if (pScrn->bitsPerPixel == 32) { + new->CR67 = 0xd0; /* 32bpp */ + /* Missing STREAMs and other stuff here? KJB */ + /* new->MMPR0 = 0xc098; / Adjust FIFO slots */ + } + { + unsigned char ndiv; + if (S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + unsigned char sr8; + VGAOUT8(0x3c4, 0x08); /* unlock extended SEQ regs */ + sr8 = VGAIN8(0x3c5); + VGAOUT8(0x3c5, 0x06); + VGAOUT8(0x3c4, 0x31); + if (VGAIN8(0x3c5) & 0x10) { /* LCD on */ + if (!ps3v->LCDClk) { /* entered only once for first mode */ + int h_lcd, v_lcd; + VGAOUT8(0x3c4, 0x61); + h_lcd = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x66); + h_lcd |= ((VGAIN8(0x3c5) & 0x02) << 7); + h_lcd = (h_lcd+1) * 8; + VGAOUT8(0x3c4, 0x69); + v_lcd = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x6e); + v_lcd |= ((VGAIN8(0x3c5) & 0x70) << 4); + v_lcd++; + + /* check if first mode has physical LCD resolution */ + if (pScrn->modes->HDisplay == h_lcd && pScrn->modes->VDisplay == v_lcd) + ps3v->LCDClk = mode->Clock; + else { + int n1, n2, sr12, sr13, sr29; + VGAOUT8(0x3c4, 0x12); + sr12 = VGAIN8(0x3c5); + VGAOUT8(0x3c4, 0x13); + sr13 = VGAIN8(0x3c5) & 0x7f; + VGAOUT8(0x3c4, 0x29); + sr29 = VGAIN8(0x3c5); + n1 = sr12 & 0x1f; + n2 = ((sr12>>6) & 0x03) | ((sr29 & 0x01) << 2); + ps3v->LCDClk = ((int)(ps3v->refclk_fact * 1431818 * (sr13+2)) / (n1+2) / (1 << n2) + 50) / 100; + } + } + S3VCommonCalcClock(pScrn, mode, + (int)(ps3v->LCDClk / ps3v->refclk_fact), + 1, 1, 31, 0, 4, + 170000, 340000, &new->SR13, &ndiv); + } + else + S3VCommonCalcClock(pScrn, mode, + (int)(dclk / ps3v->refclk_fact), + 1, 1, 31, 0, 4, + 170000, 340000, &new->SR13, &ndiv); + VGAOUT8(0x3c4, 0x08); + VGAOUT8(0x3c5, sr8); + } + else /* S3_ViRGE_GX2 */ + S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 4, + 170000, 340000, &new->SR13, &ndiv); + new->SR29 = ndiv >> 7; + new->SR12 = (ndiv & 0x1f) | ((ndiv & 0x60) << 1); + } + } /* end GX2 or MX if() */ + else if(S3_TRIO_3D_SERIES(ps3v->Chipset)) { + new->SR0F = 0x00; + if (pScrn->bitsPerPixel == 8) { + if(dclk > 115000) { /* We need pixmux */ + new->CR67 = 0x10; + new->SR15 |= 0x10; /* Set DCLK/2 bit */ + new->SR18 = 0x80; /* Enable pixmux */ + } + } + else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) { + if(dclk > 115000) { + new->CR67 = 0x20; + new->SR15 |= 0x10; + new->SR18 = 0x80; + new->SR0F = 0x10; + } else { + new->CR67 = 0x30; /* 15bpp */ + } + } + else if (pScrn->bitsPerPixel == 16) { + if(dclk > 115000) { + new->CR67 = 0x40; + new->SR15 |= 0x10; + new->SR18 = 0x80; + new->SR0F = 0x10; + } else { + new->CR67 = 0x50; + } + } + else if (pScrn->bitsPerPixel == 24) { + new->CR67 = 0xd0 | 0x0c; + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + new->MMPR0 = 0xc000; /* Adjust FIFO slots */ + } + else if (pScrn->bitsPerPixel == 32) { + new->CR67 = 0xd0 | 0x0c; + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + new->MMPR0 = 0x10000; /* Still more FIFO slots */ + new->SR0F = 0x10; + } + S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 4, + 230000, 460000, &new->SR13, &new->SR12); + } /* end TRIO_3D if() */ + else if(ps3v->Chipset == S3_ViRGE_DXGX) { + if (pScrn->bitsPerPixel == 8) { + if(dclk > 80000) { /* We need pixmux */ + new->CR67 = 0x10; + new->SR15 |= 0x10; /* Set DCLK/2 bit */ + new->SR18 = 0x80; /* Enable pixmux */ + } + } + else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) { + new->CR67 = 0x30; /* 15bpp */ + } + else if (pScrn->bitsPerPixel == 16) { + if(mode->Flags & V_DBLSCAN) + { + new->CR67 = 0x50; + } + else + { + new->CR67 = 0x50 | 0x0c; + /* Flag STREAMS proc. required */ + /* XV support needs STREAMS in depth 16 */ + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + } + if( ps3v->XVideo ) + { + new->MMPR0 = 0x107c02; /* Adjust FIFO slots, overlay */ + } + else + { + new->MMPR0 = 0xc000; /* Adjust FIFO slots */ + } + } + else if (pScrn->bitsPerPixel == 24) { + new->CR67 = 0xd0 | 0x0c; + /* Flag STREAMS proc. required */ + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + if( ps3v->XVideo ) + { + new->MMPR0 = 0x107c02; /* Adjust FIFO slots, overlay */ + } + else + { + new->MMPR0 = 0xc000; /* Adjust FIFO slots */ + } + } + else if (pScrn->bitsPerPixel == 32) { + new->CR67 = 0xd0 | 0x0c; + /* Flag STREAMS proc. required */ + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + new->MMPR0 = 0x10000; /* Still more FIFO slots */ + } + S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 3, + 135000, 270000, &new->SR13, &new->SR12); + } /* end DXGX if() */ + else { /* Everything else ... (only ViRGE) */ + if (pScrn->bitsPerPixel == 8) { + if(dclk > 80000) { /* We need pixmux */ + new->CR67 = 0x10; + new->SR15 |= 0x10; /* Set DCLK/2 bit */ + new->SR18 = 0x80; /* Enable pixmux */ + } + } + else if ((pScrn->bitsPerPixel == 16) && (pScrn->weight.green == 5)) { + new->CR67 = 0x30; /* 15bpp */ + } + else if (pScrn->bitsPerPixel == 16) { + new->CR67 = 0x50; + } + else if (pScrn->bitsPerPixel == 24) { + new->CR67 = 0xd0 | 0x0c; + /* Flag STREAMS proc. required */ + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + new->MMPR0 = 0xc000; /* Adjust FIFO slots */ + } + else if (pScrn->bitsPerPixel == 32) { + new->CR67 = 0xd0 | 0x0c; + /* Flag STREAMS proc. required */ + ps3v->NeedSTREAMS = TRUE; + S3VInitSTREAMS(pScrn, new->STREAMS, mode); + new->MMPR0 = 0x10000; /* Still more FIFO slots */ + } + S3VCommonCalcClock(pScrn, mode, dclk, 1, 1, 31, 0, 3, + 135000, 270000, &new->SR13, &new->SR12); + } /* end great big if()... */ + + + /* Now adjust the value of the FIFO based upon options specified */ + if( ps3v->fifo_moderate ) { + if(pScrn->bitsPerPixel < 24) + new->MMPR0 -= 0x8000; + else + new->MMPR0 -= 0x4000; + } + else if( ps3v->fifo_aggressive ) { + if(pScrn->bitsPerPixel < 24) + new->MMPR0 -= 0xc000; + else + new->MMPR0 -= 0x6000; + } + + /* If we have an interlace mode, set the interlace bit. Note that mode + * vertical timings are already adjusted by the standard VGA code + */ + if(mode->Flags & V_INTERLACE) { + new->CR42 = 0x20; /* Set interlace mode */ + } + else { + new->CR42 = 0x00; + } + + if(S3_ViRGE_GX2_SERIES(ps3v->Chipset) || + S3_ViRGE_MX_SERIES(ps3v->Chipset) ) + { + new->CR34 = 0; + } + else + { + /* Set display fifo */ + new->CR34 = 0x10; + } + /* Now we adjust registers for extended mode timings */ + /* This is taken without change from the accel/s3_virge code */ + + i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) | + ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) | + ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) | + ((mode->CrtcHSyncStart & 0x800) >> 7); + + if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64) + i |= 0x08; /* add another 64 DCLKs to blank pulse width */ + + if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32) + i |= 0x20; /* add another 32 DCLKs to hsync pulse width */ + + /* video playback chokes if sync start and display end are equal */ + if (mode->CrtcHSyncStart - mode->CrtcHDisplay < ps3v->HorizScaleFactor) { + int tmp = vganew->CRTC[4] + ((i&0x10)<<4) + ps3v->HorizScaleFactor; + vganew->CRTC[4] = tmp & 0xff; + i |= ((tmp >> 4) & 0x10); + } + + j = ( vganew->CRTC[0] + ((i&0x01)<<8) + + vganew->CRTC[4] + ((i&0x10)<<4) + 1) / 2; + + if (j-(vganew->CRTC[4] + ((i&0x10)<<4)) < 4) { + if (vganew->CRTC[4] + ((i&0x10)<<4) + 4 <= vganew->CRTC[0]+ ((i&0x01)<<8)) + j = vganew->CRTC[4] + ((i&0x10)<<4) + 4; + else + j = vganew->CRTC[0]+ ((i&0x01)<<8) + 1; + } + new->CR3B = j & 0xFF; + i |= (j & 0x100) >> 2; + new->CR3C = (vganew->CRTC[0] + ((i&0x01)<<8))/2; + new->CR5D = i; + + new->CR5E = (((mode->CrtcVTotal - 2) & 0x400) >> 10) | + (((mode->CrtcVDisplay - 1) & 0x400) >> 9) | + (((mode->CrtcVSyncStart) & 0x400) >> 8) | + (((mode->CrtcVSyncStart) & 0x400) >> 6) | 0x40; + + + width = (pScrn->displayWidth * (pScrn->bitsPerPixel / 8))>> 3; + vganew->CRTC[19] = 0xFF & width; + new->CR51 = (0x300 & width) >> 4; /* Extension bits */ + + /* Set doublescan */ + if( mode->Flags & V_DBLSCAN) + vganew->CRTC[9] |= 0x80; + + /* And finally, select clock source 2 for programmable PLL */ + vganew->MiscOutReg |= 0x0c; + + + new->CR33 = 0x20; + if (S3_TRIO_3D_2X_SERIES(ps3v->Chipset) || S3_ViRGE_GX2_SERIES(ps3v->Chipset) + /* MXTESTME */ || S3_ViRGE_MX_SERIES(ps3v->Chipset) ) + { + new->CR85 = 0x12; /* avoid sreen flickering */ + /* by increasing FIFO filling, larger # fills FIFO from memory earlier */ + /* on GX2 this affects all depths, not just those running STREAMS. */ + /* new, secondary stream settings. */ + new->CR87 = 0x10; + /* gx2 - set up in XV init code */ + new->CR92 = 0x00; + new->CR93 = 0x00; + /* gx2 primary mclk timeout, def=0xb */ + new->CR7B = 0xb; + /* gx2 secondary mclk timeout, def=0xb */ + new->CR7D = 0xb; + } + if (ps3v->Chipset == S3_ViRGE_DXGX || S3_TRIO_3D_SERIES(ps3v->Chipset)) { + new->CR86 = 0x80; /* disable DAC power saving to avoid bright left edge */ + } + if (ps3v->Chipset == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(ps3v->Chipset) || + S3_ViRGE_MX_SERIES(ps3v->Chipset) || S3_TRIO_3D_SERIES(ps3v->Chipset)) { + int dbytes = pScrn->displayWidth * ((pScrn->bitsPerPixel+7)/8); + new->CR91 = (dbytes + 7) / 8; + new->CR90 = (((dbytes + 7) / 8) >> 8) | 0x80; + } + + + /* Now we handle various XConfig memory options and others */ + + VGAOUT8(vgaCRIndex, 0x36); + new->CR36 = VGAIN8(vgaCRReg); + /* option "slow_edodram" sets EDO to 2 cycle mode on ViRGE */ + if (ps3v->Chipset == S3_ViRGE) { + if( ps3v->slow_edodram ) + new->CR36 = (new->CR36 & 0xf3) | 0x08; + else + new->CR36 &= 0xf3; + } + + /* Option "fpm_vram" for ViRGE_VX sets memory in fast page mode */ + if (ps3v->Chipset == S3_ViRGE_VX) { + if( ps3v->fpm_vram ) + new->CR36 |= 0x0c; + else + new->CR36 &= ~0x0c; + } + + /* S3_INVERT_VCLK was defaulted to 0 */ + /* in 3.3.3 and never changed. */ + /* Also, bit 0 is never set in 3.9Nm, */ + /* so I left this out for 4.0. */ +#if 0 + if (mode->Private[0] & (1 << S3_INVERT_VCLK)) { + if (mode->Private[S3_INVERT_VCLK]) + new->CR67 |= 1; + else + new->CR67 &= ~1; + } +#endif + /* S3_BLANK_DELAY settings based on */ + /* defaults only. From 3.3.3 */ + { + int blank_delay; + + if(ps3v->Chipset == S3_ViRGE_VX) + /* these values need to be changed once CR67_1 is set + for gamma correction (see S3V server) ! */ + if (pScrn->bitsPerPixel == 8) + blank_delay = 0x00; + else if (pScrn->bitsPerPixel == 16) + blank_delay = 0x00; + else + blank_delay = 0x51; + else + if (pScrn->bitsPerPixel == 8) + blank_delay = 0x00; + else if (pScrn->bitsPerPixel == 16) + blank_delay = 0x02; + else + blank_delay = 0x04; + + if (ps3v->Chipset == S3_ViRGE_VX) + new->CR6D = blank_delay; + else { + new->CR65 = (new->CR65 & ~0x38) + | (blank_delay & 0x07) << 3; + VGAOUT8(vgaCRIndex, 0x6d); + new->CR6D = VGAIN8(vgaCRReg); + } + } + /* S3_EARLY_SC was defaulted to 0 */ + /* in 3.3.3 and never changed. */ + /* Also, bit 1 is never set in 3.9Nm, */ + /* so I left this out for 4.0. */ +#if 0 + if (mode->Private[0] & (1 << S3_EARLY_SC)) { + if (mode->Private[S3_EARLY_SC]) + new->CR65 |= 2; + else + new->CR65 &= ~2; + } +#endif + + VGAOUT8(vgaCRIndex, 0x68); + new->CR68 = VGAIN8(vgaCRReg); + new->CR69 = 0; + + /* Flat panel centering and expansion registers */ + if (S3_ViRGE_MX_SERIES(ps3v->Chipset) && (ps3v->lcd_center)) { + new->SR54 = 0x10 ; + new->SR55 = 0x80 ; + new->SR56 = 0x10 ; + new->SR57 = 0x80 ; + } else { + new->SR54 = 0x1f ; + new->SR55 = 0x9f ; + new->SR56 = 0x1f ; + new->SR57 = 0xff ; + } + + pScrn->vtSema = TRUE; + + /* Do it! Write the mode registers */ + /* to hardware, start STREAMS if */ + /* needed, etc. */ + S3VWriteMode( pScrn, vganew, new ); + /* Adjust the viewport */ + S3VAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + return TRUE; +} + + +/* + * This is called at the end of each server generation. It restores the + * original (text) mode. It should also unmap the video memory, and free + * any per-generation data allocated by the driver. It should finish + * by unwrapping and calling the saved CloseScreen function. + */ + +/* Mandatory */ +static Bool +S3VCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + S3VPtr ps3v = S3VPTR(pScrn); + vgaRegPtr vgaSavePtr = &hwp->SavedReg; + S3VRegPtr S3VSavePtr = &ps3v->SavedReg; + + /* Like S3VRestore, but uses passed */ + /* mode registers. */ + if (pScrn->vtSema) { + S3VWriteMode(pScrn, vgaSavePtr, S3VSavePtr); + vgaHWLock(hwp); + S3VDisableMmio(pScrn); + S3VUnmapMem(pScrn); + } + + if (ps3v->EXADriverPtr) { + exaDriverFini(pScreen); + ps3v->EXADriverPtr = NULL; + } + + if (ps3v->AccelInfoRec) { + XAADestroyInfoRec(ps3v->AccelInfoRec); + ps3v->AccelInfoRec = NULL; + } + + if (ps3v->DGAModes) + xfree(ps3v->DGAModes); + + pScrn->vtSema = FALSE; + + pScreen->CloseScreen = ps3v->CloseScreen; + + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + + + + +/* Do screen blanking */ + +/* Mandatory */ +static Bool +S3VSaveScreen(ScreenPtr pScreen, int mode) +{ + return vgaHWSaveScreen(pScreen, mode); +} + + + + + +/* This function inits the STREAMS processor variables. + * This has essentially been taken from the accel/s3_virge code and the databook. + */ +static void +S3VInitSTREAMS(ScrnInfoPtr pScrn, unsigned int *streams, DisplayModePtr mode) +{ + PVERB5(" S3VInitSTREAMS\n"); + + switch (pScrn->bitsPerPixel) + { + case 16: + streams[0] = 0x05000000; + break; + case 24: + /* data format 8.8.8 (24 bpp) */ + streams[0] = 0x06000000; + break; + case 32: + /* one more bit for X.8.8.8, 32 bpp */ + streams[0] = 0x07000000; + break; + } + /* NO chroma keying... */ + streams[1] = 0x0; + /* Secondary stream format KRGB-16 */ + /* data book suggestion... */ + streams[2] = 0x03000000; + + streams[3] = 0x0; + + streams[4] = 0x0; + /* use 0x01000000 for primary over second. */ + /* use 0x0 for second over prim. */ + streams[5] = 0x01000000; + + streams[6] = 0x0; + + streams[7] = 0x0; + /* Stride is 3 bytes for 24 bpp mode and */ + /* 4 bytes for 32 bpp. */ + switch(pScrn->bitsPerPixel) + { + case 16: + streams[8] = + pScrn->displayWidth * 2; + break; + case 24: + streams[8] = + pScrn->displayWidth * 3; + break; + case 32: + streams[8] = + pScrn->displayWidth * 4; + break; + } + /* Choose fbaddr0 as stream source. */ + streams[9] = 0x0; + streams[10] = 0x0; + streams[11] = 0x0; + streams[12] = 0x1; + + /* Set primary stream on top of secondary */ + /* stream. */ + streams[13] = 0xc0000000; + /* Vertical scale factor. */ + streams[14] = 0x0; + + streams[15] = 0x0; + /* Vertical accum. initial value. */ + streams[16] = 0x0; + /* X and Y start coords + 1. */ + streams[18] = 0x00010001; + + /* Specify window Width -1 and Height of */ + /* stream. */ + streams[19] = + (mode->HDisplay - 1) << 16 | + (mode->VDisplay); + + /* Book says 0x07ff07ff. */ + streams[20] = 0x07ff07ff; + + streams[21] = 0x00010001; + +} + + + + +/* Used to adjust start address in frame buffer. We use the new + * CR69 reg for this purpose instead of the older CR31/CR51 combo. + * If STREAMS is running, we program the STREAMS start addr. registers. + */ + +void +S3VAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + S3VPtr ps3v = S3VPTR(pScrn); + int Base; + int vgaCRIndex, vgaCRReg, vgaIOBase; + vgaIOBase = hwp->IOBase; + vgaCRIndex = vgaIOBase + 4; + vgaCRReg = vgaIOBase + 5; + + if(ps3v->ShowCache && y) + y += pScrn->virtualY - 1; + + if( (ps3v->STREAMSRunning == FALSE) || + S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset)) { + Base = ((y * pScrn->displayWidth + x) + * (pScrn->bitsPerPixel / 8)) >> 2; + if (pScrn->bitsPerPixel == 24) + Base = Base+2 - (Base+2) % 3; + if (pScrn->bitsPerPixel == 16) + if (S3_TRIO_3D_SERIES(ps3v->Chipset) && pScrn->modes->Clock > 115000) + Base &= ~1; + + /* Now program the start address registers */ + VGAOUT16(vgaCRIndex, (Base & 0x00FF00) | 0x0C); + VGAOUT16(vgaCRIndex, ((Base & 0x00FF) << 8) | 0x0D); + VGAOUT8(vgaCRIndex, 0x69); + VGAOUT8(vgaCRReg, (Base & 0x0F0000) >> 16); + } + else { /* Change start address for STREAMS case */ + VerticalRetraceWait(); + if(ps3v->Chipset == S3_ViRGE_VX) + OUTREG(PSTREAM_FBADDR0_REG, + ((y * pScrn->displayWidth + (x & ~7)) * + pScrn->bitsPerPixel / 8)); + else + OUTREG(PSTREAM_FBADDR0_REG, + ((y * pScrn->displayWidth + (x & ~3)) * + pScrn->bitsPerPixel / 8)); + } + + return; +} + + + + +/* Usually mandatory */ +Bool +S3VSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + return S3VModeInit(xf86Screens[scrnIndex], mode); +} + + + +void S3VLoadPalette( + ScrnInfoPtr pScrn, + int numColors, + int *indicies, + LOCO *colors, + VisualPtr pVisual +){ + S3VPtr ps3v = S3VPTR(pScrn); + int i, index; + + for(i = 0; i < numColors; i++) { + index = indicies[i]; + VGAOUT8(0x3c8, index); + VGAOUT8(0x3c9, colors[index].red); + VGAOUT8(0x3c9, colors[index].green); + VGAOUT8(0x3c9, colors[index].blue); + } +} + + +/* + * Functions to support getting a ViRGE card into MMIO mode if it fails to + * default to MMIO enabled. + */ + +void +S3VEnableMmio(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp; + S3VPtr ps3v; + IOADDRESS vgaCRIndex, vgaCRReg; + unsigned char val; + + PVERB5(" S3VEnableMmio\n"); + + hwp = VGAHWPTR(pScrn); + ps3v = S3VPTR(pScrn); + /* + * enable chipset (seen on uninitialized secondary cards) + * might not be needed once we use the VGA softbooter + * (EE 05/04/99) + */ + vgaHWSetStdFuncs(hwp); + /* + * any access to the legacy VGA ports is done here. + * If legacy VGA is inaccessable the MMIO base _has_ + * to be set correctly already and MMIO _has_ to be + * enabled. + */ + val = inb(hwp->PIOOffset + 0x3C3); /*@@@EE*/ + outb(hwp->PIOOffset + 0x3C3, val | 0x01); + /* + * set CR registers to color mode + * in mono mode extended CR registers + * are not accessible. (EE 05/04/99) + */ + val = inb(hwp->PIOOffset + VGA_MISC_OUT_R); /*@@@EE*/ + outb(hwp->PIOOffset + VGA_MISC_OUT_W, val | 0x01); + vgaHWGetIOBase(hwp); /* Get VGA I/O base */ + vgaCRIndex = hwp->PIOOffset + hwp->IOBase + 4; + vgaCRReg = vgaCRIndex + 1; +#if 1 + /* + * set linear base register to the PCI register values + * some DX chipsets don't seem to do it automatically + * (EE 06/03/99) + */ + outb(vgaCRIndex, 0x59); /*@@@EE*/ + outb(vgaCRReg, ps3v->PciInfo->memBase[0] >> 24); + outb(vgaCRIndex, 0x5A); + outb(vgaCRReg, ps3v->PciInfo->memBase[0] >> 16); + outb(vgaCRIndex, 0x53); +#endif + /* Save register for restore */ + ps3v->EnableMmioCR53 = inb(vgaCRReg); + /* Enable new MMIO, if TRIO mmio is already */ + /* enabled, then it stays enabled. */ + outb(vgaCRReg, ps3v->EnableMmioCR53 | 0x08); + outb(hwp->PIOOffset + VGA_MISC_OUT_W, val); + if (S3_TRIO_3D_SERIES(ps3v->Chipset)) { + outb(vgaCRIndex, 0x40); + val = inb(vgaCRReg); + outb(vgaCRReg, val | 1); + } +} + + + +void +S3VDisableMmio(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp; + S3VPtr ps3v; + IOADDRESS vgaCRIndex, vgaCRReg; + + PVERB5(" S3VDisableMmio\n"); + + hwp = VGAHWPTR(pScrn); + ps3v = S3VPTR(pScrn); + + vgaCRIndex = hwp->PIOOffset + hwp->IOBase + 4; + vgaCRReg = vgaCRIndex + 1; + outb(vgaCRIndex, 0x53); + /* Restore register's original state */ + outb(vgaCRReg, ps3v->EnableMmioCR53); + if (S3_TRIO_3D_SERIES(ps3v->Chipset)) { + unsigned char val; + outb(vgaCRIndex, 0x40); + val = inb(vgaCRReg); + outb(vgaCRReg, val | 1); + } +} + + + +/* This function is used to debug, it prints out the contents of s3 regs */ + +static void +S3VPrintRegs(ScrnInfoPtr pScrn) +{ + unsigned char tmp1, tmp2; + vgaHWPtr hwp = VGAHWPTR(pScrn); + S3VPtr ps3v = S3VPTR(pScrn); + int vgaCRIndex, vgaCRReg, vgaIOBase, vgaIR; + vgaIOBase = hwp->IOBase; + vgaCRIndex = vgaIOBase + 4; + vgaCRReg = vgaIOBase + 5; + vgaIR = vgaIOBase + 0xa; + +/* All registers */ +/* New formatted registers, matches s3rc (sort of) */ + xf86DrvMsgVerb( pScrn->scrnIndex, X_INFO, VERBLEV, "START register dump ------------------\n"); + xf86ErrorFVerb(VERBLEV, "Misc Out[3CC]\n "); + xf86ErrorFVerb(VERBLEV, "%02x\n",VGAIN8(0x3cc)); + + xf86ErrorFVerb(VERBLEV, "\nCR[00-2f]\n "); + for(tmp1=0x0;tmp1<=0x2f;tmp1++){ + VGAOUT8(vgaCRIndex, tmp1); + xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(vgaCRReg)); + if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " "); + if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n "); + } + + xf86ErrorFVerb(VERBLEV, "\nSR[00-27]\n "); + for(tmp1=0x0;tmp1<=0x27;tmp1++){ + VGAOUT8(0x3c4, tmp1); + xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(0x3c5)); + if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " "); + if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n "); + } + xf86ErrorFVerb(VERBLEV, "\n"); /* odd hex number of digits... */ + + xf86ErrorFVerb(VERBLEV, "\nGr Cont GR[00-0f]\n "); + for(tmp1=0x0;tmp1<=0x0f;tmp1++){ + VGAOUT8(0x3ce, tmp1); + xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(0x3cf)); + if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " "); + if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n "); + } + + xf86ErrorFVerb(VERBLEV, "\nAtt Cont AR[00-1f]\n "); + VGAIN8(vgaIR); /* preset AR flip-flop by reading 3DA, ignore return value */ + tmp2=VGAIN8(0x3c0) & 0x20; + for(tmp1=0x0;tmp1<=0x1f;tmp1++){ + VGAIN8(vgaIR); /* preset AR flip-flop by reading 3DA, ignore return value */ + VGAOUT8(0x3c0, (tmp1 & ~0x20) | tmp2); + xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(0x3c1)); + if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " "); + if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n "); + } + + xf86ErrorFVerb(VERBLEV, "\nCR[30-6f]\n "); + for(tmp1=0x30;tmp1<=0x6f;tmp1++){ + VGAOUT8(vgaCRIndex, tmp1); + xf86ErrorFVerb(VERBLEV, "%02x ",VGAIN8(vgaCRReg)); + if((tmp1 & 0x3) == 0x3) xf86ErrorFVerb(VERBLEV, " "); + if((tmp1 & 0xf) == 0xf) xf86ErrorFVerb(VERBLEV, "\n "); + } + + xf86ErrorFVerb(VERBLEV, "\n"); + xf86DrvMsgVerb( pScrn->scrnIndex, X_INFO, VERBLEV, "END register dump --------------------\n"); +} + +/* this is just a debugger hook */ +/* +void print_subsys_stat(void *s3vMmioMem); +void +print_subsys_stat(void *s3vMmioMem) +{ + ErrorF("IN_SUBSYS_STAT() = %x\n", IN_SUBSYS_STAT()); + return; +} +*/ + +/* + * S3VDisplayPowerManagementSet -- + * + * Sets VESA Display Power Management Signaling (DPMS) Mode. + */ +static void +S3VDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) +{ + S3VPtr ps3v; + unsigned char sr8 = 0x0, srd = 0x0; + char modestr[][40] = { "On","Standby","Suspend","Off" }; + + ps3v = S3VPTR(pScrn); + + /* unlock extended sequence registers */ + + VGAOUT8(0x3c4, 0x08); + sr8 = VGAIN8(0x3c5); + sr8 |= 0x6; + VGAOUT8(0x3c5, sr8); + + /* load SRD */ + VGAOUT8(0x3c4, 0x0d); + srd = VGAIN8(0x3c5); + + srd &= 0x03; /* clear the sync control bits of srd */ + + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + break; + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + srd |= 0x10; + break; + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + srd |= 0x40; + break; + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + srd |= 0x50; + break; + default: + xf86ErrorFVerb(VERBLEV, "Invalid PowerManagementMode %d passed to S3VDisplayPowerManagementSet\n", PowerManagementMode); + break; + } + + VGAOUT8(0x3c4, 0x0d); + VGAOUT8(0x3c5, srd); + + xf86ErrorFVerb(VERBLEV, "Power Manag: set:%s\n", + modestr[PowerManagementMode]); + + return; +} + +static unsigned int +S3Vddc1Read(ScrnInfoPtr pScrn) +{ + register vgaHWPtr hwp = VGAHWPTR(pScrn); + register CARD32 tmp; + S3VPtr ps3v = S3VPTR(pScrn); + + while (hwp->readST01(hwp)&0x8) {}; + while (!(hwp->readST01(hwp)&0x8)) {}; + + tmp = (INREG(DDC_REG)); + return ((unsigned int) (tmp & 0x08)); +} + +static Bool +S3Vddc1(int scrnIndex) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + S3VPtr ps3v = S3VPTR(pScrn); + CARD32 tmp; + Bool success = FALSE; + xf86MonPtr pMon; + + /* initialize chipset */ + tmp = INREG(DDC_REG); + OUTREG(DDC_REG,(tmp | 0x12)); + + if ((pMon = xf86PrintEDID( + xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(), + S3Vddc1Read))) != NULL) + success = TRUE; + xf86SetDDCproperties(pScrn,pMon); + + /* undo initialization */ + OUTREG(DDC_REG,(tmp)); + return success; +} + +static Bool +S3Vddc2(int scrnIndex) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + S3VPtr ps3v = S3VPTR(pScrn); + + if ( xf86LoadSubModule(pScrn, "i2c") ) { + xf86LoaderReqSymLists(i2cSymbols,NULL); + if (S3V_I2CInit(pScrn)) { + CARD32 tmp = (INREG(DDC_REG)); + OUTREG(DDC_REG,(tmp | 0x13)); + xf86SetDDCproperties(pScrn,xf86PrintEDID( + xf86DoEDID_DDC2(pScrn->scrnIndex,ps3v->I2C))); + OUTREG(DDC_REG,tmp); + return TRUE; + } + } + return FALSE; +} + +static void +S3VProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + if (xf86LoadSubModule(pScrn, "vbe")) { + pVbe = VBEInit(NULL,index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} + +/*EOF*/ + + |