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