/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/sis_driver.c,v 1.86 2003/02/04 02:44:29 dawes Exp $ */ /* * Copyright 1998,1999 by Alan Hourihane, Wigan, England. * Parts Copyright 2001, 2002, 2003 by Thomas Winischhofer, Vienna, Austria. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of the copyright holder not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. The copyright holder makes no representations * about the suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. * * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Authors: Alan Hourihane, alanh@fairlite.demon.co.uk * Mike Chapman , * Juanjo Santamarta , * Mitani Hiroshi * David Thomas . * * Thomas Winischhofer : * - 310/325 series (315/550/650/651/740/M650) support * - (possibly incomplete) Xabre (SiS330) support * - new mode switching code for 300, 310/325 and 330 series * - many fixes for 300/540/630/730 chipsets, * - many fixes for 5597/5598, 6326 and 530/620 chipsets, * - VESA mode switching (deprecated), * - extended CRT2/video bridge handling support, * - dual head support on 300, 310/325 and 330 series * - 650/LVDS (up to 1400x1050), 650/Chrontel 701x support * - 30xB/30xLV/30xLVX video bridge support (300, 310/325, 330 series) * - Xv support for 5597/5598, 6326, 530/620 and 310/325 series * - video overlay enhancements for 300 series * - TV and hi-res support for the 6326 * - Color HW cursor support for 300(emulated), 310/325 and 330 series * - etc. */ #include "fb.h" #include "xf1bpp.h" #include "xf4bpp.h" #include "mibank.h" #include "micmap.h" #include "xf86.h" #include "xf86_OSproc.h" #include "xf86Resources.h" #include "xf86_ansic.h" #include "dixstruct.h" #include "xf86Version.h" #include "xf86PciInfo.h" #include "xf86Pci.h" #include "xf86cmap.h" #include "vgaHW.h" #include "xf86RAC.h" #include "shadowfb.h" #include "vbe.h" #include "sis_shadow.h" #include "mipointer.h" #include "mibstore.h" #include "sis.h" #include "sis_regs.h" #include "sis_vb.h" #include "sis_dac.h" #include "sis_driver.h" #define _XF86DGA_SERVER_ #include "extensions/xf86dgastr.h" #include "globals.h" #define DPMS_SERVER #include "extensions/dpms.h" #ifdef XvExtension #include "xf86xv.h" #include "Xv.h" #endif #ifdef XF86DRI #include "dri.h" #endif /* Mandatory functions */ static void SISIdentify(int flags); static Bool SISProbe(DriverPtr drv, int flags); static Bool SISPreInit(ScrnInfoPtr pScrn, int flags); static Bool SISScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv); static Bool SISEnterVT(int scrnIndex, int flags); static void SISLeaveVT(int scrnIndex, int flags); static Bool SISCloseScreen(int scrnIndex, ScreenPtr pScreen); static Bool SISSaveScreen(ScreenPtr pScreen, int mode); static Bool SISSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); static void SISAdjustFrame(int scrnIndex, int x, int y, int flags); #ifdef SISDUALHEAD static Bool SISSaveScreenDH(ScreenPtr pScreen, int mode); #endif /* Optional functions */ static void SISFreeScreen(int scrnIndex, int flags); static int SISValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags); /* Internally used functions */ static Bool SISMapMem(ScrnInfoPtr pScrn); static Bool SISUnmapMem(ScrnInfoPtr pScrn); static void SISSave(ScrnInfoPtr pScrn); static void SISRestore(ScrnInfoPtr pScrn); static void SISVESARestore(ScrnInfoPtr pScrn); static Bool SISModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); static void SISModifyModeInfo(DisplayModePtr mode); static void SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode); static void SiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg); static void SiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg); static Bool SiSSetVESAMode(ScrnInfoPtr pScrn, DisplayModePtr pMode); static void SiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe); static UShort SiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode); static void SISVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function); static void SISBridgeRestore(ScrnInfoPtr pScrn); static void SiSEnableTurboQueue(ScrnInfoPtr pScrn); unsigned char SISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode); static void SISWaitVBRetrace(ScrnInfoPtr pScrn); void SISWaitRetraceCRT1(ScrnInfoPtr pScrn); void SISWaitRetraceCRT2(ScrnInfoPtr pScrn); BOOLEAN SiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn); #ifdef CYCLECRT2 Bool SISCycleCRT2Type(int scrnIndex, DisplayModePtr mode); #endif #ifdef DEBUG static void SiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode); #endif /* TW: New mode switching functions */ extern BOOLEAN SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom); extern BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch); extern USHORT SiS_CalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode); extern USHORT SiS_CheckCalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags); extern void SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr); extern DisplayModePtr SiSBuildBuiltInModeList(ScrnInfoPtr pScrn); #ifdef SISDUALHEAD extern BOOLEAN SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom); extern BOOLEAN SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn, DisplayModePtr mode); #endif /* TW: For power management for 310/325 series */ extern void SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr); extern void SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr); extern void SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension); extern void SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension); #ifdef SISDUALHEAD static int SISEntityIndex = -1; #endif /* * This is intentionally screen-independent. It indicates the binding * choice made in the first PreInit. */ static int pix24bpp = 0; /* * This contains the functions needed by the server after loading the driver * module. It must be supplied, and gets passed back by the SetupProc * function in the dynamic case. In the static case, a reference to this * is compiled in, and this requires that the name of this DriverRec be * an upper-case version of the driver name. */ DriverRec SIS = { SIS_CURRENT_VERSION, SIS_DRIVER_NAME, SISIdentify, SISProbe, SISAvailableOptions, NULL, 0 }; static SymTabRec SISChipsets[] = { { PCI_CHIP_SIS5597, "SIS5597/5598" }, { PCI_CHIP_SIS530, "SIS530/620" }, { PCI_CHIP_SIS6326, "SIS6326/AGP/DVD" }, { PCI_CHIP_SIS300, "SIS300/305" }, { PCI_CHIP_SIS630, "SIS630/730" }, { PCI_CHIP_SIS540, "SIS540" }, { PCI_CHIP_SIS315, "SIS315" }, { PCI_CHIP_SIS315H, "SIS315H" }, { PCI_CHIP_SIS315PRO, "SIS315PRO" }, { PCI_CHIP_SIS550, "SIS550" }, { PCI_CHIP_SIS650, "SIS650/M650/651/740" }, #ifdef INCL_SIS330 /* TW: New for SiS330 (untested) */ { PCI_CHIP_SIS330, "SIS330(Xabre)" }, #endif { -1, NULL } }; static PciChipsets SISPciChipsets[] = { { PCI_CHIP_SIS5597, PCI_CHIP_SIS5597, RES_SHARED_VGA }, { PCI_CHIP_SIS530, PCI_CHIP_SIS530, RES_SHARED_VGA }, { PCI_CHIP_SIS6326, PCI_CHIP_SIS6326, RES_SHARED_VGA }, { PCI_CHIP_SIS300, PCI_CHIP_SIS300, RES_SHARED_VGA }, { PCI_CHIP_SIS630, PCI_CHIP_SIS630, RES_SHARED_VGA }, { PCI_CHIP_SIS540, PCI_CHIP_SIS540, RES_SHARED_VGA }, { PCI_CHIP_SIS550, PCI_CHIP_SIS550, RES_SHARED_VGA }, { PCI_CHIP_SIS315, PCI_CHIP_SIS315, RES_SHARED_VGA }, { PCI_CHIP_SIS315H, PCI_CHIP_SIS315H, RES_SHARED_VGA }, { PCI_CHIP_SIS315PRO, PCI_CHIP_SIS315PRO, RES_SHARED_VGA }, { PCI_CHIP_SIS650, PCI_CHIP_SIS650, RES_SHARED_VGA }, #ifdef INCL_SIS330 /* TW: New for SiS330 */ { PCI_CHIP_SIS330, PCI_CHIP_SIS330, RES_SHARED_VGA }, #endif { -1, -1, RES_UNDEFINED } }; static const char *xaaSymbols[] = { "XAACopyROP", "XAACreateInfoRec", "XAADestroyInfoRec", "XAAFillSolidRects", "XAAHelpPatternROP", "XAAInit", NULL }; static const char *vgahwSymbols[] = { "vgaHWFreeHWRec", "vgaHWGetHWRec", "vgaHWGetIOBase", "vgaHWGetIndex", "vgaHWInit", "vgaHWLock", "vgaHWMapMem", "vgaHWProtect", "vgaHWRestore", "vgaHWSave", "vgaHWSaveScreen", "vgaHWUnlock", NULL }; static const char *miscfbSymbols[] = { "xf1bppScreenInit", "xf4bppScreenInit", NULL }; static const char *fbSymbols[] = { "fbPictureInit", "fbScreenInit", NULL }; static const char *shadowSymbols[] = { "ShadowFBInit", NULL }; static const char *ramdacSymbols[] = { "xf86CreateCursorInfoRec", "xf86DestroyCursorInfoRec", "xf86InitCursor", NULL }; static const char *ddcSymbols[] = { "xf86PrintEDID", "xf86SetDDCproperties", "xf86InterpretEDID", "xf86DoEDID_DDC1", #ifdef SISI2C "xf86DoEDID_DDC2", #endif NULL }; static const char *i2cSymbols[] = { "xf86I2CBusInit", "xf86CreateI2CBusRec", NULL }; static const char *int10Symbols[] = { "xf86FreeInt10", "xf86InitInt10", NULL }; static const char *vbeSymbols[] = { #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) "VBEInit", #else "VBEExtendedInit", #endif "vbeDoEDID", "vbeFree", "VBEGetVBEInfo", "VBEFreeVBEInfo", "VBEGetModeInfo", "VBEFreeModeInfo", "VBESaveRestore", "VBESetVBEMode", "VBEGetVBEMode", "VBESetDisplayStart", "VBESetGetLogicalScanlineLength", NULL }; #ifdef XF86DRI static const char *drmSymbols[] = { "drmAddMap", "drmAgpAcquire", "drmAgpAlloc", "drmAgpBase", "drmAgpBind", "drmAgpEnable", "drmAgpFree", "drmAgpGetMode", "drmAgpRelease", "drmCtlInstHandler", "drmGetInterruptFromBusID", "drmSiSAgpInit", NULL }; static const char *driSymbols[] = { "DRICloseScreen", "DRICreateInfoRec", "DRIDestroyInfoRec", "DRIFinishScreenInit", "DRIGetSAREAPrivate", "DRILock", "DRIQueryVersion", "DRIScreenInit", "DRIUnlock", "GlxSetVisualConfigs", NULL }; #endif #ifdef XFree86LOADER static MODULESETUPPROTO(sisSetup); static XF86ModuleVersionInfo sisVersRec = { SIS_DRIVER_NAME, MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XF86_VERSION_CURRENT, SIS_MAJOR_VERSION, SIS_MINOR_VERSION, SIS_PATCHLEVEL, ABI_CLASS_VIDEODRV, /* This is a video driver */ ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, {0,0,0,0} }; XF86ModuleData sisModuleData = { &sisVersRec, sisSetup, NULL }; pointer sisSetup(pointer module, pointer opts, int *errmaj, int *errmin) { static Bool setupDone = FALSE; if (!setupDone) { setupDone = TRUE; xf86AddDriver(&SIS, module, 0); LoaderRefSymLists(vgahwSymbols, fbSymbols, i2cSymbols, xaaSymbols, miscfbSymbols, shadowSymbols, ramdacSymbols, vbeSymbols, int10Symbols, #ifdef XF86DRI drmSymbols, driSymbols, #endif NULL); return (pointer)TRUE; } if (errmaj) *errmaj = LDR_ONCEONLY; return NULL; } #endif /* XFree86LOADER */ static Bool SISGetRec(ScrnInfoPtr pScrn) { /* * Allocate an SISRec, and hook it into pScrn->driverPrivate. * pScrn->driverPrivate is initialised to NULL, so we can check if * the allocation has already been done. */ if (pScrn->driverPrivate != NULL) return TRUE; pScrn->driverPrivate = xnfcalloc(sizeof(SISRec), 1); /* Initialise it to 0 */ memset(pScrn->driverPrivate, 0, sizeof(SISRec)); return TRUE; } static void SISFreeRec(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = NULL; #endif /* TW: Just to make sure... */ if(!pSiS) return; pSiSEnt = pSiS->entityPrivate; if(pSiS->pstate) xfree(pSiS->pstate); pSiS->pstate = NULL; if(pSiS->fonts) xfree(pSiS->fonts); pSiS->fonts = NULL; #ifdef SISDUALHEAD if(pSiSEnt) { if(!pSiS->SecondHead) { /* TW: Free memory only if we are first head; in case of an error * during init of the second head, the server will continue - * and we need the BIOS image and SiS_Private for the first * head. */ if(pSiSEnt->BIOS) xfree(pSiSEnt->BIOS); pSiSEnt->BIOS = pSiS->BIOS = NULL; if(pSiSEnt->SiS_Pr) xfree(pSiSEnt->SiS_Pr); pSiSEnt->SiS_Pr = pSiS->SiS_Pr = NULL; } else { pSiS->BIOS = NULL; pSiS->SiS_Pr = NULL; } } else { #endif if(pSiS->BIOS) xfree(pSiS->BIOS); pSiS->BIOS = NULL; if(pSiS->SiS_Pr) xfree(pSiS->SiS_Pr); pSiS->SiS_Pr = NULL; #ifdef SISDUALHEAD } #endif if (pSiS->pVbe) vbeFree(pSiS->pVbe); pSiS->pVbe = NULL; if (pScrn->driverPrivate == NULL) return; xfree(pScrn->driverPrivate); pScrn->driverPrivate = NULL; } static void SISDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { SISPtr pSiS = SISPTR(pScrn); unsigned char extDDC_PCR=0; unsigned char crtc17, seq1; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SISDisplayPowerManagementSet(%d)\n",PowerManagementMode); /* unlock registers */ #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif /* Read CR17 */ inSISIDXREG(SISCR, 0x17, crtc17); /* Read SR1 */ inSISIDXREG(SISSR, 0x01, seq1); if(pSiS->VBFlags & CRT2_LCD) { if(((pSiS->VGAEngine == SIS_300_VGA) && (!(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)))) || ((pSiS->VGAEngine == SIS_315_VGA) && ((pSiS->VBFlags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) { /* Read Power Control Register (SR11) */ inSISIDXREG(SISSR, 0x11, extDDC_PCR); /* if not blanked, obtain state of LCD blank flags set by BIOS */ if(!pSiS->Blank) { pSiS->LCDon = extDDC_PCR; } /* erase LCD blank flags */ extDDC_PCR &= ~0x0C; } } switch (PowerManagementMode) { case DPMSModeOn: /* HSync: On, VSync: On */ pSiS->Blank = FALSE; seq1 &= ~0x20; crtc17 |= 0x80; if(pSiS->VBFlags & CRT2_LCD) { if(pSiS->VGAEngine == SIS_315_VGA) { if(pSiS->VBFlags & VB_CHRONTEL) { SiS_Chrontel701xBLOn(pSiS->SiS_Pr); } else if(pSiS->VBFlags & VB_LVDS) { extDDC_PCR |= (pSiS->LCDon & 0x0C); } else if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOn(pSiS->SiS_Pr,&pSiS->sishw_ext); } } else if(pSiS->VGAEngine == SIS_300_VGA) { if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOn(pSiS->SiS_Pr,&pSiS->sishw_ext); } else { extDDC_PCR |= (pSiS->LCDon & 0x0C); } } } break; case DPMSModeStandby: /* HSync: Off, VSync: On */ case DPMSModeSuspend: /* HSync: On, VSync: Off */ pSiS->Blank = TRUE; seq1 |= 0x20 ; if(pSiS->VBFlags & CRT2_LCD) { if(pSiS->VGAEngine == SIS_315_VGA) { if(pSiS->VBFlags & VB_CHRONTEL) { SiS_Chrontel701xBLOff(pSiS->SiS_Pr); } else if(pSiS->VBFlags & VB_LVDS) { extDDC_PCR |= 0x08; } else if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOff(pSiS->SiS_Pr,&pSiS->sishw_ext); } } else if(pSiS->VGAEngine == SIS_300_VGA) { if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOff(pSiS->SiS_Pr,&pSiS->sishw_ext); } else { extDDC_PCR |= 0x08; } } } break; case DPMSModeOff: /* HSync: Off, VSync: Off */ pSiS->Blank = TRUE; seq1 |= 0x20; if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) { /* TW: We can't switch off CRT1 if bridge is in slavemode */ if(pSiS->VBFlags & CRT2_ENABLE) { if(!(SiSBridgeIsInSlaveMode(pScrn))) crtc17 &= ~0x80; } else crtc17 &= ~0x80; } else { crtc17 &= ~0x80; } if(pSiS->VBFlags & CRT2_LCD) { if(pSiS->VGAEngine == SIS_315_VGA) { if(pSiS->VBFlags & VB_CHRONTEL) { SiS_Chrontel701xBLOff(pSiS->SiS_Pr); } else if(pSiS->VBFlags & VB_LVDS) { extDDC_PCR |= 0x0C; } else if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOff(pSiS->SiS_Pr,&pSiS->sishw_ext); } } else if(pSiS->VGAEngine == SIS_300_VGA) { if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOff(pSiS->SiS_Pr,&pSiS->sishw_ext); } else { extDDC_PCR |= 0x0C; } } } break; } outSISIDXREG(SISSR, 0x01, seq1); /* Set/Clear "Display On" bit */ outSISIDXREG(SISCR, 0x17, crtc17); if(pSiS->VBFlags & CRT2_LCD) { if(((pSiS->VGAEngine == SIS_300_VGA) && (!(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)))) || ((pSiS->VGAEngine == SIS_315_VGA) && ((pSiS->VBFlags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) { outSISIDXREG(SISSR, 0x11, extDDC_PCR); } } outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ usleep(10000); outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ } #ifdef SISDUALHEAD /* TW: DPMS for dual head mode */ static void SISDisplayPowerManagementSetDH(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { SISPtr pSiS = SISPTR(pScrn); unsigned char crtc17 = 0; unsigned char extDDC_PCR=0; unsigned char seq1 = 0; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "SISDisplayPowerManagementSetDH(%d)\n",PowerManagementMode); /* unlock registers */ #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif if (pSiS->SecondHead) { /* TW: Second (slave) head is always CRT1 */ /* Read CR17 and SR01 */ inSISIDXREG(SISCR, 0x17, crtc17); inSISIDXREG(SISSR, 0x01, seq1); switch (PowerManagementMode) { case DPMSModeOn: /* HSync: On, VSync: On */ seq1 &= ~0x20 ; crtc17 |= 0x80; pSiS->BlankCRT1 = FALSE; break; case DPMSModeStandby: /* HSync: Off, VSync: On */ case DPMSModeSuspend: /* HSync: On, VSync: Off */ seq1 |= 0x20; pSiS->BlankCRT1 = TRUE; break; case DPMSModeOff: /* HSync: Off, VSync: Off */ seq1 |= 0x20 ; pSiS->BlankCRT1 = TRUE; crtc17 &= ~0x80; break; } outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ outSISIDXREG(SISSR, 0x01, seq1); /* Set/Clear "Display On" bit */ usleep(10000); outSISIDXREG(SISCR, 0x17, crtc17); outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ } else { /* TW: Master head is always CRT2 */ /* TV can not be managed */ if(!(pSiS->VBFlags & CRT2_LCD)) return; if(((pSiS->VGAEngine == SIS_300_VGA) && (!(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)))) || ((pSiS->VGAEngine == SIS_315_VGA) && ((pSiS->VBFlags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) { /* Read Power Control Register (SR11) */ inSISIDXREG(SISSR, 0x11, extDDC_PCR); /* if not blanked obtain state of LCD blank flags set by BIOS */ if(!pSiS->BlankCRT2) { pSiS->LCDon = extDDC_PCR; } /* erase LCD blank flags */ extDDC_PCR &= ~0xC; } switch (PowerManagementMode) { case DPMSModeOn: pSiS->BlankCRT2 = FALSE; if(pSiS->VGAEngine == SIS_315_VGA) { if(pSiS->VBFlags & VB_CHRONTEL) { SiS_Chrontel701xBLOn(pSiS->SiS_Pr); } else if(pSiS->VBFlags & VB_LVDS) { extDDC_PCR |= (pSiS->LCDon & 0x0C); } else if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOn(pSiS->SiS_Pr, &pSiS->sishw_ext); } } else if(pSiS->VGAEngine == SIS_300_VGA) { if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOn(pSiS->SiS_Pr, &pSiS->sishw_ext); } else { extDDC_PCR |= (pSiS->LCDon & 0x0C); } } break; case DPMSModeStandby: case DPMSModeSuspend: pSiS->BlankCRT2 = TRUE; if(pSiS->VGAEngine == SIS_315_VGA) { if(pSiS->VBFlags & VB_CHRONTEL) { SiS_Chrontel701xBLOff(pSiS->SiS_Pr); } else if(pSiS->VBFlags & VB_LVDS) { extDDC_PCR |= 0x08; } else if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOff(pSiS->SiS_Pr, &pSiS->sishw_ext); } } else if(pSiS->VGAEngine == SIS_300_VGA) { if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOff(pSiS->SiS_Pr, &pSiS->sishw_ext); } else { extDDC_PCR |= 0x08; } } break; case DPMSModeOff: pSiS->BlankCRT2 = TRUE; if(pSiS->VGAEngine == SIS_315_VGA) { if(pSiS->VBFlags & VB_CHRONTEL) { SiS_Chrontel701xBLOff(pSiS->SiS_Pr); } else if(pSiS->VBFlags & VB_LVDS) { extDDC_PCR |= 0x0C; } else if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOff(pSiS->SiS_Pr, &pSiS->sishw_ext); } } else if(pSiS->VGAEngine == SIS_300_VGA) { if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { SiS_SiS30xBLOff(pSiS->SiS_Pr, &pSiS->sishw_ext); } else { extDDC_PCR |= 0x0C; } } break; } if(((pSiS->VGAEngine == SIS_300_VGA) && (!(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)))) || ((pSiS->VGAEngine == SIS_315_VGA) && ((pSiS->VBFlags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) { outSISIDXREG(SISSR, 0x11, extDDC_PCR); } } } #endif /* Mandatory */ static void SISIdentify(int flags) { xf86PrintChipsets(SIS_NAME, "driver for SiS chipsets", SISChipsets); } static void SIS1bppColorMap(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); outSISREG(SISCOLIDX, 0x00); outSISREG(SISCOLDATA, 0x00); outSISREG(SISCOLDATA, 0x00); outSISREG(SISCOLDATA, 0x00); outSISREG(SISCOLIDX, 0x3f); outSISREG(SISCOLDATA, 0x3f); outSISREG(SISCOLDATA, 0x3f); outSISREG(SISCOLDATA, 0x3f); } /* Mandatory */ static Bool SISProbe(DriverPtr drv, int flags) { int i; GDevPtr *devSections; int *usedChips; int numDevSections; int numUsed; Bool foundScreen = FALSE; /* * The aim here is to find all cards that this driver can handle, * and for the ones not already claimed by another driver, claim the * slot, and allocate a ScrnInfoRec. * * This should be a minimal probe, and it should under no circumstances * change the state of the hardware. Because a device is found, don't * assume that it will be used. Don't do any initialisations other than * the required ScrnInfoRec initialisations. Don't allocate any new * data structures. * */ /* * Next we check, if there has been a chipset override in the config file. * For this we must find out if there is an active device section which * is relevant, i.e., which has no driver specified or has THIS driver * specified. */ if ((numDevSections = xf86MatchDevice(SIS_DRIVER_NAME, &devSections)) <= 0) { /* * There's no matching device section in the config file, so quit * now. */ return FALSE; } /* * We need to probe the hardware first. We then need to see how this * fits in with what is given in the config file, and allow the config * file info to override any contradictions. */ /* * All of the cards this driver supports are PCI, so the "probing" just * amounts to checking the PCI data that the server has already collected. */ if (xf86GetPciVideoInfo() == NULL) { /* * We won't let anything in the config file override finding no * PCI video cards at all. This seems reasonable now, but we'll see. */ return FALSE; } numUsed = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_SIS, SISChipsets, SISPciChipsets, devSections, numDevSections, drv, &usedChips); /* Free it since we don't need that list after this */ xfree(devSections); if (numUsed <= 0) return FALSE; if (flags & PROBE_DETECT) foundScreen = TRUE; else for (i = 0; i < numUsed; i++) { ScrnInfoPtr pScrn; #ifdef SISDUALHEAD EntityInfoPtr pEnt; #endif /* Allocate a ScrnInfoRec and claim the slot */ pScrn = NULL; if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], SISPciChipsets, NULL, NULL, NULL, NULL, NULL))) { /* Fill in what we can of the ScrnInfoRec */ pScrn->driverVersion = SIS_CURRENT_VERSION; pScrn->driverName = SIS_DRIVER_NAME; pScrn->name = SIS_NAME; pScrn->Probe = SISProbe; pScrn->PreInit = SISPreInit; pScrn->ScreenInit = SISScreenInit; pScrn->SwitchMode = SISSwitchMode; pScrn->AdjustFrame = SISAdjustFrame; pScrn->EnterVT = SISEnterVT; pScrn->LeaveVT = SISLeaveVT; pScrn->FreeScreen = SISFreeScreen; pScrn->ValidMode = SISValidMode; foundScreen = TRUE; } #ifdef SISDUALHEAD pEnt = xf86GetEntityInfo(usedChips[i]); /* TW: I assume these chipsets as - basically - dual head capable. */ if (pEnt->chipset == PCI_CHIP_SIS630 || pEnt->chipset == PCI_CHIP_SIS540 || pEnt->chipset == PCI_CHIP_SIS650 || pEnt->chipset == PCI_CHIP_SIS550 || pEnt->chipset == PCI_CHIP_SIS315 || pEnt->chipset == PCI_CHIP_SIS315H || pEnt->chipset == PCI_CHIP_SIS315PRO || pEnt->chipset == PCI_CHIP_SIS330 || pEnt->chipset == PCI_CHIP_SIS300) { SISEntPtr pSiSEnt = NULL; DevUnion *pPriv; xf86SetEntitySharable(usedChips[i]); if (SISEntityIndex < 0) SISEntityIndex = xf86AllocateEntityPrivateIndex(); pPriv = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex); if (!pPriv->ptr) { pPriv->ptr = xnfcalloc(sizeof(SISEntRec), 1); pSiSEnt = pPriv->ptr; pSiSEnt->lastInstance = -1; pSiSEnt->DisableDual = FALSE; pSiSEnt->ErrorAfterFirst = FALSE; pSiSEnt->MapCountIOBase = pSiSEnt->MapCountFbBase = 0; pSiSEnt->FbBase = pSiSEnt->IOBase = NULL; pSiSEnt->forceUnmapIOBase = FALSE; pSiSEnt->forceUnmapFbBase = FALSE; #ifdef __alpha__ pSiSEnt->MapCountIOBaseDense = 0; pSiSEnt->IOBaseDense = NULL; pSiSEnt->forceUnmapIOBaseDense = FALSE; #endif } else { pSiSEnt = pPriv->ptr; } pSiSEnt->lastInstance++; xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0], pSiSEnt->lastInstance); } #endif } xfree(usedChips); return foundScreen; } /* TW: If monitor section has no HSync/VRefresh data, * derive it from DDC data. */ static void SiSSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag) { MonPtr mon = pScrn->monitor; xf86MonPtr ddc = mon->DDC; int i,j; float myhhigh, myhlow; int myvhigh, myvlow; unsigned char temp; const myhddctiming myhtiming[11] = { { 1, 0x20, 31.6 }, /* rounded up by .1 */ { 1, 0x02, 35.3 }, { 1, 0x04, 37.6 }, { 1, 0x08, 38.0 }, { 1, 0x01, 38.0 }, { 2, 0x40, 47.0 }, { 2, 0x80, 48.2 }, { 2, 0x08, 48.5 }, { 2, 0x04, 56.6 }, { 2, 0x02, 60.1 }, { 2, 0x01, 80.1 } }; const myvddctiming myvtiming[10] = { { 1, 0x02, 56 }, { 1, 0x01, 60 }, { 2, 0x08, 60 }, { 2, 0x04, 70 }, { 1, 0x08, 72 }, { 2, 0x80, 72 }, { 1, 0x04, 75 }, { 2, 0x40, 75 }, { 2, 0x02, 75 }, { 2, 0x01, 75 } }; /* "Future modes"; we only check the really high ones */ const myddcstdmodes mystdmodes[8] = { { 1280, 1024, 85, 91.1 }, { 1600, 1200, 60, 75.0 }, { 1600, 1200, 65, 81.3 }, { 1600, 1200, 70, 87.5 }, { 1600, 1200, 75, 93.8 }, { 1600, 1200, 85, 106.3 }, { 1920, 1440, 60, 90.0 }, { 1920, 1440, 75, 112.5 } }; if(flag) { /* HSync */ for (i = 0; i < 4; i++) { if (ddc->det_mon[i].type == DS_RANGES) { mon->nHsync = 1; mon->hsync[0].lo = ddc->det_mon[i].section.ranges.min_h; mon->hsync[0].hi = ddc->det_mon[i].section.ranges.max_h; return; } } /* If no sync ranges detected in detailed timing table, we * derive them from supported VESA modes. */ myhlow = myhhigh = 0.0; for(i=0; i<11; i++) { if(myhtiming[i].whichone == 1) temp = ddc->timings1.t1; else temp = ddc->timings1.t2; if(temp & myhtiming[i].mask) { if((i==0) || (myhlow > myhtiming[i].rate)) myhlow = myhtiming[i].rate; } if(myhtiming[10-i].whichone == 1) temp = ddc->timings1.t1; else temp = ddc->timings1.t2; if(temp & myhtiming[10-i].mask) { if((i==0) || (myhhigh < myhtiming[10-i].rate)) myhhigh = myhtiming[10-i].rate; } } for(i=0;itimings2[i].hsize > 256) { for(j=0; j<8; j++) { if((ddc->timings2[i].hsize == mystdmodes[j].hsize) && (ddc->timings2[i].vsize == mystdmodes[j].vsize) && (ddc->timings2[i].refresh == mystdmodes[j].refresh)) { if(mystdmodes[j].hsync > myhhigh) myhhigh = mystdmodes[j].hsync; } } } } if((myhhigh) && (myhlow)) { mon->nHsync = 1; mon->hsync[0].lo = myhlow - 0.1; mon->hsync[0].hi = myhhigh; } } else { /* Vrefresh */ for (i = 0; i < 4; i++) { if (ddc->det_mon[i].type == DS_RANGES) { mon->nVrefresh = 1; mon->vrefresh[0].lo = ddc->det_mon[i].section.ranges.min_v; mon->vrefresh[0].hi = ddc->det_mon[i].section.ranges.max_v; return; } } myvlow = myvhigh = 0; for(i=0; i<10; i++) { if(myvtiming[i].whichone == 1) temp = ddc->timings1.t1; else temp = ddc->timings1.t2; if(temp & myvtiming[i].mask) { if((i==0) || (myvlow > myvtiming[i].rate)) myvlow = myvtiming[i].rate; } if(myvtiming[9-i].whichone == 1) temp = ddc->timings1.t1; else temp = ddc->timings1.t2; if(temp & myvtiming[9-i].mask) { if((i==0) || (myvhigh < myvtiming[9-i].rate)) myvhigh = myvtiming[9-i].rate; } } for(i=0;itimings2[i].hsize > 256) { for(j=0; j<8; j++) { if((ddc->timings2[i].hsize == mystdmodes[j].hsize) && (ddc->timings2[i].vsize == mystdmodes[j].vsize) && (ddc->timings2[i].refresh == mystdmodes[j].refresh)) { if(mystdmodes[j].refresh > myvhigh) myvhigh = mystdmodes[j].refresh; } } } } if((myvhigh) && (myvlow)) { mon->nVrefresh = 1; mon->vrefresh[0].lo = myvlow; mon->vrefresh[0].hi = myvhigh; } } } static xf86MonPtr SiSInternalDDC(ScrnInfoPtr pScrn, int crtno) { SISPtr pSiS = SISPTR(pScrn); USHORT temp, i; unsigned char buffer[256]; xf86MonPtr pMonitor = NULL; /* TW: If CRT1 is off, skip DDC */ if((pSiS->CRT1off) && (!crtno)) return NULL; temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS, crtno, 0, &buffer[0]); if((!temp) || (temp == 0xffff)) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC probing failed, now trying via VBE\n", crtno + 1); return(NULL); } else { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC supported\n", crtno + 1); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC level: %s%s%s%s\n", crtno + 1, (temp & 0x1a) ? "" : "[none of the supported]", (temp & 0x02) ? "2 " : "", (temp & 0x08) ? "3 " : "", (temp & 0x10) ? "4" : ""); if(temp & 0x02) { i = 3; /* Number of retrys */ do { temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS, crtno, 1, &buffer[0]); } while((temp) && i--); if(!temp) { if((pMonitor = xf86InterpretEDID(pScrn->scrnIndex, &buffer[0]))) { return(pMonitor); } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRT%d DDC EDID corrupt\n", crtno + 1); return(NULL); } } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRT%d DDC reading failed\n", crtno + 1); return(NULL); } } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DDC levels 3 and 4 not supported by this driver yet.\n"); return(NULL); } } } static xf86MonPtr SiSDoPrivateDDC(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) return(SiSInternalDDC(pScrn, 1)); else #endif return(SiSInternalDDC(pScrn, 0)); } /* Mandatory */ static Bool SISPreInit(ScrnInfoPtr pScrn, int flags) { SISPtr pSiS; MessageType from; unsigned char usScratchCR17, CR5F; unsigned char usScratchCR32; unsigned long int i; int temp; ClockRangePtr clockRanges; char *mod = NULL; const char *Sym = NULL; int pix24flags; #ifdef SISDUALHEAD SISEntPtr pSiSEnt = NULL; #endif DisplayModePtr first, p, n; DisplayModePtr tempmode, delmode, mymodes; unsigned char srlockReg,crlockReg; unsigned char tempreg; xf86MonPtr pMonitor = NULL; Bool didddc2; vbeInfoPtr pVbe; VbeInfoBlock *vbe; if (flags & PROBE_DETECT) { if (xf86LoadSubModule(pScrn, "vbe")) { int index = xf86GetEntityInfo(pScrn->entityList[0])->index; #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) if((pVbe = VBEInit(NULL,index))) { #else if((pVbe = VBEExtendedInit(NULL,index,0))) { #endif ConfiguredMonitor = vbeDoEDID(pVbe, NULL); vbeFree(pVbe); } } return TRUE; } /* * Note: This function is only called once at server startup, and * not at the start of each server generation. This means that * only things that are persistent across server generations can * be initialised here. xf86Screens[] is the array of all screens, * (pScrn is a pointer to one of these). Privates allocated using * xf86AllocateScrnInfoPrivateIndex() are too, and should be used * for data that must persist across server generations. * * Per-generation data should be allocated with * AllocateScreenPrivateIndex() from the ScreenInit() function. */ /* Check the number of entities, and fail if it isn't one. */ if(pScrn->numEntities != 1) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Number of entities is not 1\n"); return FALSE; } /* The vgahw module should be loaded here when needed */ if(!xf86LoadSubModule(pScrn, "vgahw")) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not load vgahw module\n"); return FALSE; } xf86LoaderReqSymLists(vgahwSymbols, NULL); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SiS driver (31/01/03-1) by " "Thomas Winischhofer \n"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "See http://www.winischhofer.net/linuxsisvga.shtml " "for documentation and updates\n"); /* Allocate a vgaHWRec */ if(!vgaHWGetHWRec(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not allocate VGA private\n"); return FALSE; } /* Allocate the SISRec driverPrivate */ if(!SISGetRec(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not allocate memory for pSiS private\n"); return FALSE; } pSiS = SISPTR(pScrn); pSiS->pScrn = pScrn; #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) pSiS->IODBase = 0; #else pSiS->IODBase = pScrn->domainIOBase; #endif /* Get the entity, and make sure it is PCI. */ pSiS->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); if(pSiS->pEnt->location.type != BUS_PCI) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Entity's bus type is not PCI\n"); SISFreeRec(pScrn); return FALSE; } #ifdef SISDUALHEAD /* TW: Allocate an entity private if necessary */ if(xf86IsEntityShared(pScrn->entityList[0])) { pSiSEnt = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex)->ptr; pSiS->entityPrivate = pSiSEnt; /* TW: If something went wrong, quit here */ if ((pSiSEnt->DisableDual) || (pSiSEnt->ErrorAfterFirst)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "First head encountered fatal error, can't continue\n"); SISFreeRec(pScrn); return FALSE; } } #endif /* Find the PCI info for this screen */ pSiS->PciInfo = xf86GetPciInfoForEntity(pSiS->pEnt->index); pSiS->PciTag = pSiS->sishw_ext.PciTag = pciTag(pSiS->PciInfo->bus, pSiS->PciInfo->device, pSiS->PciInfo->func); pSiS->Primary = xf86IsPrimaryPci(pSiS->PciInfo); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "This adapter is %s display adapter\n", (pSiS->Primary ? "primary" : "secondary")); if(pSiS->Primary) { VGAHWPTR(pScrn)->MapSize = 0x10000; /* Standard 64k VGA window */ if(!vgaHWMapMem(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not map VGA memory\n"); SISFreeRec(pScrn); return FALSE; } } vgaHWGetIOBase(VGAHWPTR(pScrn)); /* TW: We "patch" the PIOOffset inside vgaHW in order to force * the vgaHW module to use our relocated i/o ports. */ VGAHWPTR(pScrn)->PIOOffset = pSiS->IODBase + (pSiS->PciInfo->ioBase[2] & 0xFFFC) - 0x380; pSiS->pInt = NULL; if(!pSiS->Primary) { #if !defined(__alpha__) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing display adapter through int10\n"); #endif if(xf86LoadSubModule(pScrn, "int10")) { xf86LoaderReqSymLists(int10Symbols, NULL); #if !defined(__alpha__) pSiS->pInt = xf86InitInt10(pSiS->pEnt->index); #endif } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not load int10 module\n"); } } #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) { resRange vgamem[] = { {ResShrMemBlock,0xA0000,0xAFFFF}, {ResShrMemBlock,0xB0000,0xB7FFF}, {ResShrMemBlock,0xB8000,0xBFFFF}, _END }; xf86SetOperatingState(vgamem, pSiS->pEnt->index, ResUnusedOpr); } #else xf86SetOperatingState(resVgaMem, pSiS->pEnt->index, ResUnusedOpr); #endif /* Operations for which memory access is required */ pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT; /* Operations for which I/O access is required */ pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT; /* The ramdac module should be loaded here when needed */ if(!xf86LoadSubModule(pScrn, "ramdac")) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not load ramdac module\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(ramdacSymbols, NULL); /* Set pScrn->monitor */ pScrn->monitor = pScrn->confScreen->monitor; /* * Set the Chipset and ChipRev, allowing config file entries to * override. DANGEROUS! */ if (pSiS->pEnt->device->chipset && *pSiS->pEnt->device->chipset) { pScrn->chipset = pSiS->pEnt->device->chipset; pSiS->Chipset = xf86StringToToken(SISChipsets, pScrn->chipset); from = X_CONFIG; } else if (pSiS->pEnt->device->chipID >= 0) { pSiS->Chipset = pSiS->pEnt->device->chipID; pScrn->chipset = (char *)xf86TokenToString(SISChipsets, pSiS->Chipset); from = X_CONFIG; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", pSiS->Chipset); } else { from = X_PROBED; pSiS->Chipset = pSiS->PciInfo->chipType; pScrn->chipset = (char *)xf86TokenToString(SISChipsets, pSiS->Chipset); } if (pSiS->pEnt->device->chipRev >= 0) { pSiS->ChipRev = pSiS->pEnt->device->chipRev; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", pSiS->ChipRev); } else { pSiS->ChipRev = pSiS->PciInfo->chipRev; } pSiS->sishw_ext.jChipRevision = pSiS->ChipRev; /* TW: Determine SiS6326 chiprevision. This is not yet used for * anything, but it will as soon as I found out on which revisions * the hardware video overlay really works. * According to SiS the only differences are: * Chip name Chip type TV-Out MPEG II decoder * 6326 AGP Rev. G0/H0 no no * 6326 DVD Rev. D2 yes yes * 6326 Rev. Cx yes yes */ pSiS->SiS6326Flags = 0; if(pSiS->Chipset == PCI_CHIP_SIS6326) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Chipset is SiS6326 %s (revision 0x%02x)\n", (pSiS->ChipRev == 0xaf) ? "(Ax)" : ((pSiS->ChipRev == 0x0a) ? "AGP (G0)" : ((pSiS->ChipRev == 0x0b) ? "AGP (H0)" : (((pSiS->ChipRev & 0xf0) == 0xd0) ? "DVD (Dx)" : (((pSiS->ChipRev & 0xf0) == 0x90) ? "(9x)" : (((pSiS->ChipRev & 0xf0) == 0xc0) ? "(Cx)" : "(unknown)"))))), pSiS->ChipRev); if((pSiS->ChipRev != 0x0a) && (pSiS->ChipRev != 0x0b)) { pSiS->SiS6326Flags |= SIS6326_HASTV; } } /* * This shouldn't happen because such problems should be caught in * SISProbe(), but check it just in case. */ if (pScrn->chipset == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04X is not recognised\n", pSiS->Chipset); #ifdef SISDUALHEAD if (pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } if (pSiS->Chipset < 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chipset \"%s\" is not recognised\n", pScrn->chipset); #ifdef SISDUALHEAD if (pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } /* TW: Determine chipset and VGA engine type for new mode switching code */ switch(pSiS->Chipset) { case PCI_CHIP_SIS300: pSiS->sishw_ext.jChipType = SIS_300; pSiS->VGAEngine = SIS_300_VGA; break; case PCI_CHIP_SIS630: /* 630 + 730 */ pSiS->sishw_ext.jChipType = SIS_630; if(pciReadLong(0x00000000, 0x00) == 0x07301039) { pSiS->sishw_ext.jChipType = SIS_730; } pSiS->VGAEngine = SIS_300_VGA; break; case PCI_CHIP_SIS540: pSiS->sishw_ext.jChipType = SIS_540; pSiS->VGAEngine = SIS_300_VGA; break; case PCI_CHIP_SIS315H: pSiS->sishw_ext.jChipType = SIS_315H; pSiS->VGAEngine = SIS_315_VGA; break; case PCI_CHIP_SIS315: /* TW: Override for simplicity */ pSiS->Chipset = PCI_CHIP_SIS315H; pSiS->sishw_ext.jChipType = SIS_315; pSiS->VGAEngine = SIS_315_VGA; break; case PCI_CHIP_SIS315PRO: /* TW: Override for simplicity */ pSiS->Chipset = PCI_CHIP_SIS315H; pSiS->sishw_ext.jChipType = SIS_315PRO; pSiS->VGAEngine = SIS_315_VGA; break; case PCI_CHIP_SIS550: pSiS->sishw_ext.jChipType = SIS_550; pSiS->VGAEngine = SIS_315_VGA; break; case PCI_CHIP_SIS650: /* 650 + 740 */ pSiS->sishw_ext.jChipType = SIS_650; pSiS->VGAEngine = SIS_315_VGA; break; case PCI_CHIP_SIS330: pSiS->sishw_ext.jChipType = SIS_330; pSiS->VGAEngine = SIS_315_VGA; break; case PCI_CHIP_SIS530: pSiS->sishw_ext.jChipType = SIS_530; pSiS->VGAEngine = SIS_530_VGA; break; default: pSiS->sishw_ext.jChipType = SIS_OLD; pSiS->VGAEngine = SIS_OLD_VGA; break; } /* TW: Now check if sisfb is loaded. Since sisfb only supports * the 300 and 310/325 series, we only do this for these chips. * We use this for checking where sisfb starts its memory * heap in order to automatically detect the correct MaxXFBMem * setting (which normally is given by the option of the same name). * That only works if sisfb is completely running, ie with * a video mode (because the fbdev will not be installed otherwise.) */ pSiS->donttrustpdc = FALSE; pSiS->sisfbpdc = 0; if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) { int fd, i; sisfb_info mysisfbinfo; BOOL found = FALSE; char name[10]; i=0; do { sprintf(name, "/dev/fb%1d", i); if((fd = open(name, 'r'))) { if(!ioctl(fd, SISFB_GET_INFO, &mysisfbinfo)) { if(mysisfbinfo.sisfb_id == SISFB_ID) { if((mysisfbinfo.sisfb_version >= 1) && (mysisfbinfo.sisfb_revision >=5) && (mysisfbinfo.sisfb_patchlevel >= 8)) { /* TW: Added PCI bus/slot/func into in sisfb Version 1.5.08. Check this to make sure we run on the same card as sisfb */ if((mysisfbinfo.sisfb_pcibus == pSiS->PciInfo->bus) && (mysisfbinfo.sisfb_pcislot == pSiS->PciInfo->device) && (mysisfbinfo.sisfb_pcifunc == pSiS->PciInfo->func) ) { found = TRUE; } } else found = TRUE; if(found) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "%s: SiS kernel fb driver (sisfb) %d.%d.%d detected (PCI: %02d:%02d.%d)\n", &name[5], mysisfbinfo.sisfb_version, mysisfbinfo.sisfb_revision, mysisfbinfo.sisfb_patchlevel, pSiS->PciInfo->bus, pSiS->PciInfo->device, pSiS->PciInfo->func); /* TW: Added version/rev/pl in sisfb 1.4.0 */ if(mysisfbinfo.sisfb_version == 0) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Old version of sisfb found. Please update\n"); } pSiS->sisfbMem = mysisfbinfo.heapstart; /* TW: Basically, we can't trust the pdc register if sisfb is loaded */ pSiS->donttrustpdc = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb: memory heap starts at %dKB\n", pSiS->sisfbMem); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb: using video mode 0x%02x\n", mysisfbinfo.fbvidmode); if((mysisfbinfo.sisfb_version >= 1) && (mysisfbinfo.sisfb_revision >=5) && (mysisfbinfo.sisfb_patchlevel >= 6)) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb: %sreserved hardware cursor, using %s command queue\n", (mysisfbinfo.sisfb_caps & 0x80) ? "" : "not ", (mysisfbinfo.sisfb_caps & 0x40) ? "SiS300 series Turbo" : (mysisfbinfo.sisfb_caps & 0x20) ? "SiS310/325 series AGP" : (mysisfbinfo.sisfb_caps & 0x10) ? "SiS310/325 series VRAM" : (mysisfbinfo.sisfb_caps & 0x08) ? "SiS310/325 series MMIO" : "no"); } if((mysisfbinfo.sisfb_version >= 1) && (mysisfbinfo.sisfb_revision >=5) && (mysisfbinfo.sisfb_patchlevel >= 10)) { /* TW: We can trust the pdc value if sisfb is of recent version */ pSiS->donttrustpdc = FALSE; if(mysisfbinfo.sisfb_patchlevel >= 11) { pSiS->sisfbpdc = mysisfbinfo.sisfb_lcdpdc; } } } } } close (fd); } i++; } while((i <= 7) && (!found)); } /* * The first thing we should figure out is the depth, bpp, etc. * TW: Additionally, determine the size of the HWCursor memory * area. */ switch (pSiS->VGAEngine) { case SIS_300_VGA: pSiS->CursorSize = 4096; pix24flags = Support32bppFb | SupportConvert24to32; break; case SIS_315_VGA: pSiS->CursorSize = 16384; pix24flags = Support32bppFb | SupportConvert24to32; break; case SIS_530_VGA: pSiS->CursorSize = 2048; pix24flags = Support32bppFb | Support24bppFb | SupportConvert24to32 | SupportConvert32to24; break; default: pSiS->CursorSize = 2048; pix24flags = Support24bppFb | SupportConvert32to24 | PreferConvert32to24; break; } #ifdef SISDUALHEAD /* TW: In case of Dual Head, we need to determine if we are the "master" head or * the "slave" head. In order to do that, we set PrimInit to DONE in the * shared entity at the end of the first initialization. The second * initialization then knows that some things have already been done. THIS * ALWAYS ASSUMES THAT THE FIRST DEVICE INITIALIZED IS THE MASTER! */ if(xf86IsEntityShared(pScrn->entityList[0])) { if(pSiSEnt->lastInstance > 0) { if(!xf86IsPrimInitDone(pScrn->entityList[0])) { /* First Head (always CRT2) */ pSiS->SecondHead = FALSE; pSiSEnt->pScrn_1 = pScrn; pSiSEnt->CRT1ModeNo = pSiSEnt->CRT2ModeNo = -1; pSiS->DualHeadMode = TRUE; pSiSEnt->DisableDual = FALSE; pSiSEnt->BIOS = NULL; pSiSEnt->SiS_Pr = NULL; } else { /* Second Head (always CRT1) */ pSiS->SecondHead = TRUE; pSiSEnt->pScrn_2 = pScrn; pSiS->DualHeadMode = TRUE; } } else { /* TW: Only one screen in config file - disable dual head mode */ pSiS->SecondHead = FALSE; pSiS->DualHeadMode = FALSE; pSiSEnt->DisableDual = TRUE; } } else { /* TW: Entity is not shared - disable dual head mode */ pSiS->SecondHead = FALSE; pSiS->DualHeadMode = FALSE; } #endif pSiS->ForceCursorOff = FALSE; /* TW: Allocate SiS_Private (for mode switching code) and initialize it */ pSiS->SiS_Pr = NULL; #ifdef SISDUALHEAD if(pSiSEnt) { if(pSiSEnt->SiS_Pr) pSiS->SiS_Pr = pSiSEnt->SiS_Pr; } #endif if(!pSiS->SiS_Pr) { if(!(pSiS->SiS_Pr = xnfcalloc(sizeof(SiS_Private), 1))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not allocate memory for SiS_Pr private\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->SiS_Pr = pSiS->SiS_Pr; #endif memset(pSiS->SiS_Pr, 0, sizeof(SiS_Private)); } pSiS->SiS_Pr->SiS_Backup70xx = 0xff; pSiS->SiS_Pr->SiS_CHOverScan = -1; pSiS->SiS_Pr->SiS_ChSW = FALSE; pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE; /* TW: Get our relocated IO registers */ pSiS->RelIO = (pSiS->PciInfo->ioBase[2] & 0xFFFC) + pSiS->IODBase; pSiS->sishw_ext.ulIOAddress = pSiS->RelIO + 0x30; xf86DrvMsg(pScrn->scrnIndex, from, "Relocated IO registers at 0x%lX\n", (unsigned long)pSiS->RelIO); /* TW: Initialize SiS Port Reg definitions for externally used * BIOS emulation (init.c/init301.c) functions. */ SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30); /* TW: The following identifies the old chipsets. This is only * partly used since the really old chips are not supported, * but I keep it here for future use. */ if(pSiS->VGAEngine == SIS_OLD_VGA || pSiS->VGAEngine == SIS_530_VGA) { switch(pSiS->Chipset) { case PCI_CHIP_SG86C205: /* Just for making it complete */ { unsigned char temp; sisSaveUnlockExtRegisterLock(pSiS, &srlockReg, &crlockReg); inSISIDXREG(SISSR, 0x10, temp); if(temp & 0x80) pSiS->oldChipset = OC_SIS6205B; else pSiS->oldChipset = (pSiS->ChipRev == 0x11) ? OC_SIS6205C : OC_SIS6205A; break; } case PCI_CHIP_SIS82C204: /* Just for making it complete */ pSiS->oldChipset = OC_SIS82204; break; case 0x6225: /* Just for making it complete */ pSiS->oldChipset = OC_SIS6225; break; case PCI_CHIP_SIS5597: pSiS->oldChipset = OC_SIS5597; break; case PCI_CHIP_SIS6326: pSiS->oldChipset = OC_SIS6326; break; case PCI_CHIP_SIS530: if((pSiS->ChipRev & 0x0f) < 0x0a) pSiS->oldChipset = OC_SIS530A; else pSiS->oldChipset = OC_SIS530B; break; default: pSiS->oldChipset = OC_UNKNOWN; } } if(!xf86SetDepthBpp(pScrn, 8, 8, 8, pix24flags)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86SetDepthBpp() error\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } /* Check that the returned depth is one we support */ temp = 0; switch(pScrn->depth) { case 8: case 16: case 24: break; case 15: if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) temp = 1; break; default: temp = 1; } if(temp) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given depth (%d) is not supported by this driver/chipset\n", pScrn->depth); if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } xf86PrintDepthBpp(pScrn); /* Get the depth24 pixmap format */ if(pScrn->depth == 24 && pix24bpp == 0) pix24bpp = xf86GetBppFromDepth(pScrn, 24); /* * This must happen after pScrn->display has been set because * xf86SetWeight references it. */ if(pScrn->depth > 8) { /* The defaults are OK for us */ rgb zeros = {0, 0, 0}; if(!xf86SetWeight(pScrn, zeros, zeros)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86SetWeight() error\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } else { Bool ret = FALSE; switch(pScrn->depth) { case 15: if((pScrn->weight.red != 5) || (pScrn->weight.green != 5) || (pScrn->weight.blue != 5)) ret = TRUE; break; case 16: if((pScrn->weight.red != 5) || (pScrn->weight.green != 6) || (pScrn->weight.blue != 5)) ret = TRUE; break; case 24: if((pScrn->weight.red != 8) || (pScrn->weight.green != 8) || (pScrn->weight.blue != 8)) ret = TRUE; break; } if(ret) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RGB Weight %d%d%d at depth %d not supported by hardware\n", pScrn->weight.red, pScrn->weight.green, pScrn->weight.blue, pScrn->depth); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } } } /* TW: Set the current layout parameters */ pSiS->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; pSiS->CurrentLayout.depth = pScrn->depth; /* (Inside this function, we can use pScrn's contents anyway) */ if(!xf86SetDefaultVisual(pScrn, -1)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86SetDefaultVisual() error\n"); #ifdef SISDUALHEAD if (pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } else { /* We don't support DirectColor at > 8bpp */ if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual " "(%s) is not supported at depth %d\n", xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); #ifdef SISDUALHEAD if (pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } } /* * The cmap layer needs this to be initialised. */ { Gamma zeros = {0.0, 0.0, 0.0}; if(!xf86SetGamma(pScrn, zeros)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86SetGamma() error\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); SISFreeRec(pScrn); return FALSE; } } /* We use a programamble clock */ pScrn->progClock = TRUE; /* Set the bits per RGB for 8bpp mode */ if(pScrn->depth == 8) { pScrn->rgbBits = 6; } pSiS->ddc1Read = SiSddc1Read; from = X_DEFAULT; /* Unlock registers */ sisSaveUnlockExtRegisterLock(pSiS, &srlockReg, &crlockReg); /* TW: We need no backup area (300/310/325 new mode switching code) */ pSiS->sishw_ext.pSR = NULL; pSiS->sishw_ext.pCR = NULL; /* TW: Read BIOS for 300 and 310/325 series customization */ pSiS->sishw_ext.pjVirtualRomBase = NULL; pSiS->BIOS = NULL; pSiS->sishw_ext.UseROM = FALSE; if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { #ifdef SISDUALHEAD if(pSiSEnt) { if(pSiSEnt->BIOS) { pSiS->BIOS = pSiSEnt->BIOS; pSiS->sishw_ext.pjVirtualRomBase = pSiS->BIOS; } } #endif if(!pSiS->BIOS) { if(!(pSiS->BIOS = xcalloc(1, BIOS_SIZE))) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Could not allocate memory for video BIOS image\n"); } else { unsigned long segstart; unsigned short romptr; BOOLEAN found; int i; static const char sis_rom_sig[] = "Silicon Integrated Systems"; static const char *sis_sig[10] = { "300", "540", "630", "730", "315", "315", "315", "5315", "6325", "Xabre" }; static const unsigned short sis_nums[10] = { SIS_300, SIS_540, SIS_630, SIS_730, SIS_315PRO, SIS_315H, SIS_315, SIS_550, SIS_650, SIS_330 }; found = FALSE; for(segstart=BIOS_BASE; segstart<0x000f0000; segstart+=0x00001000) { #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) if(xf86ReadBIOS(segstart, 0, pSiS->BIOS, BIOS_SIZE) != BIOS_SIZE) continue; #else if(xf86ReadDomainMemory(pSiS->PciTag, segstart, BIOS_SIZE, pSiS->BIOS) != BIOS_SIZE) continue; #endif if((pSiS->BIOS[0] != 0x55) || (pSiS->BIOS[1] != 0xaa)) continue; romptr = pSiS->BIOS[0x12] | (pSiS->BIOS[0x13] << 8); if(romptr > (BIOS_SIZE - strlen(sis_rom_sig))) continue; if(strncmp(sis_rom_sig, (char *)&pSiS->BIOS[romptr], strlen(sis_rom_sig)) != 0) continue; romptr = pSiS->BIOS[0x14] | (pSiS->BIOS[0x15] << 8); if(romptr > (BIOS_SIZE - 5)) continue; for(i = 0; (i < 10) && (!found); i++) { if(strncmp(sis_sig[i], (char *)&pSiS->BIOS[romptr], strlen(sis_sig[i])) == 0) { if(sis_nums[i] == pSiS->sishw_ext.jChipType) { found = TRUE; break; } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Ignoring BIOS for SiS %s at %p\n", sis_sig[i], segstart); } } } if(found) break; } if(!found) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Could not find/read video BIOS\n"); xfree(pSiS->BIOS); pSiS->BIOS = NULL; } else { #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->BIOS = pSiS->BIOS; #endif pSiS->sishw_ext.pjVirtualRomBase = pSiS->BIOS; romptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Video BIOS version \"%7s\" found at %p\n", &pSiS->BIOS[romptr], segstart); } } } if(pSiS->BIOS) pSiS->sishw_ext.UseROM = TRUE; else pSiS->sishw_ext.UseROM = FALSE; } /* Evaluate options */ SiSOptions(pScrn); #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(!pSiS->SecondHead) { /* TW: Copy some option settings to entity private */ pSiSEnt->HWCursor = pSiS->HWCursor; pSiSEnt->ForceCRT2Type = pSiS->ForceCRT2Type; pSiSEnt->ForceTVType = pSiS->ForceTVType; pSiSEnt->TurboQueue = pSiS->TurboQueue; pSiSEnt->PDC = pSiS->PDC; pSiSEnt->OptTVStand = pSiS->OptTVStand; pSiSEnt->NonDefaultPAL = pSiS->NonDefaultPAL; pSiSEnt->OptTVOver = pSiS->OptTVOver; pSiSEnt->OptTVSOver = pSiS->OptTVSOver; pSiSEnt->OptROMUsage = pSiS->OptROMUsage; pSiSEnt->DSTN = pSiS->DSTN; pSiSEnt->XvOnCRT2 = pSiS->XvOnCRT2; pSiSEnt->NoAccel = pSiS->NoAccel; pSiSEnt->NoXvideo = pSiS->NoXvideo; pSiSEnt->forceCRT1 = pSiS->forceCRT1; pSiSEnt->chtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs; pSiSEnt->chtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo; pSiSEnt->chtvlumaflickerfilter = pSiS->chtvlumaflickerfilter; pSiSEnt->chtvchromabandwidth = pSiS->chtvchromabandwidth; pSiSEnt->chtvchromaflickerfilter = pSiS->chtvchromaflickerfilter; pSiSEnt->chtvtextenhance = pSiS->chtvtextenhance; pSiSEnt->chtvcontrast = pSiS->chtvcontrast; pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor; pSiSEnt->sistvedgeenhance = pSiS->sistvedgeenhance; pSiSEnt->sistvantiflicker = pSiS->sistvantiflicker; pSiSEnt->sistvsaturation = pSiS->sistvsaturation; pSiSEnt->tvxpos = pSiS->tvxpos; pSiSEnt->tvypos = pSiS->tvypos; pSiSEnt->restorebyset = pSiS->restorebyset; } else { /* We always use same cursor type on both screens */ if(pSiS->HWCursor != pSiSEnt->HWCursor) { pSiS->HWCursor = pSiSEnt->HWCursor; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent HWCursor setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: HWCursor shall be %s\n", pSiS->HWCursor ? "enabled" : "disabled"); } /* We need to use identical CRT2 Type setting */ if(pSiS->ForceCRT2Type != pSiSEnt->ForceCRT2Type) { if(pSiS->ForceCRT2Type != CRT2_DEFAULT) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Ignoring inconsistent ForceCRT2Type setting. Master head rules\n"); } pSiS->ForceCRT2Type = pSiSEnt->ForceCRT2Type; } if(pSiS->ForceTVType != pSiSEnt->ForceTVType) { if(pSiS->ForceTVType != -1) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Ignoring inconsistent ForceTVType setting. Master head rules\n"); } pSiS->ForceTVType = pSiSEnt->ForceTVType; } /* We need identical TurboQueue setting */ if(pSiS->TurboQueue != pSiSEnt->TurboQueue) { pSiS->TurboQueue = pSiSEnt->TurboQueue; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent TurboQueue setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: Turboqueue shall be %s\n", pSiS->TurboQueue ? "enabled" : "disabled"); } /* We need identical PDC setting */ if(pSiS->PDC != pSiSEnt->PDC) { pSiS->PDC = pSiSEnt->PDC; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent PanelDelayCompensation setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: PanelDelayCompensation shall be %d%s\n", pSiS->PDC, (pSiS->PDC == -1) ? " (autodetected)" : ""); } /* We need identical TVStandard setting */ if( (pSiS->OptTVStand != pSiSEnt->OptTVStand) || (pSiS->NonDefaultPAL != pSiSEnt->NonDefaultPAL) ) { if(pSiS->OptTVStand != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent TVStandard setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: TVStandard shall be %s\n", (pSiSEnt->OptTVStand ? ( (pSiSEnt->NonDefaultPAL == -1) ? "PAL" : ((pSiSEnt->NonDefaultPAL) ? "PALM" : "PALN") ) : "NTSC")); } pSiS->OptTVStand = pSiSEnt->OptTVStand; pSiS->NonDefaultPAL = pSiSEnt->NonDefaultPAL; } /* We need identical UseROMData setting */ if(pSiS->OptROMUsage != pSiSEnt->OptROMUsage) { if(pSiS->OptROMUsage != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent UseROMData setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: Video ROM data usage shall be %s\n", pSiSEnt->OptROMUsage ? "enabled" : "disabled"); } pSiS->OptROMUsage = pSiSEnt->OptROMUsage; } /* We need identical DSTN setting */ if(pSiS->DSTN != pSiSEnt->DSTN) { pSiS->DSTN = pSiSEnt->DSTN; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent DSTN setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: DSTN shall be %s\n", pSiS->DSTN ? "enabled" : "disabled"); } /* We need identical XvOnCRT2 setting */ if(pSiS->XvOnCRT2 != pSiSEnt->XvOnCRT2) { pSiS->XvOnCRT2 = pSiSEnt->XvOnCRT2; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent XvOnCRT2 setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: Xv shall be used on CRT%d\n", pSiS->XvOnCRT2 ? 2 : 1); } /* We need identical NoAccel setting */ if(pSiS->NoAccel != pSiSEnt->NoAccel) { pSiS->NoAccel = pSiSEnt->NoAccel; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent NoAccel setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: Acceleration shall be %s\n", pSiS->NoAccel ? "disabled" : "enabled"); } /* We need identical ForceCRT1 setting */ if(pSiS->forceCRT1 != pSiSEnt->forceCRT1) { if(pSiS->forceCRT1 != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent ForceCRT1 setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: CRT1 shall be %s\n", pSiSEnt->forceCRT1 ? "enabled" : "disabled"); } pSiS->forceCRT1 = pSiSEnt->forceCRT1; } /* We need identical TVOverscan setting */ if(pSiS->OptTVOver != pSiSEnt->OptTVOver) { if(pSiS->OptTVOver != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVOverscan setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: CHTVOverscan shall be %s\n", pSiSEnt->OptTVOver ? "true (=overscan)" : "false (=underscan)"); } pSiS->OptTVOver = pSiSEnt->OptTVOver; } /* We need identical TVSOverscan setting */ if(pSiS->OptTVSOver != pSiSEnt->OptTVSOver) { if(pSiS->OptTVSOver != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVSuperOverscan setting\n"); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Master head ruled: CHTVSuperOverscan shall be %s\n", pSiSEnt->OptTVSOver ? "true" : "false"); } pSiS->OptTVSOver = pSiSEnt->OptTVSOver; } /* We need identical TV settings */ if(pSiS->chtvtype != pSiSEnt->chtvtype) { if(pSiS->chtvtype != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVType setting; set to %s\n", (pSiSEnt->chtvtype) ? "SCART" : "HDTV"); } pSiS->chtvtype = pSiSEnt->chtvtype; } if(pSiS->chtvlumabandwidthcvbs != pSiSEnt->chtvlumabandwidthcvbs) { if(pSiS->chtvlumabandwidthcvbs != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVLumaBandWidthCVBS setting; set to %d\n", pSiSEnt->chtvlumabandwidthcvbs); } pSiS->chtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs; } if(pSiS->chtvlumabandwidthsvideo != pSiSEnt->chtvlumabandwidthsvideo) { if(pSiS->chtvlumabandwidthsvideo != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVLumaBandWidthSVIDEO setting; set to %d\n", pSiSEnt->chtvlumabandwidthsvideo); } pSiS->chtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo; } if(pSiS->chtvlumaflickerfilter != pSiSEnt->chtvlumaflickerfilter) { if(pSiS->chtvlumaflickerfilter != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVLumaFlickerFilter setting; set to %d\n", pSiSEnt->chtvlumaflickerfilter); } pSiS->chtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter; } if(pSiS->chtvchromabandwidth != pSiSEnt->chtvchromabandwidth) { if(pSiS->chtvchromabandwidth != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVChromaBandWidth setting; set to %d\n", pSiSEnt->chtvchromabandwidth); } pSiS->chtvchromabandwidth = pSiSEnt->chtvchromabandwidth; } if(pSiS->chtvchromaflickerfilter != pSiSEnt->chtvchromaflickerfilter) { if(pSiS->chtvchromaflickerfilter != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVChromaFlickerFilter setting; set to %d\n", pSiSEnt->chtvchromaflickerfilter); } pSiS->chtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter; } if(pSiS->chtvcvbscolor != pSiSEnt->chtvcvbscolor) { if(pSiS->chtvcvbscolor != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVCVBSColor setting; set to %s\n", pSiSEnt->chtvcvbscolor ? "true" : "false"); } pSiS->chtvcvbscolor = pSiSEnt->chtvcvbscolor; } if(pSiS->chtvtextenhance != pSiSEnt->chtvtextenhance) { if(pSiS->chtvtextenhance != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVTextEnhance setting; set to %d\n", pSiSEnt->chtvtextenhance); } pSiS->chtvtextenhance = pSiSEnt->chtvtextenhance; } if(pSiS->chtvcontrast != pSiSEnt->chtvcontrast) { if(pSiS->chtvcontrast != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent CHTVContrast setting; set to %d\n", pSiSEnt->chtvcontrast); } pSiS->chtvcontrast = pSiSEnt->chtvcontrast; } if(pSiS->sistvedgeenhance != pSiSEnt->sistvedgeenhance) { if(pSiS->sistvedgeenhance != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent SISTVEdgeEnhance setting; set to %d\n", pSiSEnt->sistvedgeenhance); } pSiS->sistvedgeenhance = pSiSEnt->sistvedgeenhance; } if(pSiS->sistvantiflicker != pSiSEnt->sistvantiflicker) { if(pSiS->sistvantiflicker != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent SISTVAntiFlicker setting; set to %d\n", pSiSEnt->sistvantiflicker); } pSiS->sistvantiflicker = pSiSEnt->sistvantiflicker; } if(pSiS->sistvsaturation != pSiSEnt->sistvsaturation) { if(pSiS->sistvsaturation != -1) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent SISTVSaturation setting; set to %d\n", pSiSEnt->sistvsaturation); } pSiS->sistvsaturation = pSiSEnt->sistvsaturation; } if(pSiS->tvxpos != pSiSEnt->tvxpos) { if(pSiS->tvxpos != 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent TVXPosOffset setting; set to %d\n", pSiSEnt->tvxpos); } pSiS->tvxpos = pSiSEnt->tvxpos; } if(pSiS->tvypos != pSiSEnt->tvypos) { if(pSiS->tvypos != 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Ignoring inconsistent TVYPosOffset setting; set to %d\n", pSiSEnt->tvypos); } pSiS->tvypos = pSiSEnt->tvypos; } if(pSiS->restorebyset != pSiSEnt->restorebyset) { pSiS->restorebyset = pSiSEnt->restorebyset; } } } #endif /* TW: Handle UseROMData and NoOEM options */ if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { from = X_PROBED; if(pSiS->OptROMUsage == 0) { pSiS->sishw_ext.UseROM = FALSE; from = X_CONFIG; } xf86DrvMsg(pScrn->scrnIndex, from, "Video ROM data usage is %s\n", pSiS->sishw_ext.UseROM ? "enabled" : "disabled"); if(!pSiS->OptUseOEM) xf86DrvMsg(pScrn->scrnIndex, from, "Internal OEM LCD/TV data usage is disabled\n"); if(pSiS->sbiosn) { if(pSiS->BIOS) { FILE *fd = NULL; int i; if((fd = fopen(pSiS->sbiosn, "w" ))) { i = fwrite(pSiS->BIOS, 65536, 1, fd); fclose(fd); } } xfree(pSiS->sbiosn); } } /* Do basic configuration */ SiSSetup(pScrn); from = X_PROBED; if (pSiS->pEnt->device->MemBase != 0) { /* * XXX Should check that the config file value matches one of the * PCI base address values. */ pSiS->FbAddress = pSiS->pEnt->device->MemBase; from = X_CONFIG; } else { pSiS->FbAddress = pSiS->PciInfo->memBase[0] & 0xFFFFFFF0; } pSiS->realFbAddress = pSiS->FbAddress; #ifdef SISDUALHEAD if(pSiS->DualHeadMode) xf86DrvMsg(pScrn->scrnIndex, from, "Global linear framebuffer at 0x%lX\n", (unsigned long)pSiS->FbAddress); else #endif xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", (unsigned long)pSiS->FbAddress); if (pSiS->pEnt->device->IOBase != 0) { /* * XXX Should check that the config file value matches one of the * PCI base address values. */ pSiS->IOAddress = pSiS->pEnt->device->IOBase; from = X_CONFIG; } else { pSiS->IOAddress = pSiS->PciInfo->memBase[1] & 0xFFFFFFF0; } xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX\n", (unsigned long)pSiS->IOAddress); pSiS->sishw_ext.bIntegratedMMEnabled = TRUE; /* Register the PCI-assigned resources. */ if(xf86RegisterResources(pSiS->pEnt->index, NULL, ResExclusive)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86RegisterResources() found resource conflicts\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); SISFreeRec(pScrn); return FALSE; } from = X_PROBED; if (pSiS->pEnt->device->videoRam != 0) { pScrn->videoRam = pSiS->pEnt->device->videoRam; from = X_CONFIG; } pSiS->RealVideoRam = pScrn->videoRam; if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pScrn->videoRam > 4096) && (from != X_CONFIG)) { pScrn->videoRam = 4096; xf86DrvMsg(pScrn->scrnIndex, from, "SiS6326: Detected %d KB VideoRAM, limiting to %d KB\n", pSiS->RealVideoRam, pScrn->videoRam); } else xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d KB\n", pScrn->videoRam); if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pScrn->videoRam > 4096)) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SiS6326 engines do not support more than 4096KB RAM, therefore\n"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TurboQueue, HWCursor, 2D acceleration and XVideo are disabled.\n"); pSiS->TurboQueue = FALSE; pSiS->HWCursor = FALSE; pSiS->NoXvideo = TRUE; pSiS->NoAccel = TRUE; } pSiS->FbMapSize = pSiS->availMem = pScrn->videoRam * 1024; pSiS->sishw_ext.ulVideoMemorySize = pScrn->videoRam * 1024; pSiS->sishw_ext.bSkipDramSizing = TRUE; /* TW: Calculate real availMem according to Accel/TurboQueue and * HWCursur setting. Also, initialize some variables used * in other modules. */ pSiS->cursorOffset = 0; switch (pSiS->VGAEngine) { case SIS_300_VGA: pSiS->TurboQueueLen = 512; if(pSiS->TurboQueue) { pSiS->availMem -= (pSiS->TurboQueueLen*1024); pSiS->cursorOffset = 512; } if(pSiS->HWCursor) { pSiS->availMem -= pSiS->CursorSize; if(pSiS->OptUseColorCursor) pSiS->availMem -= pSiS->CursorSize; } pSiS->CmdQueLenMask = 0xFFFF; pSiS->CmdQueLenFix = 0; pSiS->cursorBufferNum = 0; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->cursorBufferNum = 0; #endif break; case SIS_315_VGA: if(pSiS->TurboQueue) { pSiS->availMem -= (512*1024); /* Command Queue is 512k */ pSiS->cursorOffset = 512; } if(pSiS->HWCursor) { pSiS->availMem -= pSiS->CursorSize; if(pSiS->OptUseColorCursor) pSiS->availMem -= pSiS->CursorSize; } pSiS->cursorBufferNum = 0; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->cursorBufferNum = 0; #endif break; default: /* TW: cursorOffset not used in cursor functions for 530 and * older chips, because the cursor is *above* the TQ. * On 5597 and older revisions of the 6326, the TQ is * max 32K, on newer 6326 revisions and the 530 either 30 * (or 32?) or 62K (or 64?). However, to make sure, we * use only 30K (or 32?), but reduce the available memory * by 64, and locate the TQ at the beginning of this last * 64K block. (We do this that way even when using the * HWCursor, because the cursor only takes 2K, and the queue * does not seem to last that far anyway.) * The TQ must be located at 32KB boundaries. */ if(pSiS->RealVideoRam < 3072) { if(pSiS->TurboQueue) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not enough video RAM for TurboQueue. TurboQueue disabled\n"); } pSiS->TurboQueue = FALSE; } pSiS->CmdQueMaxLen = 32; if(pSiS->TurboQueue) { pSiS->availMem -= (64*1024); pSiS->CmdQueMaxLen = 900; /* TW: To make sure; should be 992 */ } else if (pSiS->HWCursor) { pSiS->availMem -= pSiS->CursorSize; } if(pSiS->Chipset == PCI_CHIP_SIS530) { /* TW: Check if Flat Panel is enabled */ inSISIDXREG(SISSR, 0x0e, tempreg); if(!tempreg & 0x04) pSiS->availMem -= pSiS->CursorSize; /* TW: Set up mask for MMIO register */ pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x1FFF : 0x00FF; } else { /* TW: TQ is never used on 6326/5597, because the accelerator * always Syncs. So this is just cosmentic work. (And I * am not even sure that 0x7fff is correct. MMIO 0x83a8 * holds 0xec0 if (30k) TQ is enabled, 0x20 if TQ disabled. * The datasheet has no real explanation on the queue length * if the TQ is enabled. Not syncing and waiting for a * suitable queue length instead does not work. */ pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x7FFF : 0x003F; } /* TW: This is to be subtracted from MMIO queue length register contents * for getting the real Queue length. */ pSiS->CmdQueLenFix = (pSiS->TurboQueue) ? 32 : 0; } #ifdef SISDUALHEAD /* TW: In dual head mode, we share availMem equally - so align it * to 8KB; this way, the address of the FB of the second * head is aligned to 4KB for mapping. */ if (pSiS->DualHeadMode) pSiS->availMem &= 0xFFFFE000; #endif /* TW: Check MaxXFBMem setting */ #ifdef SISDUALHEAD /* TW: Since DRI is not supported in dual head mode, we don't need MaxXFBMem setting. */ if (pSiS->DualHeadMode) { if(pSiS->maxxfbmem) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MaxXFBMem not used in Dual Head mode. Using all VideoRAM.\n"); } pSiS->maxxfbmem = pSiS->availMem; } else #endif if (pSiS->maxxfbmem) { if (pSiS->maxxfbmem > pSiS->availMem) { if (pSiS->sisfbMem) { pSiS->maxxfbmem = pSiS->sisfbMem * 1024; xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid MaxXFBMem setting. Using sisfb heap start information\n"); } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid MaxXFBMem setting. Using all VideoRAM for framebuffer\n"); pSiS->maxxfbmem = pSiS->availMem; } } else if (pSiS->sisfbMem) { if (pSiS->maxxfbmem > pSiS->sisfbMem * 1024) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MaxXFBMem beyond sisfb heap start. Using sisfb heap start information\n"); pSiS->maxxfbmem = pSiS->sisfbMem * 1024; } } } else if (pSiS->sisfbMem) { pSiS->maxxfbmem = pSiS->sisfbMem * 1024; } else pSiS->maxxfbmem = pSiS->availMem; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dK of framebuffer memory\n", pSiS->maxxfbmem / 1024); /* TW: Check if the chipset supports two video overlays */ pSiS->Flags650 = 0; if ( (!pSiS->NoXvideo) && ( pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA || pSiS->Chipset == PCI_CHIP_SIS530 || pSiS->Chipset == PCI_CHIP_SIS6326 || pSiS->Chipset == PCI_CHIP_SIS5597 ) ) { pSiS->hasTwoOverlays = FALSE; switch (pSiS->Chipset) { case PCI_CHIP_SIS300: case PCI_CHIP_SIS630: case PCI_CHIP_SIS550: case PCI_CHIP_SIS330: /* ? */ pSiS->hasTwoOverlays = TRUE; break; case PCI_CHIP_SIS650: { static const char *id650str[] = { "0", "0", "0", "0", "0 A0 AA", "0 A2 CA", "0", "0", "0M A0", "0M A1 AA", "1 A0 AA", "1 A1 AA" "0", "0", "0", "0" }; inSISIDXREG(SISCR, 0x5F, CR5F); CR5F &= 0xf0; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "SiS650 revision ID %x (SiS65%s)\n", CR5F, id650str[CR5F >> 4]); if((CR5F == 0x80) || (CR5F == 0x90) || (CR5F == 0xa0) || (CR5F == 0xb0)) { pSiS->hasTwoOverlays = TRUE; /* TW: This is an M650 or 651 */ pSiS->Flags650 |= SiS650_LARGEOVERLAY; } break; } } xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Hardware supports %s video overlay%s\n", pSiS->hasTwoOverlays ? "two" : "one", pSiS->hasTwoOverlays ? "s" : ""); } /* TW: Backup VB connection and CRT1 on/off register */ if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { inSISIDXREG(SISCR, 0x32, pSiS->oldCR32); inSISIDXREG(SISCR, 0x17, pSiS->oldCR17); pSiS->postVBCR32 = pSiS->oldCR32; } if(pSiS->forceCRT1 != -1) { if(pSiS->forceCRT1) pSiS->CRT1off = 0; else pSiS->CRT1off = 1; } else pSiS->CRT1off = -1; /* TW: There are some strange machines out there which require a special * manupulation of ISA bridge registers in order to make the Chrontel * work. Try to find out if we're running on such a machine. */ pSiS->SiS_Pr->SiS_ChSW = FALSE; if(pSiS->Chipset == PCI_CHIP_SIS630) { int i=0; do { if(mychswtable[i].subsysVendor == pSiS->PciInfo->subsysVendor && mychswtable[i].subsysCard == pSiS->PciInfo->subsysCard) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PCI card/vendor found in list for Chrontel/ISA bridge poking\n"); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Vendor: %s (ID %04x)\n", mychswtable[i].vendorName, pSiS->PciInfo->subsysCard); pSiS->SiS_Pr->SiS_ChSW = TRUE; } i++; } while(mychswtable[i].subsysVendor != 0); } /* TW: Detect video bridge and sense connected devices */ SISVGAPreInit(pScrn); /* TW: Detect CRT1 */ SISCRT1PreInit(pScrn); /* TW: Detect CRT2-LCD and LCD size */ SISLCDPreInit(pScrn); /* TW: Detect CRT2-TV and PAL/NTSC mode */ SISTVPreInit(pScrn); /* TW: Detect CRT2-VGA */ SISCRT2PreInit(pScrn); /* TW: Backup detected CRT2 devices */ pSiS->detectedCRT2Devices = pSiS->VBFlags & (CRT2_LCD | CRT2_TV | CRT2_VGA); /* TW: Eventually overrule detected CRT2 type */ if(pSiS->ForceCRT2Type == CRT2_DEFAULT) { if(pSiS->VBFlags & CRT2_VGA) pSiS->ForceCRT2Type = CRT2_VGA; else if(pSiS->VBFlags & CRT2_LCD) pSiS->ForceCRT2Type = CRT2_LCD; else if(pSiS->VBFlags & CRT2_TV) pSiS->ForceCRT2Type = CRT2_TV; } switch(pSiS->ForceCRT2Type) { case CRT2_TV: pSiS->VBFlags = pSiS->VBFlags & ~(CRT2_LCD | CRT2_VGA); if(pSiS->VBFlags & VB_VIDEOBRIDGE) pSiS->VBFlags = pSiS->VBFlags | CRT2_TV; else pSiS->VBFlags = pSiS->VBFlags & ~(CRT2_TV); break; case CRT2_LCD: pSiS->VBFlags = pSiS->VBFlags & ~(CRT2_TV | CRT2_VGA); if((pSiS->VBFlags & VB_VIDEOBRIDGE) && (pSiS->VBLCDFlags)) pSiS->VBFlags = pSiS->VBFlags | CRT2_LCD; else { pSiS->VBFlags = pSiS->VBFlags & ~(CRT2_LCD); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Can't force CRT2 to LCD, no panel detected\n"); } break; case CRT2_VGA: if(pSiS->VBFlags & VB_LVDS) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "LVDS does not support secondary VGA\n"); break; } if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SiS30xLV bridge does not support secondary VGA\n"); break; } pSiS->VBFlags = pSiS->VBFlags & ~(CRT2_TV | CRT2_LCD); if(pSiS->VBFlags & VB_VIDEOBRIDGE) pSiS->VBFlags = pSiS->VBFlags | CRT2_VGA; else pSiS->VBFlags = pSiS->VBFlags & ~(CRT2_VGA); break; default: pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA); } /* TW: Eventually overrule TV Type (SVIDEO, COMPOSITE, SCART) */ if(pSiS->ForceTVType != -1) { if(pSiS->VBFlags & VB_SISBRIDGE) { pSiS->VBFlags &= ~(TV_INTERFACE); pSiS->VBFlags |= pSiS->ForceTVType; } } /* TW: Handle ForceCRT1 option */ pSiS->CRT1changed = FALSE; if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { usScratchCR17 = pSiS->oldCR17; usScratchCR32 = pSiS->postVBCR32; if(pSiS->VESA != 1) { /* TW: Copy forceCRT1 option to CRT1off if option is given */ #ifdef SISDUALHEAD /* TW: In DHM, handle this option only for master head, not the slave */ if( (pSiS->forceCRT1 != -1) && (!(pSiS->DualHeadMode && pSiS->SecondHead)) ) { #else if(pSiS->forceCRT1 != -1) { #endif xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "CRT1 detection overruled by ForceCRT1 option\n"); if(pSiS->forceCRT1) { pSiS->CRT1off = 0; if (!(usScratchCR17 & 0x80)) pSiS->CRT1changed = TRUE; usScratchCR17 |= 0x80; usScratchCR32 |= 0x20; } else { if( ! ( (pScrn->bitsPerPixel == 8) && ( (pSiS->VBFlags & VB_LVDS) || ((pSiS->VGAEngine == SIS_300_VGA) && (pSiS->VBFlags & VB_301B)) ) ) ) { pSiS->CRT1off = 1; if (usScratchCR17 & 0x80) pSiS->CRT1changed = TRUE; usScratchCR32 &= ~0x20; /* TW: We must not actually switch off CRT1 before we changed the mode! */ } } outSISIDXREG(SISCR, 0x17, usScratchCR17); outSISIDXREG(SISCR, 0x32, usScratchCR32); if(pSiS->CRT1changed) { outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ usleep(10000); outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT1 status changed by ForceCRT1 option\n"); } } } /* TW: Store the new VB connection register contents for later mode changes */ pSiS->newCR32 = usScratchCR32; } /* TW: Check if CRT1 used (or needed; this eg. if no CRT2 detected) */ if (pSiS->VBFlags & VB_VIDEOBRIDGE) { /* TW: No CRT2 output? Then we NEED CRT1! * We also need CRT1 if depth = 8 and bridge=LVDS|630+301B */ if ( (!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) || ( (pScrn->bitsPerPixel == 8) && ( (pSiS->VBFlags & (VB_LVDS | VB_CHRONTEL)) || ((pSiS->VGAEngine == SIS_300_VGA) && (pSiS->VBFlags & VB_301B)) ) ) ) { pSiS->CRT1off = 0; } /* TW: No CRT2 output? Then we can't use Xv on CRT2 */ if (!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) pSiS->XvOnCRT2 = FALSE; } else { /* TW: no video bridge? */ /* Then we NEED CRT1... */ pSiS->CRT1off = 0; /* ... and can't use CRT2 for Xv output */ pSiS->XvOnCRT2 = FALSE; } /* TW: Handle TVStandard option */ if(pSiS->NonDefaultPAL != -1) { if( (!(pSiS->VBFlags & VB_SISBRIDGE)) && (!((pSiS->VBFlags & VB_CHRONTEL)) && (pSiS->ChrontelType == CHRONTEL_701x)) ) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PALM and PALN only supported on Chrontel 701x and SiS30x/B/LV\n"); pSiS->NonDefaultPAL = -1; pSiS->VBFlags &= ~(TV_PALN | TV_PALM); } } if(pSiS->NonDefaultPAL != -1) { if((pSiS->Chipset == PCI_CHIP_SIS300) || (pSiS->Chipset == PCI_CHIP_SIS540)) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PALM and PALN not supported on SiS300 and SiS540\n"); pSiS->NonDefaultPAL = -1; pSiS->VBFlags &= ~(TV_PALN | TV_PALM); } } if(pSiS->OptTVStand != -1) { if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { if(!(pSiS->Flags & (TV_CHSCART | TV_CHHDTV))) { pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM); if(pSiS->OptTVStand) pSiS->VBFlags |= TV_PAL; else pSiS->VBFlags |= TV_NTSC; if(pSiS->NonDefaultPAL == 1) pSiS->VBFlags |= TV_PALM; else if(!pSiS->NonDefaultPAL) pSiS->VBFlags |= TV_PALN; } else { pSiS->OptTVStand = pSiS->NonDefaultPAL = -1; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Option TVStandard ignored for SCART and 480i HDTV\n"); } } else if(pSiS->Chipset == PCI_CHIP_SIS6326) { pSiS->SiS6326Flags &= ~SIS6326_TVPAL; if(pSiS->OptTVStand) pSiS->SiS6326Flags |= SIS6326_TVPAL; } } /* TW: Do some checks */ if(pSiS->OptTVOver != -1) { if(pSiS->VBFlags & VB_CHRONTEL) { pSiS->UseCHOverScan = pSiS->OptTVOver; } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CHTVOverscan option only supported on CHRONTEL 70xx\n"); pSiS->UseCHOverScan = -1; } } else pSiS->UseCHOverScan = -1; if(pSiS->sistvedgeenhance != -1) { if(!(pSiS->VBFlags & VB_301)) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SISTVEdgeEnhance option only supported on SiS301\n"); pSiS->sistvedgeenhance = -1; } } /* TW: Determine CRT1<>CRT2 mode * Note: When using VESA or if the bridge is in slavemode, display * is ALWAYS in MIRROR_MODE! * This requires extra checks in functions using this flag! * (see sis_video.c for example) */ if(pSiS->VBFlags & DISPTYPE_DISP2) { if(pSiS->CRT1off) { /* TW: CRT2 only ------------------------------- */ #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRT1 not detected or forced off. Dual Head mode can't initialize.\n"); if(pSiSEnt) pSiSEnt->DisableDual = TRUE; if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); SISFreeRec(pScrn); return FALSE; } #endif pSiS->VBFlags |= VB_DISPMODE_SINGLE; /* TW: No CRT1? Then we use the video overlay on CRT2 */ pSiS->XvOnCRT2 = TRUE; } else /* TW: CRT1 and CRT2 - mirror or dual head ----- */ #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { pSiS->VBFlags |= (VB_DISPMODE_DUAL | DISPTYPE_CRT1); if(pSiS->VESA != -1) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VESA option not used in Dual Head mode. VESA disabled.\n"); } if (pSiSEnt) pSiSEnt->DisableDual = FALSE; pSiS->VESA = 0; } else #endif pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1); } else { /* TW: CRT1 only ------------------------------- */ #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No CRT2 output selected or no bridge detected. " "Dual Head mode can't initialize.\n"); if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); SISFreeRec(pScrn); return FALSE; } #endif pSiS->VBFlags |= (VB_DISPMODE_SINGLE | DISPTYPE_CRT1); } if( (pSiS->VGAEngine == SIS_315_VGA) || (pSiS->VGAEngine == SIS_300_VGA) ) { if ( (!pSiS->NoXvideo) && (!pSiS->hasTwoOverlays) ) { xf86DrvMsg(pScrn->scrnIndex, from, "Using Xv overlay on CRT%d\n", pSiS->XvOnCRT2 ? 2 : 1); } } /* TW: Init Ptrs for Save/Restore functions and calc MaxClock */ SISDACPreInit(pScrn); /* ********** end of VBFlags setup ********** */ /* TW: VBFlags are initialized now. Back them up for SlaveMode modes. */ pSiS->VBFlags_backup = pSiS->VBFlags; /* TW: Find out about paneldelaycompensation and evaluate option */ pSiS->sishw_ext.pdc = 0; if(pSiS->VGAEngine == SIS_300_VGA) { if(pSiS->VBFlags & (VB_LVDS | VB_301B | VB_302B)) { /* TW: Save the current PDC if the panel is used at the moment. * This seems by far the safest way to find out about it. * If the system is using an old version of sisfb, we can't * trust the pdc register value. If sisfb saved the pdc for * us, use it. */ if(pSiS->sisfbpdc) { pSiS->sishw_ext.pdc = pSiS->sisfbpdc; } else { if(!(pSiS->donttrustpdc)) { unsigned char tmp; inSISIDXREG(SISCR, 0x30, tmp); if(tmp & 0x20) { inSISIDXREG(SISPART1, 0x13, pSiS->sishw_ext.pdc); } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unable to detect LCD PanelDelayCompensation, LCD is not active\n"); } } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unable to detect LCD PanelDelayCompensation, please update sisfb\n"); } } pSiS->sishw_ext.pdc &= 0x3c; if(pSiS->sishw_ext.pdc) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected LCD PanelDelayCompensation %d\n", pSiS->sishw_ext.pdc); } /* If we haven't been able to find out, use our other methods */ if(pSiS->sishw_ext.pdc == 0) { int i=0; do { if(mypdctable[i].subsysVendor == pSiS->PciInfo->subsysVendor && mypdctable[i].subsysCard == pSiS->PciInfo->subsysCard) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PCI card/vendor found in list for non-default PanelDelayCompensation\n"); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Vendor: %s, card: %s (ID %04x), PanelDelayCompensation: %d\n", mypdctable[i].vendorName, mypdctable[i].cardName, pSiS->PciInfo->subsysCard, mypdctable[i].pdc); if(pSiS->PDC == -1) { pSiS->PDC = mypdctable[i].pdc; } else { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PanelDelayCompensation overruled by option\n"); } break; } i++; } while(mypdctable[i].subsysVendor != 0); } if(pSiS->PDC != -1) { if(pSiS->BIOS) { if(pSiS->VBFlags & VB_LVDS) { if(pSiS->BIOS[0x220] & 0x80) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "BIOS contains custom LCD Panel Delay Compensation %d\n", pSiS->BIOS[0x220] & 0x3c); pSiS->BIOS[0x220] &= 0x7f; } } if(pSiS->VBFlags & (VB_301B|VB_302B)) { if(pSiS->BIOS[0x220] & 0x80) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "BIOS contains custom LCD Panel Delay Compensation %d\n", ( (pSiS->VBLCDFlags & VB_LCD_1280x1024) ? pSiS->BIOS[0x223] : pSiS->BIOS[0x224] ) & 0x3c); pSiS->BIOS[0x220] &= 0x7f; } } } pSiS->sishw_ext.pdc = (pSiS->PDC & 0x3c); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using LCD Panel Delay Compensation %d\n", pSiS->PDC); } } } #ifdef SISDUALHEAD /* TW: In dual head mode, both heads (currently) share the maxxfbmem equally. * If memory sharing is done differently, the following has to be changed; * the other modules (eg. accel and Xv) use dhmOffset for hardware * pointer settings relative to VideoRAM start and won't need to be changed. */ if (pSiS->DualHeadMode) { if (pSiS->SecondHead == FALSE) { /* ===== First head (always CRT2) ===== */ /* We use only half of the memory available */ pSiS->maxxfbmem /= 2; /* Initialize dhmOffset */ pSiS->dhmOffset = 0; /* Copy framebuffer addresses & sizes to entity */ pSiSEnt->masterFbAddress = pSiS->FbAddress; pSiSEnt->masterFbSize = pSiS->maxxfbmem; pSiSEnt->slaveFbAddress = pSiS->FbAddress + pSiS->maxxfbmem; pSiSEnt->slaveFbSize = pSiS->maxxfbmem; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "%dKB video RAM at 0x%lx available for master head (CRT2)\n", pSiS->maxxfbmem/1024, pSiS->FbAddress); } else { /* ===== Second head (always CRT1) ===== */ /* We use only half of the memory available */ pSiS->maxxfbmem /= 2; /* Adapt FBAddress */ pSiS->FbAddress += pSiS->maxxfbmem; /* Initialize dhmOffset */ pSiS->dhmOffset = pSiS->availMem - pSiS->maxxfbmem; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "%dKB video RAM at 0x%lx available for slave head (CRT1)\n", pSiS->maxxfbmem/1024, pSiS->FbAddress); } } else pSiS->dhmOffset = 0; #endif /* TW: Note: Do not use availMem for anything from now. Use * maxxfbmem instead. (availMem does not take dual head * mode into account.) */ /* TW: Now for something completely different: DDC. For 300 and 310/325 series, we provide our own functions (in order to probe CRT2 as well) If these fail, use the VBE. All other chipsets will use VBE. No need to re-invent the wheel there. */ pSiS->pVbe = NULL; didddc2 = FALSE; if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { if(xf86LoadSubModule(pScrn, "ddc")) { xf86LoaderReqSymLists(ddcSymbols, NULL); if((pMonitor = SiSDoPrivateDDC(pScrn))) { didddc2 = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DDC monitor info:\n"); xf86PrintEDID(pMonitor); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "End of DDC monitor info\n"); xf86SetDDCproperties(pScrn, pMonitor); pScrn->monitor->DDC = pMonitor; } } } #ifdef SISDUALHEAD /* TW: In dual head mode, probe DDC using VBE only for CRT1 (second head) */ if((pSiS->DualHeadMode) && (!didddc2) && (!pSiS->SecondHead)) didddc2 = TRUE; #endif /* TW: If CRT1 is off (eventually forced), skip DDC */ if((!didddc2) && (pSiS->CRT1off)) didddc2 = TRUE; /* TW: Now (re-)load and initialize the DDC module */ if(!didddc2) { if(xf86LoadSubModule(pScrn, "ddc")) { xf86LoaderReqSymLists(ddcSymbols, NULL); /* TW: Now load and initialize VBE module. */ if(xf86LoadSubModule(pScrn, "vbe")) { xf86LoaderReqSymLists(vbeSymbols, NULL); #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) pSiS->pVbe = VBEInit(pSiS->pInt,pSiS->pEnt->index); #else pSiS->pVbe = VBEExtendedInit(pSiS->pInt,pSiS->pEnt->index, SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); #endif if(!pSiS->pVbe) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Could not initialize VBE module for DDC\n"); } } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Could not load VBE module for DDC\n"); } if(pSiS->pVbe) { if((pMonitor = vbeDoEDID(pSiS->pVbe,NULL))) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VBE DDC monitor info:\n"); xf86SetDDCproperties(pScrn, xf86PrintEDID(pMonitor)); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "End of VBE DDC monitor info:\n"); pScrn->monitor->DDC = pMonitor; } } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Could not retrieve DDC data\n"); } } } #if 0 /* TW: DDC1 obviously no longer supported by SiS chipsets */ if (!ret && pSiS->ddc1Read) xf86SetDDCproperties(pScrn, xf86PrintEDID(xf86DoEDID_DDC1( pScrn->scrnIndex,vgaHWddc1SetSpeed,pSiS->ddc1Read ))); #endif /* end of DDC */ /* Set the min pixel clock */ pSiS->MinClock = 12000; /* XXX Guess, need to check this (TW: good for even 50Hz interlace) */ xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n", pSiS->MinClock / 1000); from = X_PROBED; /* * If the user has specified ramdac speed in the XF86Config * file, we respect that setting. */ if(pSiS->pEnt->device->dacSpeeds[0]) { int speed = 0; switch(pScrn->bitsPerPixel) { case 8: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP8]; break; case 16: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP16]; break; case 24: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP24]; break; case 32: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP32]; break; } if(speed == 0) pSiS->MaxClock = pSiS->pEnt->device->dacSpeeds[0]; else pSiS->MaxClock = speed; from = X_CONFIG; } xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n", pSiS->MaxClock / 1000); /* * Setup the ClockRanges, which describe what clock ranges are available, * and what sort of modes they can be used for. */ clockRanges = xnfcalloc(sizeof(ClockRange), 1); clockRanges->next = NULL; clockRanges->minClock = pSiS->MinClock; clockRanges->maxClock = pSiS->MaxClock; clockRanges->clockIndex = -1; /* programmable */ clockRanges->interlaceAllowed = TRUE; clockRanges->doubleScanAllowed = TRUE; /* TW: If there is no HSync or VRefresh data for the monitor, derive it from DDC data. (Idea taken from radeon driver) */ if(pScrn->monitor->DDC) { if(pScrn->monitor->nHsync <= 0) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Substituting missing monitor HSync data by DDC data\n"); SiSSetSyncRangeFromEdid(pScrn, 1); } if(pScrn->monitor->nVrefresh <= 0) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Substituting missing monitor VRefresh data by DDC data\n"); SiSSetSyncRangeFromEdid(pScrn, 0); } } /* * TW: Since we have lots of built-in modes for 300/310/325/330 series * with vb support, we replace the given default mode list with our * own. In case the video bridge is to be used, no other than our * built-in modes are supported; therefore, delete the entire modelist * given. */ pSiS->HaveCustomModes = FALSE; if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { if(!(pSiS->noInternalModes)) { if((mymodes = SiSBuildBuiltInModeList(pScrn))) { #ifdef SISDUALHEAD if( (pSiS->UseVESA) || ((pSiS->DualHeadMode) && (!pSiS->SecondHead)) || ((!pSiS->DualHeadMode) && (pSiS->VBFlags & DISPTYPE_DISP2)) ) { #else if((pSiS->UseVESA) || (pSiS->VBFlags & DISPTYPE_DISP2)) { #endif while(pScrn->monitor->Modes) xf86DeleteMode(&pScrn->monitor->Modes, pScrn->monitor->Modes); pScrn->monitor->Modes = mymodes; } else { delmode = pScrn->monitor->Modes; while(delmode) { if(delmode->type & M_T_DEFAULT) { tempmode = delmode->next; xf86DeleteMode(&pScrn->monitor->Modes, delmode); delmode = tempmode; } else { delmode = delmode->next; } } tempmode = pScrn->monitor->Modes; if(tempmode) pSiS->HaveCustomModes = TRUE; pScrn->monitor->Modes = mymodes; while(mymodes) { if(!mymodes->next) break; else mymodes = mymodes->next; } mymodes->next = tempmode; if(tempmode) { tempmode->prev = mymodes; } } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Replaced %s mode list with built-in modes\n", pSiS->HaveCustomModes ? "default" : "entire"); #ifdef TWDEBUG pScrn->modes = pScrn->monitor->Modes; xf86PrintModes(pScrn); pScrn->modes = NULL; #endif } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Building list of built-in modes failed, using XFree86 defaults\n"); } } } /* * TW: Add our built-in modes for TV on the 6326 */ if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Adding %s TV modes for 6326 to mode list:\n", (pSiS->SiS6326Flags & SIS6326_TVPAL) ? "PAL" : "NTSC"); if(pSiS->SiS6326Flags & SIS6326_TVPAL) { SiS6326PAL800x600Mode.next = pScrn->monitor->Modes; pScrn->monitor->Modes = &SiS6326PAL640x480Mode; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\"PAL800x600\" \"PAL800x600U\" \"PAL720x540\" \"PAL640x480\"\n"); } else { SiS6326NTSC640x480Mode.next = pScrn->monitor->Modes; pScrn->monitor->Modes = &SiS6326NTSC640x400Mode; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\"NTSC640x480\" \"NTSC640x480U\" \"NTSC640x400\"\n"); } } } /* * TW: Add our built-in hi-res modes on the 6326 */ if(pSiS->Chipset == PCI_CHIP_SIS6326) { if(pScrn->bitsPerPixel == 8) { SiS6326SIS1600x1200_60Mode.next = pScrn->monitor->Modes; pScrn->monitor->Modes = &SiS6326SIS1600x1200_60Mode; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Adding mode \"SIS1600x1200-60\" (depth 8 only)\n"); } if(pScrn->bitsPerPixel <= 16) { SiS6326SIS1280x1024_75Mode.next = pScrn->monitor->Modes; pScrn->monitor->Modes = &SiS6326SIS1280x1024_75Mode; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Adding mode \"SIS1280x1024-75\" (depth 8, 15 and 16 only)\n"); } } if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\"Unknown reason\" in the following list means that the mode\n"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "is not supported on the chipset/bridge/current output device.\n"); } /* * xf86ValidateModes will check that the mode HTotal and VTotal values * don't exceed the chipset's limit if pScrn->maxHValue and * pScrn->maxVValue are set. Since our SISValidMode() already takes * care of this, we don't worry about setting them here. */ /* Select valid modes from those available */ /* * Assuming min pitch 256, max 4096 ==> 8192 * Assuming min height 128, max 4096 */ i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, clockRanges, NULL, 256, 8192, pScrn->bitsPerPixel * 8, 128, 4096, pScrn->display->virtualX, pScrn->display->virtualY, pSiS->maxxfbmem, LOOKUP_BEST_REFRESH); if(i == -1) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86ValidateModes() error\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); SISFreeRec(pScrn); return FALSE; } /* TW: Go through mode list and mark all those modes as bad, * - which are unsuitable for dual head mode (if running dhm), * - which exceed the LCD panels specs (if running on LCD) * - TODO: which exceed TV capabilities (if running on TV) * Also, find the highest used pixelclock on the master head. */ #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(!pSiS->SecondHead) pSiSEnt->maxUsedClock = 0; } #endif if((p = first = pScrn->modes)) { do { n = p->next; /* TW: Check the modes if they comply with our built-in tables. * This is of practical use only if the user disabled the * usage of the internal (built-in) modes. */ if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { if(p->type & M_T_DEFAULT) { if( ( (strcmp(p->name, "320x200") != 0) && (strcmp(p->name, "320x240") != 0) && (strcmp(p->name, "400x300") != 0) && (strcmp(p->name, "512x384") != 0) ) && (p->Flags & V_DBLSCAN) ) { p->status = MODE_NO_DBLESCAN; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" (mode not supported as doublescan)\n", p->name); } if( ( (strcmp(p->name, "1024x768") != 0) && (strcmp(p->name, "1280x1024") != 0) && (strcmp(p->name, "848x480") != 0) && (strcmp(p->name, "856x480") != 0)) && (p->Flags & V_INTERLACE) ) { p->status = MODE_NO_INTERLACE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" (mode not supported as interlaced)\n", p->name); } if( ( (strcmp(p->name, "320x200") == 0) || (strcmp(p->name, "320x240") == 0) || (strcmp(p->name, "400x300") == 0) || (strcmp(p->name, "512x384") == 0) ) && (!(p->Flags & V_DBLSCAN)) ) { p->status = MODE_CLOCK_RANGE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" (only supported as doublescan)\n", p->name); } } } #ifdef SISDUALHEAD /* TW: Modes that require the bridge to operate in SlaveMode * are not suitable for Dual Head mode. Also check for * modes that exceed panel dimension. */ if(pSiS->DualHeadMode) { if(pSiS->SecondHead == FALSE) { if( (strcmp(p->name, "320x200") == 0) || (strcmp(p->name, "320x240") == 0) || (strcmp(p->name, "400x300") == 0) || (strcmp(p->name, "512x384") == 0) || (strcmp(p->name, "640x400") == 0) ) { p->status = MODE_BAD; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" (not suitable for dual head mode)\n", p->name); } } if(pSiS->VBFlags & DISPTYPE_DISP2) { if(pSiS->VBFlags & CRT2_LCD) { if(pSiS->SecondHead == FALSE) { if((p->HDisplay > pSiS->LCDwidth) || (p->VDisplay > pSiS->LCDheight)) { p->status = MODE_PANEL; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" (exceeds LCD panel dimension)\n", p->name); } if(p->Flags & V_INTERLACE) { p->status = MODE_BAD; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" (interlace on LCD not supported)\n", p->name); } } } /* TO DO: TV */ } /* TW: Search for the highest clock on first head in order to calculate * max clock for second head (CRT1) */ if(!pSiS->SecondHead) { if((p->status == MODE_OK) && (p->Clock > pSiSEnt->maxUsedClock)) { pSiSEnt->maxUsedClock = p->Clock; } } } else { #endif if(pSiS->VBFlags & DISPTYPE_DISP2) { if(pSiS->VBFlags & CRT2_LCD) { if((p->HDisplay > pSiS->LCDwidth) || (p->VDisplay > pSiS->LCDheight)) { p->status = MODE_PANEL; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" (exceeds LCD panel dimension)\n", p->name); } if(p->Flags & V_INTERLACE) { p->status = MODE_BAD; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" (interlace on LCD not supported)\n", p->name); } } } #ifdef SISDUALHEAD } #endif p = n; } while (p != NULL && p != first); } /* Prune the modes marked as invalid */ xf86PruneDriverModes(pScrn); if(i == 0 || pScrn->modes == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); SISFreeRec(pScrn); return FALSE; } xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); /* Set the current mode to the first in the list */ pScrn->currentMode = pScrn->modes; /* TW: Copy to CurrentLayout */ pSiS->CurrentLayout.mode = pScrn->currentMode; pSiS->CurrentLayout.displayWidth = pScrn->displayWidth; /* Print the list of modes being used */ xf86PrintModes(pScrn); #ifdef SISDUALHEAD /* TW: Due to palette & timing problems we don't support 8bpp in DHM */ if((pSiS->DualHeadMode) && (pScrn->bitsPerPixel == 8)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Colordepth 8 not supported in Dual Head mode.\n"); if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); SISFreeRec(pScrn); return FALSE; } #endif /* Set display resolution */ xf86SetDpi(pScrn, 0, 0); /* Load bpp-specific modules */ switch(pScrn->bitsPerPixel) { case 1: mod = "xf1bpp"; Sym = "xf1bppScreenInit"; break; case 4: mod = "xf4bpp"; Sym = "xf4bppScreenInit"; break; case 8: case 16: case 24: case 32: mod = "fb"; break; } if(mod && xf86LoadSubModule(pScrn, mod) == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not load %s module", mod); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); SISFreeRec(pScrn); return FALSE; } if(mod) { if(Sym) { xf86LoaderReqSymbols(Sym, NULL); } else { xf86LoaderReqSymLists(fbSymbols, NULL); } } /* Load XAA if needed */ if(!pSiS->NoAccel) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Accel enabled\n"); if(!xf86LoadSubModule(pScrn, "xaa")) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not load xaa module\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); SISFreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(xaaSymbols, NULL); } /* Load shadowfb if needed */ if(pSiS->ShadowFB) { if(!xf86LoadSubModule(pScrn, "shadowfb")) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not load shadowfb module\n"); #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE; #endif if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); SISFreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(shadowSymbols, NULL); } /* TW: Now load and initialize VBE module for VESA. */ pSiS->UseVESA = 0; if(pSiS->VESA == 1) { if(!pSiS->pVbe) { if(xf86LoadSubModule(pScrn, "vbe")) { xf86LoaderReqSymLists(vbeSymbols, NULL); #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) pSiS->pVbe = VBEInit(pSiS->pInt,pSiS->pEnt->index); #else pSiS->pVbe = VBEExtendedInit(pSiS->pInt,pSiS->pEnt->index, SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); #endif } } if(pSiS->pVbe) { vbe = VBEGetVBEInfo(pSiS->pVbe); pSiS->vesamajor = (unsigned)(vbe->VESAVersion >> 8); pSiS->vesaminor = vbe->VESAVersion & 0xff; pSiS->vbeInfo = vbe; SiSBuildVesaModeList(pScrn, pSiS->pVbe, vbe); VBEFreeVBEInfo(vbe); pSiS->UseVESA = 1; } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Could not load and initialize VBE module. VESA disabled.\n"); } } if(pSiS->pVbe) { vbeFree(pSiS->pVbe); pSiS->pVbe = NULL; } #ifdef SISDUALHEAD xf86SetPrimInitDone(pScrn->entityList[0]); #endif sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg); if(pSiS->pInt) xf86FreeInt10(pSiS->pInt); pSiS->pInt = NULL; return TRUE; } /* * Map the framebuffer and MMIO memory. */ static Bool SISMapMem(ScrnInfoPtr pScrn) { SISPtr pSiS; int mmioFlags; #ifdef SISDUALHEAD SISEntPtr pSiSEnt = NULL; #endif pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD pSiSEnt = pSiS->entityPrivate; #endif /* * Map IO registers to virtual address space */ #if !defined(__alpha__) mmioFlags = VIDMEM_MMIO; #else /* * For Alpha, we need to map SPARSE memory, since we need * byte/short access. */ mmioFlags = VIDMEM_MMIO | VIDMEM_SPARSE; #endif #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { pSiSEnt->MapCountIOBase++; if(!(pSiSEnt->IOBase)) { /* TW: Only map if not mapped previously */ pSiSEnt->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, pSiS->PciTag, pSiS->IOAddress, 0x10000); } pSiS->IOBase = pSiSEnt->IOBase; } else #endif pSiS->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, pSiS->PciTag, pSiS->IOAddress, 0x10000); if(pSiS->IOBase == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not map MMIO area\n"); return FALSE; } #ifdef __alpha__ /* * for Alpha, we need to map DENSE memory as well, for * setting CPUToScreenColorExpandBase. */ #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { pSiSEnt->MapCountIOBaseDense++; if(!(pSiSEnt->IOBaseDense)) { /* TW: Only map if not mapped previously */ pSiSEnt->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pSiS->PciTag, pSiS->IOAddress, 0x10000); } pSiS->IOBaseDense = pSiSEnt->IOBaseDense; } else #endif pSiS->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pSiS->PciTag, pSiS->IOAddress, 0x10000); if(pSiS->IOBaseDense == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not map MMIO dense area\n"); return FALSE; } #endif /* __alpha__ */ #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { pSiSEnt->MapCountFbBase++; if(!(pSiSEnt->FbBase)) { /* TW: Only map if not mapped previously */ pSiSEnt->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, pSiS->PciTag, (unsigned long)pSiS->realFbAddress, pSiS->FbMapSize); pSiS->sishw_ext.pjVideoMemoryAddress = (UCHAR *)pSiSEnt->FbBase; } pSiS->FbBase = pSiSEnt->FbBase; /* TW: Adapt FbBase (for DHM; dhmOffset is 0 otherwise) */ pSiS->FbBase += pSiS->dhmOffset; } else { #endif pSiS->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, pSiS->PciTag, (unsigned long)pSiS->FbAddress, pSiS->FbMapSize); pSiS->sishw_ext.pjVideoMemoryAddress = (UCHAR *)pSiS->FbBase; #ifdef SISDUALHEAD } #endif if(pSiS->FbBase == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not map framebuffer area\n"); return FALSE; } return TRUE; } /* * Unmap the framebuffer and MMIO memory. */ static Bool SISUnmapMem(ScrnInfoPtr pScrn) { SISPtr pSiS; #ifdef SISDUALHEAD SISEntPtr pSiSEnt = NULL; #endif pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD pSiSEnt = pSiS->entityPrivate; #endif /* TW: In dual head mode, we must not unmap if the other head still * assumes memory as mapped */ #ifdef SISDUALHEAD if (pSiS->DualHeadMode) { if (pSiSEnt->MapCountIOBase) { pSiSEnt->MapCountIOBase--; if ((pSiSEnt->MapCountIOBase == 0) || (pSiSEnt->forceUnmapIOBase)) { xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBase, 0x10000); pSiSEnt->IOBase = NULL; pSiSEnt->MapCountIOBase = 0; pSiSEnt->forceUnmapIOBase = FALSE; } pSiS->IOBase = NULL; } #ifdef __alpha__ if (pSiSEnt->MapCountIOBaseDense) { pSiSEnt->MapCountIOBaseDense--; if ((pSiSEnt->MapCountIOBaseDense == 0) || (pSiSEnt->forceUnmapIOBaseDense)) { xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBaseDense, 0x10000); pSiSEnt->IOBaseDense = NULL; pSiSEnt->MapCountIOBaseDense = 0; pSiSEnt->forceUnmapIOBaseDense = FALSE; } pSiS->IOBaseDense = NULL; } #endif /* __alpha__ */ if (pSiSEnt->MapCountFbBase) { pSiSEnt->MapCountFbBase--; if ((pSiSEnt->MapCountFbBase == 0) || (pSiSEnt->forceUnmapFbBase)) { xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->FbBase, pSiS->FbMapSize); pSiSEnt->FbBase = NULL; pSiSEnt->MapCountFbBase = 0; pSiSEnt->forceUnmapFbBase = FALSE; } pSiS->FbBase = NULL; } } else { #endif xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBase, 0x10000); pSiS->IOBase = NULL; #ifdef __alpha__ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBaseDense, 0x10000); pSiS->IOBaseDense = NULL; #endif xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->FbBase, pSiS->FbMapSize); pSiS->FbBase = NULL; #ifdef SISDUALHEAD } #endif return TRUE; } /* * This function saves the video state. */ static void SISSave(ScrnInfoPtr pScrn) { SISPtr pSiS; vgaRegPtr vgaReg; SISRegPtr sisReg; pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD /* TW: We always save master & slave */ if(pSiS->DualHeadMode && pSiS->SecondHead) return; #endif vgaReg = &VGAHWPTR(pScrn)->SavedReg; sisReg = &pSiS->SavedReg; vgaHWSave(pScrn, vgaReg, VGA_SR_ALL); sisSaveUnlockExtRegisterLock(pSiS,&sisReg->sisRegs3C4[0x05],&sisReg->sisRegs3D4[0x80]); (*pSiS->SiSSave)(pScrn, sisReg); if(pSiS->UseVESA) SISVESASaveRestore(pScrn, MODE_SAVE); /* TW: Save these as they may have been changed prior to SISSave() call */ if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { sisReg->sisRegs3D4[0x17] = pSiS->oldCR17; if(vgaReg->numCRTC >= 0x17) vgaReg->CRTC[0x17] = pSiS->oldCR17; sisReg->sisRegs3D4[0x32] = pSiS->oldCR32; } } /* * TW: Just adapted from the std* functions in vgaHW.c */ static void SiS_WriteAttr(SISPtr pSiS, int index, int value) { CARD8 tmp; tmp = inb(pSiS->IODBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); index |= 0x20; outb(pSiS->IODBase + VGA_ATTR_INDEX, index); outb(pSiS->IODBase + VGA_ATTR_DATA_W, value); } static int SiS_ReadAttr(SISPtr pSiS, int index) { CARD8 tmp; tmp = inb(pSiS->IODBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); index |= 0x20; outb(pSiS->IODBase + VGA_ATTR_INDEX, index); return (inb(pSiS->IODBase + VGA_ATTR_DATA_R)); } static void SiS_SaveFonts(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn; #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) CARD8 *vgaIOBase = (CARD8 *)VGAHWPTR(pScrn)->IOBase; #else pointer vgaIOBase = VGAHWPTR(pScrn)->Base; #endif if (pSiS->fonts != NULL) return; /* If in graphics mode, don't save anything */ attr10 = SiS_ReadAttr(pSiS, 0x10); if (attr10 & 0x01) return; pSiS->fonts = xalloc(16384); /* save the registers that are needed here */ miscOut = inSISREG(SISMISCR); inSISIDXREG(SISGR, 0x04, gr4); inSISIDXREG(SISGR, 0x05, gr5); inSISIDXREG(SISGR, 0x06, gr6); inSISIDXREG(SISSR, 0x02, seq2); inSISIDXREG(SISSR, 0x04, seq4); /* Force into color mode */ outSISREG(SISMISCW, miscOut | 0x01); inSISIDXREG(SISSR, 0x01, scrn); outSISIDXREG(SISSR, 0x00, 0x01); outSISIDXREG(SISSR, 0x01, scrn | 0x20); outSISIDXREG(SISSR, 0x00, 0x03); SiS_WriteAttr(pSiS, 0x10, 0x01); /* graphics mode */ /*font1 */ outSISIDXREG(SISSR, 0x02, 0x04); /* write to plane 2 */ outSISIDXREG(SISSR, 0x04, 0x06); /* enable plane graphics */ outSISIDXREG(SISGR, 0x04, 0x02); /* read plane 2 */ outSISIDXREG(SISGR, 0x05, 0x00); /* write mode 0, read mode 0 */ outSISIDXREG(SISGR, 0x06, 0x05); /* set graphics */ slowbcopy_frombus(vgaIOBase, pSiS->fonts, 8192); /* font2 */ outSISIDXREG(SISSR, 0x02, 0x08); /* write to plane 3 */ outSISIDXREG(SISSR, 0x04, 0x06); /* enable plane graphics */ outSISIDXREG(SISGR, 0x04, 0x03); /* read plane 3 */ outSISIDXREG(SISGR, 0x05, 0x00); /* write mode 0, read mode 0 */ outSISIDXREG(SISGR, 0x06, 0x05); /* set graphics */ slowbcopy_frombus(vgaIOBase, pSiS->fonts + 8192, 8192); inSISIDXREG(SISSR, 0x01, scrn); outSISIDXREG(SISSR, 0x00, 0x01); outSISIDXREG(SISSR, 0x01, scrn & ~0x20); outSISIDXREG(SISSR, 0x00, 0x03); /* Restore clobbered registers */ SiS_WriteAttr(pSiS, 0x10, attr10); outSISIDXREG(SISSR, 0x02, seq2); outSISIDXREG(SISSR, 0x04, seq4); outSISIDXREG(SISGR, 0x04, gr4); outSISIDXREG(SISGR, 0x05, gr5); outSISIDXREG(SISGR, 0x06, gr6); outSISREG(SISMISCW, miscOut); } static void SiS_RestoreFonts(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn; #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) CARD8 *vgaIOBase = (CARD8 *)VGAHWPTR(pScrn)->IOBase; #else pointer vgaIOBase = VGAHWPTR(pScrn)->Base; #endif if (pSiS->fonts == NULL) return; #if 0 if (pVesa->mapPhys == 0xa0000 && pVesa->curBank != 0) VESABankSwitch(pScrn->pScreen, 0); #endif /* save the registers that are needed here */ miscOut = inSISREG(SISMISCR); attr10 = SiS_ReadAttr(pSiS, 0x10); inSISIDXREG(SISGR, 0x01, gr1); inSISIDXREG(SISGR, 0x03, gr3); inSISIDXREG(SISGR, 0x04, gr4); inSISIDXREG(SISGR, 0x05, gr5); inSISIDXREG(SISGR, 0x06, gr6); inSISIDXREG(SISGR, 0x08, gr8); inSISIDXREG(SISSR, 0x02, seq2); inSISIDXREG(SISSR, 0x04, seq4); /* Force into color mode */ outSISREG(SISMISCW, miscOut | 0x01); inSISIDXREG(SISSR, 0x01, scrn); outSISIDXREG(SISSR, 0x00, 0x01); outSISIDXREG(SISSR, 0x01, scrn | 0x20); outSISIDXREG(SISSR, 0x00, 0x03); SiS_WriteAttr(pSiS, 0x10, 0x01); /* graphics mode */ if (pScrn->depth == 4) { outSISIDXREG(SISGR, 0x03, 0x00); /* don't rotate, write unmodified */ outSISIDXREG(SISGR, 0x08, 0xFF); /* write all bits in a byte */ outSISIDXREG(SISGR, 0x01, 0x00); /* all planes come from CPU */ } outSISIDXREG(SISSR, 0x02, 0x04); /* write to plane 2 */ outSISIDXREG(SISSR, 0x04, 0x06); /* enable plane graphics */ outSISIDXREG(SISGR, 0x04, 0x02); /* read plane 2 */ outSISIDXREG(SISGR, 0x05, 0x00); /* write mode 0, read mode 0 */ outSISIDXREG(SISGR, 0x06, 0x05); /* set graphics */ slowbcopy_tobus(pSiS->fonts, vgaIOBase, 8192); outSISIDXREG(SISSR, 0x02, 0x08); /* write to plane 3 */ outSISIDXREG(SISSR, 0x04, 0x06); /* enable plane graphics */ outSISIDXREG(SISGR, 0x04, 0x03); /* read plane 3 */ outSISIDXREG(SISGR, 0x05, 0x00); /* write mode 0, read mode 0 */ outSISIDXREG(SISGR, 0x06, 0x05); /* set graphics */ slowbcopy_tobus(pSiS->fonts + 8192, vgaIOBase, 8192); inSISIDXREG(SISSR, 0x01, scrn); outSISIDXREG(SISSR, 0x00, 0x01); outSISIDXREG(SISSR, 0x01, scrn & ~0x20); outSISIDXREG(SISSR, 0x00, 0x03); /* restore the registers that were changed */ outSISREG(SISMISCW, miscOut); SiS_WriteAttr(pSiS, 0x10, attr10); outSISIDXREG(SISGR, 0x01, gr1); outSISIDXREG(SISGR, 0x03, gr3); outSISIDXREG(SISGR, 0x04, gr4); outSISIDXREG(SISGR, 0x05, gr5); outSISIDXREG(SISGR, 0x06, gr6); outSISIDXREG(SISGR, 0x08, gr8); outSISIDXREG(SISSR, 0x02, seq2); outSISIDXREG(SISSR, 0x04, seq4); } /* TW: VESASaveRestore taken from vesa driver */ static void SISVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function) { SISPtr pSiS; pSiS = SISPTR(pScrn); /* Query amount of memory to save state */ if (function == MODE_QUERY || (function == MODE_SAVE && pSiS->state == NULL)) { /* Make sure we save at least this information in case of failure */ (void)VBEGetVBEMode(pSiS->pVbe, &pSiS->stateMode); SiS_SaveFonts(pScrn); if (pSiS->vesamajor > 1) { if (!VBESaveRestore(pSiS->pVbe,function,(pointer)&pSiS->state, &pSiS->stateSize,&pSiS->statePage)) return; } } /* Save/Restore Super VGA state */ if (function != MODE_QUERY) { Bool retval = TRUE; if (pSiS->vesamajor > 1) { if (function == MODE_RESTORE) memcpy(pSiS->state, pSiS->pstate, pSiS->stateSize); if ((retval = VBESaveRestore(pSiS->pVbe,function, (pointer)&pSiS->state, &pSiS->stateSize,&pSiS->statePage)) && function == MODE_SAVE) { /* don't rely on the memory not being touched */ if (pSiS->pstate == NULL) pSiS->pstate = xalloc(pSiS->stateSize); memcpy(pSiS->pstate, pSiS->state, pSiS->stateSize); } } if (function == MODE_RESTORE) { VBESetVBEMode(pSiS->pVbe, pSiS->stateMode, NULL); SiS_RestoreFonts(pScrn); } #if 0 if (!retval) return (FALSE); #endif } #if 0 if ( (pSiS->vesamajor > 1) && (function == MODE_SAVE || pSiS->pstate) ) { if (function == MODE_RESTORE) memcpy(pSiS->state, pSiS->pstate, pSiS->stateSize); if ((VBESaveRestore(pSiS->pVbe,function, (pointer)&pSiS->state, &pSiS->stateSize,&pSiS->statePage))) { if (function == MODE_SAVE) { /* don't rely on the memory not being touched */ if (pSiS->pstate == NULL) pSiS->pstate = xalloc(pSiS->stateSize); memcpy(pSiS->pstate, pSiS->state, pSiS->stateSize); } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "VBESaveRestore done with success\n"); return; } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "VBESaveRestore done\n"); } else { if (function == MODE_SAVE) (void)VBEGetVBEMode(pSiS->pVbe, &pSiS->stateMode); else VBESetVBEMode(pSiS->pVbe, pSiS->stateMode, NULL); } #endif } /* * Initialise a new mode. This is currently done using the * "initialise struct, restore/write struct to HW" model for * the old chipsets (5597/530/6326). For newer chipsets, * we use either VESA or our own mode switching code. */ static Bool SISModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) { vgaHWPtr hwp = VGAHWPTR(pScrn); vgaRegPtr vgaReg; SISPtr pSiS = SISPTR(pScrn); SISRegPtr sisReg; vgaHWUnlock(hwp); SISModifyModeInfo(mode); /* TW: Initialize SiS Port Register definitions for externally used * BIOS emulation (native code switching) functions. */ if( pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA ) { SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30); } if (pSiS->UseVESA) { /* With VESA: */ #ifdef SISDUALHEAD /* TW: No dual head mode when using VESA */ if (pSiS->SecondHead) return TRUE; #endif /* * TW: This order is required: * The video bridge needs to be adjusted before the * BIOS is run as the BIOS sets up CRT2 according to * these register settings. * After the BIOS is run, the bridges and turboqueue * registers need to be readjusted as the BIOS may * very probably have messed them up. */ if( pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA ) { SiSPreSetMode(pScrn, mode); } if(!SiSSetVESAMode(pScrn, mode)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SiSSetVESAMode() failed\n"); return FALSE; } sisSaveUnlockExtRegisterLock(pSiS,NULL,NULL); if( pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA ) { SiSPreSetMode(pScrn, mode); SiSPostSetMode(pScrn, &pSiS->ModeReg); } /* TW: Prepare some register contents and set * up some mode dependent variables. */ #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "REAL REGISTER CONTENTS AFTER SETMODE:\n"); #endif if (!(*pSiS->ModeInit)(pScrn, mode)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ModeInit() failed\n"); return FALSE; } pScrn->vtSema = TRUE; /* Program the registers */ vgaHWProtect(pScrn, TRUE); (*pSiS->SiSRestore)(pScrn, &pSiS->ModeReg); vgaHWProtect(pScrn, FALSE); PDEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "HDisplay: %d, VDisplay: %d \n", mode->HDisplay, mode->VDisplay)); } else { /* Without VESA: */ #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(!(*pSiS->ModeInit)(pScrn, mode)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ModeInit() failed\n"); return FALSE; } pScrn->vtSema = TRUE; if(!(pSiS->SecondHead)) { /* TW: Head 1 (master) is always CRT2 */ SiSPreSetMode(pScrn, mode); if (!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, &pSiS->sishw_ext, pScrn, mode)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SiSBIOSSetModeCRT2() failed\n"); return FALSE; } SiSPostSetMode(pScrn, &pSiS->ModeReg); } else { /* TW: Head 2 (slave) is always CRT1 */ SiSPreSetMode(pScrn, mode); if (!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, &pSiS->sishw_ext, pScrn, mode, pSiS->IsCustom)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SiSBIOSSetModeCRT1() failed\n"); return FALSE; } SiSPostSetMode(pScrn, &pSiS->ModeReg); } } else { #endif if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) { /* TW: Prepare the register contents; On 300/310/325, * we actually "abuse" this only for setting * up some variables; the registers are NOT * being written to the hardware as the BIOS * emulation (native mode switching code) * takes care of this. */ if(!(*pSiS->ModeInit)(pScrn, mode)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ModeInit() failed\n"); return FALSE; } pScrn->vtSema = TRUE; /* 300/310/325 series: Use our own code for mode switching */ SiSPreSetMode(pScrn, mode); if(!SiSBIOSSetMode(pSiS->SiS_Pr, &pSiS->sishw_ext, pScrn, mode, pSiS->IsCustom)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SiSBIOSSetMode() failed\n"); return FALSE; } SiSPostSetMode(pScrn, &pSiS->ModeReg); #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "REAL REGISTER CONTENTS AFTER SETMODE:\n"); (*pSiS->ModeInit)(pScrn, mode); #endif } else { /* For other chipsets, use the old method */ /* Initialise the ModeReg values */ if(!vgaHWInit(pScrn, mode)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "vgaHWInit() failed\n"); return FALSE; } /* Reset our PIOOffset as vgaHWInit might have reset it */ VGAHWPTR(pScrn)->PIOOffset = pSiS->IODBase + (pSiS->PciInfo->ioBase[2] & 0xFFFC) - 0x380; /* Prepare the register contents */ if(!(*pSiS->ModeInit)(pScrn, mode)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ModeInit() failed\n"); return FALSE; } pScrn->vtSema = TRUE; /* Program the registers */ vgaHWProtect(pScrn, TRUE); vgaReg = &hwp->ModeReg; sisReg = &pSiS->ModeReg; vgaReg->Attribute[0x10] = 0x01; if(pScrn->bitsPerPixel > 8) { vgaReg->Graphics[0x05] = 0x00; } vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE); (*pSiS->SiSRestore)(pScrn, sisReg); if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { SiS6326PostSetMode(pScrn, &pSiS->ModeReg); } #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "REAL REGISTER CONTENTS AFTER SETMODE:\n"); (*pSiS->ModeInit)(pScrn, mode); #endif vgaHWProtect(pScrn, FALSE); } #ifdef SISDUALHEAD } #endif } /* TW: Update Currentlayout */ pSiS->CurrentLayout.mode = mode; /* Debug */ /* SiSDumpModeInfo(pScrn, mode); */ return TRUE; } static Bool SiSSetVESAMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) { SISPtr pSiS; int mode; pSiS = SISPTR(pScrn); if (!(mode = SiSCalcVESAModeIndex(pScrn, pMode))) return FALSE; mode |= 1 << 15; /* TW: Don't clear framebuffer */ mode |= 1 << 14; /* TW: Use linear adressing */ if(VBESetVBEMode(pSiS->pVbe, mode, NULL) == FALSE) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Setting VESA mode 0x%x failed\n", mode & 0x0fff); return (FALSE); } if(pMode->HDisplay != pScrn->virtualX) VBESetLogicalScanline(pSiS->pVbe, pScrn->virtualX); xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Setting VESA mode 0x%x succeeded\n", mode & 0x0fff); return (TRUE); } /* * Restore the initial mode. To be used internally only! */ static void SISRestore(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); SISRegPtr sisReg = &pSiS->SavedReg; vgaHWPtr hwp = VGAHWPTR(pScrn); vgaRegPtr vgaReg = &hwp->SavedReg; Bool doit = FALSE, doitlater = FALSE; if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { #ifdef SISDUALHEAD /* TW: We always restore master AND slave */ if(pSiS->DualHeadMode && pSiS->SecondHead) return; #endif /* TW: We must not disable the sequencer if the bridge is in SlaveMode! */ if(!(SiSBridgeIsInSlaveMode(pScrn))) { vgaHWProtect(pScrn, TRUE); } #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL,NULL); #endif /* TW: First, restore CRT1 on/off and VB connection registers */ outSISIDXREG(SISCR, 0x32, pSiS->oldCR32); if(!(pSiS->oldCR17 & 0x80)) { /* TW: CRT1 was off */ if(!(SiSBridgeIsInSlaveMode(pScrn))) { /* TW: Bridge is NOT in SlaveMode now -> do it */ doit = TRUE; } else { doitlater = TRUE; } } else { /* TW: CRT1 was on -> do it now */ doit = TRUE; } if(doit) { outSISIDXREG(SISCR, 0x17, pSiS->oldCR17); } /* TW: For 30xB/LV, restoring the registers does not * work. We "manually" set the old mode, instead. * The same applies for SiS730 machines with LVDS. * Finally, this behavior can be forced by setting * the option RestoreBySetMode. */ if( ( (pSiS->restorebyset) || (pSiS->VBFlags & (VB_301B|VB_302B|VB_30xLV|VB_30xLVX)) || ((pSiS->sishw_ext.jChipType == SIS_730) && (pSiS->VBFlags & VB_LVDS)) ) && (pSiS->OldMode) ) { if(pSiS->AccelInfoPtr) { (*pSiS->AccelInfoPtr->Sync)(pScrn); } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Restoring by setting old mode 0x%02x\n", pSiS->OldMode); if( (pSiS->VBFlags & (VB_301B|VB_302B|VB_30xLV|VB_30xLVX)) && (!pSiS->restorebyset) ) { if(pSiS->OldMode == 0x03) pSiS->OldMode = 0x13; } pSiS->SiS_Pr->UseCustomMode = FALSE; pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE; SiSSetMode(pSiS->SiS_Pr, &pSiS->sishw_ext, pScrn, pSiS->OldMode, FALSE); #ifdef TWDEBUG { SISRegPtr pReg = &pSiS->ModeReg; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "REAL REGISTER CONTENTS AFTER RESTORE BY SETMODE:\n"); (*pSiS->SiSSave)(pScrn, pReg); } #endif } else { if(pSiS->VBFlags & VB_VIDEOBRIDGE) { /* TW: If a video bridge is present, we need to restore * non-extended (=standard VGA) SR and CR registers * before restoring the extended ones and the bridge * registers itself. Unfortunately, the vgaHWRestore * routine clears CR17[7] - which must not be done if * the bridge is in slave mode. */ if(!(SiSBridgeIsInSlaveMode(pScrn))) { vgaHWProtect(pScrn, TRUE); if(pSiS->Primary) { vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE); } } } (*pSiS->SiSRestore)(pScrn, sisReg); } if(doitlater) { outSISIDXREG(SISCR, 0x17, pSiS->oldCR17); } sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[0x05],sisReg->sisRegs3D4[0x80]); if( ( (pSiS->sishw_ext.jChipType == SIS_730) && (pSiS->VBFlags & VB_LVDS)) || (pSiS->restorebyset) ) { /* TW: SiS730/LVDS has extreme problems restoring the text display due * to over-sensible LCD panels */ vgaHWProtect(pScrn, TRUE); if(pSiS->Primary) { vgaHWRestore(pScrn, vgaReg, (VGA_SR_FONTS | VGA_SR_CMAP)); } vgaHWProtect(pScrn, FALSE); } else { vgaHWProtect(pScrn, TRUE); if(pSiS->Primary) { vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL); } vgaHWProtect(pScrn, FALSE); } } else { /* All other chipsets */ vgaHWProtect(pScrn, TRUE); #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL,NULL); #endif (*pSiS->SiSRestore)(pScrn, sisReg); vgaHWProtect(pScrn, TRUE); if(pSiS->Primary) { vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL); } /* TW: Restore TV. This is rather complicated, but if we don't do it, * TV output will flicker terribly */ if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { if(sisReg->sis6326tv[0] & 0x04) { unsigned char tmp; int val; orSISIDXREG(SISSR, 0x01, 0x20); tmp = SiS6326GetTVReg(pScrn,0x00); tmp &= ~0x04; while(!(inSISREG(SISINPSTAT) & 0x08)); /* Wait while NOT vb */ SiS6326SetTVReg(pScrn,0x00,tmp); for(val=0; val < 2; val++) { while(!(inSISREG(SISINPSTAT) & 0x08)); /* Wait while NOT vb */ while(inSISREG(SISINPSTAT) & 0x08); /* wait while vb */ } SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]); tmp = inSISREG(SISINPSTAT); outSISREG(SISAR, 0x20); tmp = inSISREG(SISINPSTAT); while(inSISREG(SISINPSTAT) & 0x01); while(!(inSISREG(SISINPSTAT) & 0x01)); andSISIDXREG(SISSR, 0x01, ~0x20); for(val=0; val < 10; val++) { while(!(inSISREG(SISINPSTAT) & 0x08)); /* Wait while NOT vb */ while(inSISREG(SISINPSTAT) & 0x08); /* wait while vb */ } andSISIDXREG(SISSR, 0x01, ~0x20); } } sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[5],sisReg->sisRegs3D4[0x80]); vgaHWProtect(pScrn, FALSE); } } static void SISVESARestore(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); if(pSiS->UseVESA) SISVESASaveRestore(pScrn, MODE_RESTORE); } /* TW: Restore bridge registers - to be called BEFORE VESARestore */ static void SISBridgeRestore(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD /* We only restore for master head */ if(pSiS->DualHeadMode && pSiS->SecondHead) return; #endif if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) { SiSRestoreBridge(pScrn, &pSiS->SavedReg); } } /* TW: Our generic BlockHandler for Xv */ static void SISBlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask) { ScreenPtr pScreen = screenInfo.screens[i]; ScrnInfoPtr pScrn = xf86Screens[i]; SISPtr pSiS = SISPTR(pScrn); pScreen->BlockHandler = pSiS->BlockHandler; (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); pScreen->BlockHandler = SISBlockHandler; if(pSiS->VideoTimerCallback) { (*pSiS->VideoTimerCallback)(pScrn, currentTime.milliseconds); } } /* Mandatory * This gets called at the start of each server generation * * TW: We use pScrn and not CurrentLayout here, because the * properties we use have not changed (displayWidth, * depth, bitsPerPixel) */ static Bool SISScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { ScrnInfoPtr pScrn; vgaHWPtr hwp; SISPtr pSiS; int ret; int init_picture = 0; VisualPtr visual; unsigned long OnScreenSize; int height, width, displayWidth; unsigned char *FBStart; #ifdef SISDUALHEAD SISEntPtr pSiSEnt = NULL; #endif pScrn = xf86Screens[pScreen->myNum]; hwp = VGAHWPTR(pScrn); pSiS = SISPTR(pScrn); if(pSiS->UseVESA) { #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) pSiS->pVbe = VBEInit(NULL, pSiS->pEnt->index); #else pSiS->pVbe = VBEExtendedInit(NULL, pSiS->pEnt->index, SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); #endif } #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { pSiSEnt = pSiS->entityPrivate; pSiSEnt->refCount++; } #endif /* Map the VGA memory and get the VGA IO base */ if(pSiS->Primary) { hwp->MapSize = 0x10000; /* Standard 64k VGA window */ if(!vgaHWMapMem(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not map VGA window\n"); return FALSE; } } vgaHWGetIOBase(hwp); /* TW: Patch the PIOOffset inside vgaHW to use * our relocated IO ports. */ VGAHWPTR(pScrn)->PIOOffset = pSiS->IODBase + (pSiS->PciInfo->ioBase[2] & 0xFFFC) - 0x380; /* Map the SIS memory and MMIO areas */ if(!SISMapMem(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SiSMapMem() failed\n"); return FALSE; } #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif /* TW: Enable TurboQueue so that SISSave() saves it in enabled * state. If we don't do this, X will hang after a restart! * (Happens for some unknown reason only when using VESA * for mode switching; assumingly a BIOS issue.) * This is done on 300 and 310/325 series only. */ if(pSiS->UseVESA) { SiSEnableTurboQueue(pScrn); } /* Save the current state */ SISSave(pScrn); /* TW: Save the current mode number */ if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) { inSISIDXREG(SISCR, 0x34, pSiS->OldMode); } /* Initialise the first mode */ if(!SISModeInit(pScrn, pScrn->currentMode)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SiSModeInit() failed\n"); return FALSE; } /* Darken the screen for aesthetic reasons */ /* TW: Not using Dual Head variant on purpose; we darken * the screen for both displays, and un-darken * it when the second head is finished */ SISSaveScreen(pScreen, SCREEN_SAVER_ON); /* Set the viewport */ SISAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); /* Clear frame buffer */ OnScreenSize = pScrn->displayWidth * pScrn->currentMode->VDisplay * (pScrn->bitsPerPixel / 8); bzero(pSiS->FbBase, OnScreenSize); /* * The next step is to setup the screen's visuals, and initialise the * framebuffer code. In cases where the framebuffer's default * choices for things like visual layouts and bits per RGB are OK, * this may be as simple as calling the framebuffer's ScreenInit() * function. If not, the visuals will need to be setup before calling * a fb ScreenInit() function and fixed up after. * * For most PC hardware at depths >= 8, the defaults that cfb uses * are not appropriate. In this driver, we fixup the visuals after. */ /* * Reset visual list. */ miClearVisualTypes(); /* Setup the visuals we support. */ /* * For bpp > 8, the default visuals are not acceptable because we only * support TrueColor and not DirectColor. */ if(pScrn->bitsPerPixel > 8) { if(!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits, pScrn->defaultVisual)) { SISSaveScreen(pScreen, SCREEN_SAVER_OFF); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "miSetVisualTypes() failed (bpp %d)\n", pScrn->bitsPerPixel); return FALSE; } } else { if(!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) { SISSaveScreen(pScreen, SCREEN_SAVER_OFF); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "miSetVisualTypes() failed (bpp %d)\n", pScrn->bitsPerPixel); return FALSE; } } width = pScrn->virtualX; height = pScrn->virtualY; displayWidth = pScrn->displayWidth; if(pSiS->Rotate) { height = pScrn->virtualX; width = pScrn->virtualY; } if(pSiS->ShadowFB) { pSiS->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width); pSiS->ShadowPtr = xalloc(pSiS->ShadowPitch * height); displayWidth = pSiS->ShadowPitch / (pScrn->bitsPerPixel >> 3); FBStart = pSiS->ShadowPtr; } else { pSiS->ShadowPtr = NULL; FBStart = pSiS->FbBase; } if(!miSetPixmapDepths()) { SISSaveScreen(pScreen, SCREEN_SAVER_OFF); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "miSetPixmapDepths() failed\n"); return FALSE; } #ifdef SISDUALHEAD if(pSiS->SecondHead) pSiS->cmdQueueLenPtr = &(SISPTR(pSiSEnt->pScrn_1)->cmdQueueLen); else #endif pSiS->cmdQueueLenPtr = &(pSiS->cmdQueueLen); pSiS->cmdQueueLen = 0; /* TW: Force an EngineIdle() at start */ #ifdef XF86DRI #ifdef SISDUALHEAD /* TW: No DRI in dual head mode */ if(pSiS->DualHeadMode) { pSiS->directRenderingEnabled = FALSE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DRI not supported in Dual Head mode\n"); } else #endif /* Force the initialization of the context */ if(pSiS->VGAEngine != SIS_315_VGA) { pSiS->directRenderingEnabled = SISDRIScreenInit(pScreen); } else { xf86DrvMsg(pScrn->scrnIndex, X_NOT_IMPLEMENTED, "DRI not supported on this chipset\n"); pSiS->directRenderingEnabled = FALSE; } #endif /* * Call the framebuffer layer's ScreenInit function, and fill in other * pScreen fields. */ switch(pScrn->bitsPerPixel) { case 1: ret = xf1bppScreenInit(pScreen, FBStart, width, height, pScrn->xDpi, pScrn->yDpi, displayWidth); break; case 4: ret = xf4bppScreenInit(pScreen, FBStart, width, height, pScrn->xDpi, pScrn->yDpi, displayWidth); break; case 8: case 16: case 24: case 32: ret = fbScreenInit(pScreen, FBStart, width, height, pScrn->xDpi, pScrn->yDpi, displayWidth, pScrn->bitsPerPixel); init_picture = 1; break; default: xf86DrvMsg(scrnIndex, X_ERROR, "Internal error: invalid bpp (%d) in SISScrnInit\n", pScrn->bitsPerPixel); ret = FALSE; break; } if (!ret) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf1bpp/xf4bpp/fbScreenInit() failed\n"); SISSaveScreen(pScreen, SCREEN_SAVER_OFF); return FALSE; } if(pScrn->bitsPerPixel > 8) { /* Fixup RGB ordering */ visual = pScreen->visuals + pScreen->numVisuals; while (--visual >= pScreen->visuals) { if ((visual->class | DynamicClass) == DirectColor) { visual->offsetRed = pScrn->offset.red; visual->offsetGreen = pScrn->offset.green; visual->offsetBlue = pScrn->offset.blue; visual->redMask = pScrn->mask.red; visual->greenMask = pScrn->mask.green; visual->blueMask = pScrn->mask.blue; } } } else if(pScrn->depth == 1) { SIS1bppColorMap(pScrn); } /* Initialize RENDER ext; must be after RGB ordering fixed */ if(init_picture) fbPictureInit(pScreen, 0, 0); /* hardware cursor needs to wrap this layer <-- TW: what does that mean? */ if(!pSiS->ShadowFB) SISDGAInit(pScreen); xf86SetBlackWhitePixels(pScreen); if(!pSiS->NoAccel) { switch(pSiS->VGAEngine) { case SIS_530_VGA: case SIS_300_VGA: SiS300AccelInit(pScreen); break; case SIS_315_VGA: SiS310AccelInit(pScreen); break; default: SiSAccelInit(pScreen); } } miInitializeBackingStore(pScreen); xf86SetBackingStore(pScreen); xf86SetSilkenMouse(pScreen); /* Initialise cursor functions */ miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); if(pSiS->HWCursor) SiSHWCursorInit(pScreen); /* Initialise default colourmap */ if(!miCreateDefColormap(pScreen)) { SISSaveScreen(pScreen, SCREEN_SAVER_OFF); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "miCreateDefColormap() failed\n"); return FALSE; } if(!xf86HandleColormaps(pScreen, 256, (pScrn->depth == 8) ? 8 : pScrn->rgbBits, SISLoadPalette, NULL, CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) { SISSaveScreen(pScreen, SCREEN_SAVER_OFF); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86HandleColormaps() failed\n"); return FALSE; } if(pSiS->ShadowFB) { RefreshAreaFuncPtr refreshArea = SISRefreshArea; if(pSiS->Rotate) { if(!pSiS->PointerMoved) { pSiS->PointerMoved = pScrn->PointerMoved; pScrn->PointerMoved = SISPointerMoved; } switch(pScrn->bitsPerPixel) { case 8: refreshArea = SISRefreshArea8; break; case 16: refreshArea = SISRefreshArea16; break; case 24: refreshArea = SISRefreshArea24; break; case 32: refreshArea = SISRefreshArea32; break; } } ShadowFBInit(pScreen, refreshArea); } #ifdef SISDUALHEAD if(pSiS->DualHeadMode) /* TW: DPMS for dual head mode */ xf86DPMSInit(pScreen, (DPMSSetProcPtr)SISDisplayPowerManagementSetDH, 0); else #endif xf86DPMSInit(pScreen, (DPMSSetProcPtr)SISDisplayPowerManagementSet, 0); /* Init memPhysBase and fbOffset in pScrn */ pScrn->memPhysBase = pSiS->FbAddress; pScrn->fbOffset = 0; #ifdef XvExtension if(!pSiS->NoXvideo) { #ifdef SISDUALHEAD /* TW: On chipsets with only one overlay, we support * Xv only in "real" dual head mode, not Xinerama */ if ( ((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA) ) && ((pSiS->hasTwoOverlays) || (!pSiS->DualHeadMode) || (noPanoramiXExtension) ) ) { #else if ( (pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA) ) { #endif #ifdef SISDUALHEAD if (pSiS->DualHeadMode) { if ( pSiS->hasTwoOverlays || (pSiS->XvOnCRT2 && (!pSiS->SecondHead)) || ((!pSiS->XvOnCRT2 && pSiS->SecondHead)) ) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using SiS300/310/325 series HW Xv on CRT%d\n", (pSiS->SecondHead ? 1 : 2)); SISInitVideo(pScreen); } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using SiS300/310/325 series HW Xv on CRT%d\n", (pSiS->SecondHead ? 1 : 2)); } } else { #endif if (pSiS->hasTwoOverlays) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using SiS300/310/325 series HW Xv\n" ); else xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using SiS300/310/325 series HW Xv on CRT%d\n", (pSiS->XvOnCRT2 ? 2 : 1)); SISInitVideo(pScreen); #ifdef SISDUALHEAD } #endif #ifdef USE6326VIDEO } else if( pSiS->Chipset == PCI_CHIP_SIS6326 || pSiS->Chipset == PCI_CHIP_SIS530 || pSiS->Chipset == PCI_CHIP_SIS5597 ) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using SiS5597/5598/6326/530/620 HW Xv\n" ); SIS6326InitVideo(pScreen); #endif } else { /* generic Xv */ XF86VideoAdaptorPtr *ptr; int n; n = xf86XVListGenericAdaptors(pScrn, &ptr); if (n) { xf86XVScreenInit(pScreen, ptr, n); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using generic Xv\n" ); } if (!noPanoramiXExtension) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "HW Xv not supported in Xinerama mode\n"); } } #endif #ifdef XF86DRI if(pSiS->directRenderingEnabled) { /* Now that mi, drm and others have done their thing, * complete the DRI setup. */ pSiS->directRenderingEnabled = SISDRIFinishScreenInit(pScreen); } if(pSiS->directRenderingEnabled) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n"); /* TODO */ /* SISSetLFBConfig(pSiS); */ } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering disabled\n"); } #endif pSiS->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = SISCloseScreen; #ifdef SISDUALHEAD if(pSiS->DualHeadMode) pScreen->SaveScreen = SISSaveScreenDH; else #endif pScreen->SaveScreen = SISSaveScreen; /* Install BlockHandler */ pSiS->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = SISBlockHandler; /* Report any unused options (only for the first generation) */ if(serverGeneration == 1) { xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); } /* Turn on the screen now */ /* TW: We do this in dual head mode after second head is finished */ #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(pSiS->SecondHead) SISSaveScreen(pScreen, SCREEN_SAVER_OFF); } else #endif SISSaveScreen(pScreen, SCREEN_SAVER_OFF); return TRUE; } /* Usually mandatory */ Bool SISSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; SISPtr pSiS = SISPTR(pScrn); if(!pSiS->NoAccel) { if(pSiS->AccelInfoPtr) { (*pSiS->AccelInfoPtr->Sync)(pScrn); } } return SISModeInit(xf86Screens[scrnIndex], mode); } #ifdef CYCLECRT2 /* TW: Cycle CRT2 output devices */ Bool SISCycleCRT2Type(int scrnIndex, DisplayModePtr mode) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; SISPtr pSiS = SISPTR(pScrn); int i = 0; /* TW: Only on 300 and 310/325 series */ if(pSiS->VGAEngine != SIS_300_VGA && pSiS->VGAEngine != SIS_315_VGA) return FALSE; /* TW: Only if there is a video bridge */ if(pSiS->VBFlags & VB_VIDEOBRIDGE) return FALSE; /* TW: Only if there were more than 1 CRT2 devices detected */ if(pSiS->detectedCRT2Devices & CRT2_VGA) i++; if(pSiS->detectedCRT2Devices & CRT2_LCD) i++; if(pSiS->detectedCRT2Devices & CRT2_TV) i++; if(i <= 1) return FALSE; /* TW: Cycle CRT2 type */ i = (pSiS->VBFlags & DISPTYPE_DISP2) << 1; while(!(i & pSiS->detectedCRT2Devices)) { i <<= 1; if(i > CRT2_VGA) i = CRT2_LCD; } /* TW: Check if mode is suitable for desired output device */ if(!SiS_CheckCalcModeIndex(pScrn, pScrn->currentMode, ((pSiS->VBFlags & ~(DISPTYPE_DISP2)) | i))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Current mode not suitable for desired CRT2 output device\n"); return FALSE; } /* TW: Sync the accelerators */ if(!pSiS->NoAccel) { if(pSiS->AccelInfoPtr) { (*pSiS->AccelInfoPtr->Sync)(pScrn); } } pSiS->VBFlags &= ~(DISPTYPE_DISP2); pSiS->VBFlags |= i; return SISModeInit(xf86Screens[scrnIndex], mode); } #endif /* * This function is used to initialize the Start Address - the first * displayed location in the video memory. */ /* Usually mandatory */ void SISAdjustFrame(int scrnIndex, int x, int y, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; SISPtr pSiS; vgaHWPtr hwp; int base; unsigned char temp; hwp = VGAHWPTR(pScrn); pSiS = SISPTR(pScrn); base = y * pSiS->CurrentLayout.displayWidth + x; if(pSiS->UseVESA) { /* TW: Let BIOS adjust frame if using VESA */ VBESetDisplayStart(pSiS->pVbe, x, y, TRUE); } else { #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif if(pScrn->bitsPerPixel < 8) { base = (y * pSiS->CurrentLayout.displayWidth + x + 3) >> 3; } else { base = y * pSiS->CurrentLayout.displayWidth + x; /* calculate base bpp dep. */ switch(pSiS->CurrentLayout.bitsPerPixel) { case 16: base >>= 1; break; case 24: base = ((base * 3)) >> 2; base -= base % 6; break; case 32: break; default: /* 8bpp */ base >>= 2; break; } } #ifdef SISDUALHEAD if (pSiS->DualHeadMode) { /* TW: We assume that DualHeadMode only can be true for * dual head capable chipsets (and thus save the check * for chipset here) */ if (!pSiS->SecondHead) { /* TW: Head 1 (master) is always CRT2 */ SiS_UnLockCRT2(pSiS->SiS_Pr, &pSiS->sishw_ext, pSiS->RelIO+0x30); outSISIDXREG(SISPART1, 0x06, GETVAR8(base)); outSISIDXREG(SISPART1, 0x05, GETBITS(base, 15:8)); outSISIDXREG(SISPART1, 0x04, GETBITS(base, 23:16)); if (pSiS->VGAEngine == SIS_315_VGA) { setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7); } SiS_LockCRT2(pSiS->SiS_Pr, &pSiS->sishw_ext, pSiS->RelIO+0x30); } else { /* TW: Head 2 (slave) is always CRT1 */ base += (pSiS->dhmOffset/4); outSISIDXREG(SISCR, 0x0D, base & 0xFF); outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF); outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF); if (pSiS->VGAEngine == SIS_315_VGA) { setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01); } } } else { #endif switch (pSiS->VGAEngine) { case SIS_300_VGA: outSISIDXREG(SISCR, 0x0D, base & 0xFF); outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF); outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF); if (pSiS->VBFlags & CRT2_ENABLE) { SiS_UnLockCRT2(pSiS->SiS_Pr, &pSiS->sishw_ext, pSiS->RelIO+0x30); outSISIDXREG(SISPART1, 0x06, GETVAR8(base)); outSISIDXREG(SISPART1, 0x05, GETBITS(base, 15:8)); outSISIDXREG(SISPART1, 0x04, GETBITS(base, 23:16)); SiS_LockCRT2(pSiS->SiS_Pr, &pSiS->sishw_ext, pSiS->RelIO+0x30); } break; case SIS_315_VGA: outSISIDXREG(SISCR, 0x0D, base & 0xFF); outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF); outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF); setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01); if (pSiS->VBFlags & CRT2_ENABLE) { SiS_UnLockCRT2(pSiS->SiS_Pr, &pSiS->sishw_ext, pSiS->RelIO+0x30); outSISIDXREG(SISPART1, 0x06, GETVAR8(base)); outSISIDXREG(SISPART1, 0x05, GETBITS(base, 15:8)); outSISIDXREG(SISPART1, 0x04, GETBITS(base, 23:16)); setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7); SiS_LockCRT2(pSiS->SiS_Pr, &pSiS->sishw_ext, pSiS->RelIO+0x30); } break; default: outSISIDXREG(SISCR, 0x0D, base & 0xFF); outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF); inSISIDXREG(SISSR, 0x27, temp); temp &= 0xF0; temp |= (base & 0x0F0000) >> 16; outSISIDXREG(SISSR, 0x27, temp); } #ifdef SISDUALHEAD } #endif } /* if not VESA */ } /* * This is called when VT switching back to the X server. Its job is * to reinitialise the video mode. * Mandatory! */ static Bool SISEnterVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; SISPtr pSiS = SISPTR(pScrn); sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); if(!SISModeInit(pScrn, pScrn->currentMode)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SiSEnterVT: SISModeInit() failed\n"); return FALSE; } SISAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); #ifdef XF86DRI /* TW: this is to be done AFTER switching the mode */ if(pSiS->directRenderingEnabled) DRIUnlock(screenInfo.screens[scrnIndex]); #endif return TRUE; } /* * This is called when VT switching away from the X server. Its job is * to restore the previous (text) mode. * Mandatory! */ static void SISLeaveVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; vgaHWPtr hwp = VGAHWPTR(pScrn); SISPtr pSiS = SISPTR(pScrn); #ifdef XF86DRI ScreenPtr pScreen; /* TW: to be done before mode change */ if(pSiS->directRenderingEnabled) { pScreen = screenInfo.screens[scrnIndex]; DRILock(pScreen, 0); } #endif #ifdef SISDUALHEAD if(pSiS->DualHeadMode && pSiS->SecondHead) return; #endif if(pSiS->CursorInfoPtr) { #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(!pSiS->SecondHead) { pSiS->ForceCursorOff = TRUE; pSiS->CursorInfoPtr->HideCursor(pScrn); SISWaitVBRetrace(pScrn); pSiS->ForceCursorOff = FALSE; } } else { #endif pSiS->CursorInfoPtr->HideCursor(pScrn); SISWaitVBRetrace(pScrn); #ifdef SISDUALHEAD } #endif } SISBridgeRestore(pScrn); if(pSiS->UseVESA) { /* TW: This is a q&d work-around for a BIOS bug. In case we disabled CRT2, * VBESaveRestore() does not restore CRT1. So we set any mode now, * because VBESetVBEMode correctly restores CRT1. Afterwards, we * can call VBESaveRestore to restore original mode. */ if ( (pSiS->VBFlags & VB_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)) ) VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL); SISVESARestore(pScrn); } else { SISRestore(pScrn); } vgaHWLock(hwp); } /* * This is called at the end of each server generation. It restores the * original (text) mode. It should really also unmap the video memory too. * Mandatory! */ static Bool SISCloseScreen(int scrnIndex, ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; vgaHWPtr hwp = VGAHWPTR(pScrn); SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif #ifdef XF86DRI if(pSiS->directRenderingEnabled) { SISDRICloseScreen(pScreen); pSiS->directRenderingEnabled = FALSE; } #endif if(pScrn->vtSema) { if(pSiS->CursorInfoPtr) { #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(!pSiS->SecondHead) { pSiS->ForceCursorOff = TRUE; pSiS->CursorInfoPtr->HideCursor(pScrn); SISWaitVBRetrace(pScrn); pSiS->ForceCursorOff = FALSE; } } else { #endif pSiS->CursorInfoPtr->HideCursor(pScrn); SISWaitVBRetrace(pScrn); #ifdef SISDUALHEAD } #endif } SISBridgeRestore(pScrn); if(pSiS->UseVESA) { /* TW: This is a q&d work-around for a BIOS bug. In case we disabled CRT2, * VBESaveRestore() does not restore CRT1. So we set any mode now, * because VBESetVBEMode correctly restores CRT1. Afterwards, we * can call VBESaveRestore to restore original mode. */ if( (pSiS->VBFlags & VB_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2))) VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL); SISVESARestore(pScrn); } else { SISRestore(pScrn); } vgaHWLock(hwp); } SISUnmapMem(pScrn); vgaHWUnmapMem(pScrn); #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { pSiSEnt = pSiS->entityPrivate; pSiSEnt->refCount--; } #endif if(pSiS->pInt) { xf86FreeInt10(pSiS->pInt); pSiS->pInt = NULL; } if(pSiS->AccelInfoPtr) { XAADestroyInfoRec(pSiS->AccelInfoPtr); pSiS->AccelInfoPtr = NULL; } if(pSiS->CursorInfoPtr) { xf86DestroyCursorInfoRec(pSiS->CursorInfoPtr); pSiS->CursorInfoPtr = NULL; } if(pSiS->ShadowPtr) { xfree(pSiS->ShadowPtr); pSiS->ShadowPtr = NULL; } if(pSiS->DGAModes) { xfree(pSiS->DGAModes); pSiS->DGAModes = NULL; } if(pSiS->adaptor) { xfree(pSiS->adaptor); pSiS->adaptor = NULL; } pScrn->vtSema = FALSE; /* Restore Blockhandler */ pScreen->BlockHandler = pSiS->BlockHandler; pScreen->CloseScreen = pSiS->CloseScreen; return (*pScreen->CloseScreen)(scrnIndex, pScreen); } /* Free up any per-generation data structures */ /* Optional */ static void SISFreeScreen(int scrnIndex, int flags) { if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) vgaHWFreeHWRec(xf86Screens[scrnIndex]); SISFreeRec(xf86Screens[scrnIndex]); } /* Checks if a mode is suitable for the selected chipset. */ /* Optional */ static int SISValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; SISPtr pSiS = SISPTR(pScrn); if(pSiS->UseVESA) { if(SiSCalcVESAModeIndex(pScrn, mode)) return(MODE_OK); else return(MODE_BAD); } if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) { #ifdef SISDUALHEAD if((pSiS->DualHeadMode) && (pSiS->SecondHead)) { /* DHM: Only check modes for CRT1 */ if(SiS_CalcModeIndex(pScrn, mode) < 0x14) return(MODE_BAD); } else #endif if(SiS_CheckCalcModeIndex(pScrn, mode, pSiS->VBFlags) < 0x14) return(MODE_BAD); } return(MODE_OK); } /* Do screen blanking */ /* Mandatory */ static Bool SISSaveScreen(ScreenPtr pScreen, int mode) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; if ((pScrn != NULL) && pScrn->vtSema) { SISPtr pSiS = SISPTR(pScrn); /* enable access to extended sequencer registers */ #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif if(pSiS->VGAEngine == SIS_300_VGA) { if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { if(!xf86IsUnblank(mode)) { pSiS->Blank = TRUE; SiS_SiS30xBLOff(pSiS->SiS_Pr,&pSiS->sishw_ext); } else { pSiS->Blank = FALSE; SiS_SiS30xBLOn(pSiS->SiS_Pr,&pSiS->sishw_ext); } } else { /* if not blanked obtain state of LCD blank flags set by BIOS */ if(!pSiS->Blank) { inSISIDXREG(SISSR, 0x11, pSiS->LCDon); } if(!xf86IsUnblank(mode)) { pSiS->Blank = TRUE; outSISIDXREG(SISSR, 0x11, pSiS->LCDon | 0x08); } else { pSiS->Blank = FALSE; /* don't just unblanking; use LCD state set by BIOS */ outSISIDXREG(SISSR, 0x11, pSiS->LCDon); } } } else if(pSiS->VGAEngine == SIS_315_VGA) { if(!pSiS->Blank) { inSISIDXREG(SISSR, 0x11, pSiS->LCDon); } if(pSiS->VBFlags & VB_CHRONTEL) { if(!xf86IsUnblank(mode)) { pSiS->Blank = TRUE; SiS_Chrontel701xBLOff(pSiS->SiS_Pr); } else { pSiS->Blank = FALSE; SiS_Chrontel701xBLOn(pSiS->SiS_Pr); } } else if(pSiS->VBFlags & VB_LVDS) { if(!xf86IsUnblank(mode)) { pSiS->Blank = TRUE; outSISIDXREG(SISSR, 0x11, pSiS->LCDon | 0x08); } else { pSiS->Blank = FALSE; outSISIDXREG(SISSR, 0x11, pSiS->LCDon); } } else if(pSiS->VBFlags & (VB_301B|VB_302B|VB_30xLV|VB_30xLVX)) { if(!xf86IsUnblank(mode)) { pSiS->Blank = TRUE; SiS_SiS30xBLOff(pSiS->SiS_Pr,&pSiS->sishw_ext); } else { pSiS->Blank = FALSE; SiS_SiS30xBLOn(pSiS->SiS_Pr,&pSiS->sishw_ext); } } } } return vgaHWSaveScreen(pScreen, mode); } #ifdef SISDUALHEAD /* TW: SaveScreen for dual head mode */ static Bool SISSaveScreenDH(ScreenPtr pScreen, int mode) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; if ((pScrn != NULL) && pScrn->vtSema) { SISPtr pSiS = SISPTR(pScrn); if (pSiS->SecondHead) { /* Slave head is always CRT1 */ return vgaHWSaveScreen(pScreen, mode); } else { /* Master head is always CRT2 */ /* We can only blank LCD, not other CRT2 devices */ if(!(pSiS->VBFlags & CRT2_LCD)) return TRUE; /* enable access to extended sequencer registers */ #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif if(pSiS->VGAEngine == SIS_300_VGA) { if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) { if(!xf86IsUnblank(mode)) { pSiS->BlankCRT2 = TRUE; SiS_SiS30xBLOff(pSiS->SiS_Pr,&pSiS->sishw_ext); } else { pSiS->BlankCRT2 = FALSE; SiS_SiS30xBLOn(pSiS->SiS_Pr,&pSiS->sishw_ext); } } else { /* if not blanked obtain state of LCD blank flags set by BIOS */ if(!pSiS->BlankCRT2) { inSISIDXREG(SISSR, 0x11, pSiS->LCDon); } if (!xf86IsUnblank(mode)) { pSiS->BlankCRT2 = TRUE; outSISIDXREG(SISSR, 0x11, pSiS->LCDon | 0x08); } else { pSiS->BlankCRT2 = FALSE; /* don't just unblank; use LCD state set by BIOS */ outSISIDXREG(SISSR, 0x11, pSiS->LCDon); } } } else if(pSiS->VGAEngine == SIS_315_VGA) { if(!pSiS->BlankCRT2) { inSISIDXREG(SISSR, 0x11, pSiS->LCDon); } if(pSiS->VBFlags & VB_CHRONTEL) { if(!xf86IsUnblank(mode)) { pSiS->BlankCRT2 = TRUE; SiS_Chrontel701xBLOff(pSiS->SiS_Pr); } else { pSiS->BlankCRT2 = FALSE; SiS_Chrontel701xBLOn(pSiS->SiS_Pr); } } else if(pSiS->VBFlags & VB_LVDS) { if(!xf86IsUnblank(mode)) { pSiS->BlankCRT2 = TRUE; outSISIDXREG(SISSR, 0x11, pSiS->LCDon | 0x08); } else { pSiS->BlankCRT2 = FALSE; outSISIDXREG(SISSR, 0x11, pSiS->LCDon); } } else if(pSiS->VBFlags & (VB_301B|VB_302B|VB_30xLV|VB_30xLVX)) { if(!xf86IsUnblank(mode)) { pSiS->BlankCRT2 = TRUE; SiS_SiS30xBLOff(pSiS->SiS_Pr,&pSiS->sishw_ext); } else { pSiS->BlankCRT2 = FALSE; SiS_SiS30xBLOn(pSiS->SiS_Pr,&pSiS->sishw_ext); } } } } } return TRUE; } #endif #ifdef DEBUG /* locally used for debug */ static void SiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode) { xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal); xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted); } #endif /* local used for debug */ static void SISModifyModeInfo(DisplayModePtr mode) { #if 1 if(mode->CrtcHBlankStart == mode->CrtcHDisplay) mode->CrtcHBlankStart++; if(mode->CrtcHBlankEnd == mode->CrtcHTotal) mode->CrtcHBlankEnd--; if(mode->CrtcVBlankStart == mode->CrtcVDisplay) mode->CrtcVBlankStart++; if(mode->CrtcVBlankEnd == mode->CrtcVTotal) mode->CrtcVBlankEnd--; #endif } /* TW: Enable the TurboQueue (For 300 and 310/325 series only) */ void SiSEnableTurboQueue(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); unsigned short SR26, SR27; unsigned long temp; switch (pSiS->VGAEngine) { case SIS_300_VGA: if ((!pSiS->NoAccel) && (pSiS->TurboQueue)) { /* TQ size is always 512k */ temp = (pScrn->videoRam/64) - 8; SR26 = temp & 0xFF; inSISIDXREG(SISSR, 0x27, SR27); SR27 &= 0xFC; SR27 |= (0xF0 | ((temp >> 8) & 3)); outSISIDXREG(SISSR, 0x26, SR26); outSISIDXREG(SISSR, 0x27, SR27); } break; case SIS_315_VGA: if (!pSiS->NoAccel) { /* TW: On 310/325 series, there are three queue modes available * which are chosen by setting bits 7:5 in SR26: * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep * track of the queue, the FIFO, command parsing and so * on. This is the one comparable to the 300 series. * 2. VRAM queue mode (bit 6, 0x40). In this case, one will * have to do queue management himself. Register 0x85c4 will * hold the location of the next free queue slot, 0x85c8 * is the "queue read pointer" whose way of working is * unknown to me. Anyway, this mode would require a * translation of the MMIO commands to some kind of * accelerator assembly and writing these commands * to the memory location pointed to by 0x85c4. * We will not use this, as nobody knows how this * "assembly" works, and as it would require a complete * re-write of the accelerator code. * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the * queue in AGP memory space. * We go MMIO here. * SR26 bit 4 is called "Bypass H/W queue". * SR26 bit 1 is called "Enable Command Queue Auto Correction" * SR26 bit 0 resets the queue * Size of queue memory is encoded in bits 3:2 like this: * 00 (0x00) 512K * 01 (0x04) 1M * 10 (0x08) 2M * 11 (0x0C) 4M * The queue location is to be written to 0x85C0. */ #if 0 if (pSiS->TurboQueue) { #endif /* TW: We only use MMIO Cmd Queue, not VRAM or AGP */ /* TW: Set Command Queue Threshold to max value 11111b */ outSISIDXREG(SISSR, 0x27, 0x1F); /* TW: Syncronous reset for Command Queue */ outSISIDXREG(SISSR, 0x26, 0x01); /* TW: Do some magic (cp readport to writeport) */ temp = MMIO_IN32(pSiS->IOBase, 0x85C8); MMIO_OUT32(pSiS->IOBase, 0x85C4, temp); /* TW: Enable MMIO Command Queue mode (0x20), * Enable_command_queue_auto_correction (0x02) * (no idea, but sounds good, so use it) * 512k (0x00) (does this apply to MMIO mode?) */ outSISIDXREG(SISSR, 0x26, 0x22); /* TW: Calc Command Queue position (Q is always 512k)*/ temp = (pScrn->videoRam - 512) * 1024; /* TW: Set Q position */ MMIO_OUT32(pSiS->IOBase, 0x85C0, temp); #if 0 } else { /* TW: Is there a non-TurboQueue mode within MMIO mode? */ } #endif } break; default: break; } } /* TW: Things to do before a ModeSwitch. We set up the * video bridge configuration and the TurboQueue. */ void SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode) { SISPtr pSiS = SISPTR(pScrn); unsigned char usScratchCR30, usScratchCR31; unsigned char usScratchCR32, usScratchCR33; unsigned char usScratchCR17, usScratchCR38 = 0; int vbflag, temp = 0; int crt1rateindex = 0; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); /* Unlock Registers */ #endif vbflag = pSiS->VBFlags; pSiS->IsCustom = FALSE; if(pSiS->HaveCustomModes) { if(!(mode->type & M_T_DEFAULT)) { pSiS->IsCustom = TRUE; } } /* TW: The CR3x registers are for communicating with our BIOS emulation * code (native code in init.c/init301.c) or the BIOS (via VESA) */ inSISIDXREG(SISCR, 0x30, usScratchCR30); /* Bridge config */ inSISIDXREG(SISCR, 0x31, usScratchCR31); /* Bridge config */ usScratchCR32 = pSiS->newCR32; /* Bridge connection info (use our new value) */ inSISIDXREG(SISCR, 0x33, usScratchCR33); /* CRT1 refresh rate index */ if(pSiS->Chipset != PCI_CHIP_SIS300) { switch(pSiS->VGAEngine) { case SIS_300_VGA: temp = 0x35; break; case SIS_315_VGA: temp = 0x38; break; } } if(temp) inSISIDXREG(SISCR, temp, usScratchCR38); /* PAL-M, PAL-N selection */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "VBFlags=0x%x\n", pSiS->VBFlags); xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 3, "Before: CR30=0x%02x, CR31=0x%02x, CR32=0x%02x, CR33=0x%02x, CR%02x=0x%02x\n", usScratchCR30, usScratchCR31, usScratchCR32, usScratchCR33, temp, usScratchCR38); usScratchCR30 = 0; usScratchCR31 &= ~0x60; /* TW: Clear VB_Drivermode & VB_OutputDisable */ #if 0 /* TW: For future use */ if( (pSiS->VBFlags & VB_LVDS) || (pSiS->VBFlags & VB_301) || ( (pSiS->VBFlags & (VB_301B | VB_302B |VB_30xLV | VB_30xLVX)) && (!(pSiS->VBLCDFlags & VB_LCD_1400x1050)) ) ) { #endif usScratchCR31 |= 0x04; /* TW: Set VB_NotSimuMode (not for 30xB/1400x1050?) */ #if 0 } #endif switch(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) { case CRT2_TV: if(vbflag & TV_CHSCART) { usScratchCR38 |= 0x04; usScratchCR31 |= 0x01; } else if(vbflag & TV_CHHDTV) { usScratchCR38 |= 0x08; usScratchCR31 &= ~0x01; } else if(vbflag & TV_HIVISION) usScratchCR30 |= 0x80; else if(vbflag & TV_SVIDEO) usScratchCR30 |= 0x08; else if(vbflag & TV_AVIDEO) usScratchCR30 |= 0x04; else if(vbflag & TV_SCART) usScratchCR30 |= 0x10; else usScratchCR30 |= 0x08; /* default: SVIDEO */ if(!(vbflag & (TV_CHSCART | TV_CHHDTV))) { if(vbflag & TV_PAL) { usScratchCR31 |= 0x01; usScratchCR38 &= ~0xC0; if( (vbflag & VB_SISBRIDGE) || ((vbflag & VB_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x)) ) { if(vbflag & TV_PALM) usScratchCR38 |= 0x40; else if(vbflag & TV_PALN) usScratchCR38 |= 0x80; } } else usScratchCR31 &= ~0x01; } usScratchCR30 |= 0x01; /* Set SimuScanMode */ usScratchCR31 &= ~0x04; /* Clear NotSimuMode */ pSiS->SiS_Pr->SiS_CHOverScan = pSiS->UseCHOverScan; if(pSiS->OptTVSOver == 1) { pSiS->SiS_Pr->SiS_CHSOverScan = TRUE; } else { pSiS->SiS_Pr->SiS_CHSOverScan = FALSE; } break; case CRT2_LCD: usScratchCR30 |= 0x21; /* LCD + SimuScanMode */ break; case CRT2_VGA: usScratchCR30 |= 0x41; /* VGA2 + SimuScanMode */ break; default: usScratchCR30 |= 0x00; usScratchCR31 |= 0x20; /* VB_OUTPUT_DISABLE */ if(pSiS->UseVESA) { crt1rateindex = SISSearchCRT1Rate(pScrn, mode); } } /* TW: for VESA: no DRIVERMODE, otherwise * -) CRT2 will not be initialized correctly when using mode * where LCD has to scale, and * -) CRT1 will have too low rate */ if (pSiS->UseVESA) { usScratchCR31 &= 0x40; /* TW: Clear Drivermode */ #ifdef TWDEBUG usScratchCR31 |= 0x40; /* DEBUG (for non-slave mode VESA) */ crt1rateindex = SISSearchCRT1Rate(pScrn, mode); #endif } else { usScratchCR31 |= 0x40; /* TW: Set Drivermode */ if(!pSiS->IsCustom) { crt1rateindex = SISSearchCRT1Rate(pScrn, mode); } else { crt1rateindex = usScratchCR33; } } outSISIDXREG(SISCR, 0x30, usScratchCR30); outSISIDXREG(SISCR, 0x31, usScratchCR31); if(temp) { usScratchCR38 &= ~0x03; /* Clear LCDA/DualEdge bits */ outSISIDXREG(SISCR, temp, usScratchCR38); } pSiS->SiS_Pr->SiS_UseOEM = pSiS->OptUseOEM; #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(pSiS->SecondHead) { /* CRT1 */ usScratchCR33 &= 0xf0; usScratchCR33 |= (crt1rateindex & 0x0f); } else { /* CRT2 */ usScratchCR33 &= 0x0f; if(vbflag & CRT2_VGA) usScratchCR33 |= ((crt1rateindex << 4) & 0xf0); } } else { #endif if(vbflag & CRT2_VGA) { usScratchCR33 = (crt1rateindex & 0x0f) | ((crt1rateindex & 0x0f) << 4); } else { usScratchCR33 = crt1rateindex & 0x0f; } if((!(pSiS->UseVESA)) && (vbflag & CRT2_ENABLE)) { #ifndef TWDEBUG if(pSiS->CRT1off) usScratchCR33 &= 0xf0; #endif } #ifdef SISDUALHEAD } #endif outSISIDXREG(SISCR, 0x33, usScratchCR33); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "After: CR30=0x%02x, CR31=0x%02x, CR33=0x%02x\n", usScratchCR30, usScratchCR31, usScratchCR33); /* Enable TurboQueue */ SiSEnableTurboQueue(pScrn); if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) { /* Switch on CRT1 for modes that require the bridge in SlaveMode */ inSISIDXREG(SISCR, 0x17, usScratchCR17); if(!(usScratchCR17 & 0x80)) { orSISIDXREG(SISCR, 0x17, 0x80); outSISIDXREG(SISSR, 0x00, 0x01); usleep(10000); outSISIDXREG(SISSR, 0x00, 0x03); } } } /* Functions for adjusting various TV settings */ /* These are used by the PostSetMode() functions as well as * the (hopefully) upcoming display properties extension/tool. * * There is each a Set and a Get routine. The Set functions * take a value of the same range as the corresponding option. * The Get routines return a value of the same range (although * not necessarily the same value as previously set because * of the lower resolution of the respective setting compared * to the valid range). * The Get routines return -2 on error (eg. hardware does not * support this setting). * Note: The x and y positioning routines accept a position * RELATIVE to the default position. All other routines * take ABSOLUTE values. * * The Set functions will store the property regardless if TV is * currently used or not and if the hardware supports the property * or not. The Get routines will return this stored * value if TV is not currently used (because the register does * not contain the correct value then) or if the hardware supports * the respective property. This should make it easier for the * display property tool because it does not have to know the * hardware features. * * All the routines are dual head aware. It does not matter * if the function is called from the CRT1 or CRT2 session. * The values will be stored in pSiSEnt if we're running dual. */ void SiS_SetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->chtvlumabandwidthcvbs = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->chtvlumabandwidthcvbs = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_CHRONTEL)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: val /= 8; if((val == 0) || (val == 1)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 8) | 0x03),0xFE); } break; case CHRONTEL_701x: val /= 4; if((val >= 0) && (val <= 3)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 8) | 0x02),0xFC); } break; } } int SiS_GetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_CHRONTEL && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->chtvlumabandwidthcvbs; else #endif return (int)pSiS->chtvlumabandwidthcvbs; } else { #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: return(int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x01) * 8); case CHRONTEL_701x: return(int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x03) * 4); default: return -2; } } } void SiS_SetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->chtvlumabandwidthsvideo = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->chtvlumabandwidthsvideo = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_CHRONTEL)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: val /= 6; if((val >= 0) && (val <= 2)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 9) | 0x03),0xF9); } break; case CHRONTEL_701x: val /= 4; if((val >= 0) && (val <= 3)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 10) | 0x02),0xF3); } break; } } int SiS_GetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_CHRONTEL && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->chtvlumabandwidthsvideo; else #endif return (int)pSiS->chtvlumabandwidthsvideo; } else { #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x06) >> 1) * 6); case CHRONTEL_701x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x0c) >> 2) * 4); default: return -2; } } } void SiS_SetCHTVlumaflickerfilter(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->chtvlumaflickerfilter = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->chtvlumaflickerfilter = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_CHRONTEL)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: val /= 6; if((val >= 0) && (val <= 2)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 10) | 0x01),0xF3); } break; case CHRONTEL_701x: val /= 4; if((val >= 0) && (val <= 3)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 10) | 0x01),0xF3); } break; } } int SiS_GetCHTVlumaflickerfilter(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_CHRONTEL && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->chtvlumaflickerfilter; else #endif return (int)pSiS->chtvlumaflickerfilter; } else { #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 6); case CHRONTEL_701x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 4); default: return -2; } } } void SiS_SetCHTVchromabandwidth(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->chtvchromabandwidth = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->chtvchromabandwidth = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_CHRONTEL)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: val /= 4; if((val >= 0) && (val <= 3)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 12) | 0x03),0xCF); } break; case CHRONTEL_701x: val /= 8; if((val >= 0) && (val <= 1)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 12) | 0x02),0xEF); } break; } } int SiS_GetCHTVchromabandwidth(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_CHRONTEL && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->chtvchromabandwidth; else #endif return (int)pSiS->chtvchromabandwidth; } else { #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x30) >> 4) * 4); case CHRONTEL_701x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x10) >> 4) * 8); default: return -2; } } } void SiS_SetCHTVchromaflickerfilter(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->chtvchromaflickerfilter = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->chtvchromaflickerfilter = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_CHRONTEL)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: val /= 6; if((val >= 0) && (val <= 2)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 12) | 0x01),0xCF); } break; case CHRONTEL_701x: val /= 4; if((val >= 0) && (val <= 3)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 12) | 0x01),0xCF); } break; } } int SiS_GetCHTVchromaflickerfilter(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_CHRONTEL && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->chtvchromaflickerfilter; else #endif return (int)pSiS->chtvchromaflickerfilter; } else { #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 6); case CHRONTEL_701x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 4); default: return -2; } } } void SiS_SetCHTVcvbscolor(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->chtvcvbscolor = val ? 1 : 0; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_CHRONTEL)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: if(!val) SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x4003,0x00); else SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x0003,~0x40); break; case CHRONTEL_701x: if(!val) SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x0002,~0x20); else SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x2002,0x00); break; } } int SiS_GetCHTVcvbscolor(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_CHRONTEL && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->chtvcvbscolor; else #endif return (int)pSiS->chtvcvbscolor; } else { #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x40) >> 6) ^ 0x01); case CHRONTEL_701x: return(int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x20) >> 5) ^ 0x01); default: return -2; } } } void SiS_SetCHTVtextenhance(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->chtvtextenhance = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->chtvtextenhance = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_CHRONTEL)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: val /= 6; if((val >= 0) && (val <= 2)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 8) | 0x01),0xFC); } break; case CHRONTEL_701x: val /= 2; if((val >= 0) && (val <= 7)) { SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 8) | 0x03),0xF8); } break; } } int SiS_GetCHTVtextenhance(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_CHRONTEL && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->chtvtextenhance; else #endif return (int)pSiS->chtvtextenhance; } else { #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: return(int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x03) * 6); case CHRONTEL_701x: return(int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x07) * 2); default: return -2; } } } void SiS_SetCHTVcontrast(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->chtvcontrast = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->chtvcontrast = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_CHRONTEL)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif val /= 2; if((val >= 0) && (val <= 7)) { switch(pSiS->ChrontelType) { case CHRONTEL_700x: SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 8) | 0x11),0xF8); break; case CHRONTEL_701x: SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((val << 8) | 0x08),0xF8); break; } } } int SiS_GetCHTVcontrast(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_CHRONTEL && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->chtvcontrast; else #endif return (int)pSiS->chtvcontrast; } else { #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: return(int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x11) & 0x07) * 2); case CHRONTEL_701x: return(int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x08) & 0x07) * 2); default: return -2; } } } void SiS_SetSISTVedgeenhance(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->sistvedgeenhance = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->sistvedgeenhance = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_301)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif val /= 2; if((val >= 0) && (val <= 7)) { setSISIDXREG(SISPART2,0x3A, 0x1F, (val << 5)); } } int SiS_GetSISTVedgeenhance(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_301 && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->sistvedgeenhance; else #endif return (int)pSiS->sistvedgeenhance; } else { unsigned char temp; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif inSISIDXREG(SISPART2, 0x3a, temp); return(int)(((temp & 0xe0) >> 5) * 2); } } void SiS_SetSISTVantiflicker(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->sistvantiflicker = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->sistvantiflicker = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_SISBRIDGE)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif val /= 2; if((val >= 0) && (val <= 7)) { setSISIDXREG(SISPART2,0x0A,0x8F, (val << 4)); } } int SiS_GetSISTVantiflicker(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_SISBRIDGE && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->sistvantiflicker; else #endif return (int)pSiS->sistvantiflicker; } else { unsigned char temp; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif inSISIDXREG(SISPART2, 0x0a, temp); return(int)(((temp & 0x70) >> 4) * 2); } } void SiS_SetSISTVsaturation(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif pSiS->sistvsaturation = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->sistvsaturation = val; #endif if(!(pSiS->VBFlags & CRT2_TV)) return; if(!(pSiS->VBFlags & VB_SISBRIDGE)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif val /= 2; if((val >= 0) && (val <= 7)) { setSISIDXREG(SISPART4,0x21,0xF8, val); } } int SiS_GetSISTVsaturation(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif if(!(pSiS->VBFlags & VB_SISBRIDGE && pSiS->VBFlags & CRT2_TV)) { #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->sistvsaturation; else #endif return (int)pSiS->sistvsaturation; } else { unsigned char temp; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif inSISIDXREG(SISPART4, 0x21, temp); return(int)((temp & 0x07) * 2); } } void SiS_SetSIS6326TVantiflicker(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); unsigned char tmp; pSiS->sis6326antiflicker = val; if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif tmp = SiS6326GetTVReg(pScrn,0x00); if(!(tmp & 0x04)) return; /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */ if(val >= 0 && val <= 4) { tmp &= 0x1f; tmp |= (val << 5); SiS6326SetTVReg(pScrn,0x00,tmp); } } int SiS_GetSIS6326TVantiflicker(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); unsigned char tmp; if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) { return (int)pSiS->sis6326antiflicker; } #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif tmp = SiS6326GetTVReg(pScrn,0x00); if(!(tmp & 0x04)) { return (int)pSiS->sis6326antiflicker; } else { return (int)((tmp >> 5) & 0x07); } } void SiS_SetSIS6326TVenableyfilter(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); unsigned char tmp; if(val) val = 1; pSiS->sis6326enableyfilter = val; if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif tmp = SiS6326GetTVReg(pScrn,0x00); if(!(tmp & 0x04)) return; tmp = SiS6326GetTVReg(pScrn,0x43); tmp &= ~0x10; tmp |= ((val & 0x01) << 4); SiS6326SetTVReg(pScrn,0x43,tmp); } int SiS_GetSIS6326TVenableyfilter(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); unsigned char tmp; if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) { return (int)pSiS->sis6326enableyfilter; } #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif tmp = SiS6326GetTVReg(pScrn,0x00); if(!(tmp & 0x04)) { return (int)pSiS->sis6326enableyfilter; } else { tmp = SiS6326GetTVReg(pScrn,0x43); return (int)((tmp >> 4) & 0x01); } } void SiS_SetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); unsigned char tmp; if(val) val = 1; pSiS->sis6326yfilterstrong = val; if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif tmp = SiS6326GetTVReg(pScrn,0x00); if(!(tmp & 0x04)) return; tmp = SiS6326GetTVReg(pScrn,0x43); if(tmp & 0x10) { tmp &= ~0x40; tmp |= ((val & 0x01) << 6); SiS6326SetTVReg(pScrn,0x43,tmp); } } int SiS_GetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); unsigned char tmp; if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) { return (int)pSiS->sis6326yfilterstrong; } #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif tmp = SiS6326GetTVReg(pScrn,0x00); if(!(tmp & 0x04)) { return (int)pSiS->sis6326yfilterstrong; } else { tmp = SiS6326GetTVReg(pScrn,0x43); if(!(tmp & 0x10)) { return (int)pSiS->sis6326yfilterstrong; } else { return (int)((tmp >> 6) & 0x01); } } } void SiS_SetTVxposoffset(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif pSiS->tvxpos = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->tvxpos = val; #endif if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) { if(pSiS->VBFlags & CRT2_TV) { if(pSiS->VBFlags & VB_CHRONTEL) { int x = pSiS->tvx; #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) x = pSiSEnt->tvx; #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: if((val >= -32) && (val <= 32)) { x += val; if(x < 0) x = 0; SiS_SetCH700x(pSiS->SiS_Pr, (((x & 0xff) << 8) | 0x0a)); SiS_SetCH70xxANDOR(pSiS->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD); } break; case CHRONTEL_701x: /* TO DO */ break; } } else if(pSiS->VBFlags & VB_SISBRIDGE) { if((val >= -32) && (val <= 32)) { unsigned char p2_1f,p2_2b,p2_2c,p2_2d,p2_43; const unsigned char p2_left_ntsc[8][4] = { { 0x48, 0x63, 0x49, 0xf4 }, { 0x45, 0x60, 0x46, 0xf1 }, { 0x43, 0x6e, 0x44, 0xff }, { 0x40, 0x6b, 0x41, 0xfc }, { 0x3e, 0x69, 0x3f, 0xfa }, { 0x3c, 0x67, 0x3d, 0xf8 }, { 0x39, 0x64, 0x3a, 0xf5 }, { 0x37, 0x62, 0x38, 0xf3 } }; const unsigned char p2_right_ntsc[8][4] = { { 0x4b, 0x66, 0x4c, 0xf7 }, { 0x4c, 0x67, 0x4d, 0xf8 }, { 0x4e, 0x69, 0x4f, 0xfa }, { 0x4f, 0x6a, 0x50, 0xfb }, { 0x51, 0x6c, 0x52, 0xfd }, { 0x53, 0x6e, 0x54, 0xff }, { 0x55, 0x60, 0x56, 0xf1 }, { 0x56, 0x61, 0x57, 0xf2 } }; const unsigned char p2_left_pal[8][4] = { { 0x5b, 0x66, 0x5c, 0x87 }, { 0x59, 0x64, 0x5a, 0x85 }, { 0x56, 0x61, 0x57, 0x82 }, { 0x53, 0x6e, 0x54, 0x8f }, { 0x50, 0x6b, 0x51, 0x8c }, { 0x4d, 0x68, 0x4e, 0x89 }, { 0x4a, 0x65, 0x4b, 0x86 }, { 0x49, 0x64, 0x4a, 0x85 } }; const unsigned char p2_right_pal[8][4] = { { 0x5f, 0x6a, 0x60, 0x8b }, { 0x61, 0x6c, 0x62, 0x8d }, { 0x63, 0x6e, 0x64, 0x8f }, { 0x65, 0x60, 0x66, 0x81 }, { 0x66, 0x61, 0x67, 0x82 }, { 0x68, 0x63, 0x69, 0x84 }, { 0x69, 0x64, 0x6a, 0x85 }, { 0x6b, 0x66, 0x6c, 0x87 } }; val /= 4; p2_2d = pSiS->p2_2d; #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) p2_2d = pSiSEnt->p2_2d; #endif p2_2d &= 0xf0; if(val < 0) { val = -val; if(val == 8) val = 7; if(pSiS->VBFlags & TV_PAL) { p2_1f = p2_left_pal[val][0]; p2_2b = p2_left_pal[val][1]; p2_2c = p2_left_pal[val][2]; p2_2d |= (p2_left_pal[val][3] & 0x0f); } else { p2_1f = p2_left_ntsc[val][0]; p2_2b = p2_left_ntsc[val][1]; p2_2c = p2_left_ntsc[val][2]; p2_2d |= (p2_left_ntsc[val][3] & 0x0f); } } else { if(val == 8) val = 7; if(pSiS->VBFlags & TV_PAL) { p2_1f = p2_right_pal[val][0]; p2_2b = p2_right_pal[val][1]; p2_2c = p2_right_pal[val][2]; p2_2d |= (p2_right_pal[val][3] & 0x0f); } else { p2_1f = p2_right_ntsc[val][0]; p2_2b = p2_right_ntsc[val][1]; p2_2c = p2_right_ntsc[val][2]; p2_2d |= (p2_right_ntsc[val][3] & 0x0f); } } p2_43 = p2_1f + 3; SISWaitRetraceCRT2(pScrn); outSISIDXREG(SISPART2,0x1f,p2_1f); outSISIDXREG(SISPART2,0x2b,p2_2b); outSISIDXREG(SISPART2,0x2c,p2_2c); outSISIDXREG(SISPART2,0x2d,p2_2d); outSISIDXREG(SISPART2,0x43,p2_43); } } } } else if(pSiS->Chipset == PCI_CHIP_SIS6326) { if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) { unsigned char tmp; unsigned short temp1, temp2, temp3; tmp = SiS6326GetTVReg(pScrn,0x00); if(tmp & 0x04) { temp1 = pSiS->tvx1; temp2 = pSiS->tvx2; temp3 = pSiS->tvx3; if((val >= -16) && (val <= 16)) { if(val > 0) { temp1 += (val * 4); temp2 += (val * 4); while((temp1 > 0x0fff) || (temp2 > 0x0fff)) { temp1 -= 4; temp2 -= 4; } } else { val = -val; temp3 += (val * 4); while(temp3 > 0x03ff) { temp3 -= 4; } } } SiS6326SetTVReg(pScrn,0x3a,(temp1 & 0xff)); tmp = SiS6326GetTVReg(pScrn,0x3c); tmp &= 0xf0; tmp |= ((temp1 & 0x0f00) >> 8); SiS6326SetTVReg(pScrn,0x3c,tmp); SiS6326SetTVReg(pScrn,0x26,(temp2 & 0xff)); tmp = SiS6326GetTVReg(pScrn,0x27); tmp &= 0x0f; tmp |= ((temp2 & 0x0f00) >> 4); SiS6326SetTVReg(pScrn,0x27,tmp); SiS6326SetTVReg(pScrn,0x12,(temp3 & 0xff)); tmp = SiS6326GetTVReg(pScrn,0x13); tmp &= ~0xC0; tmp |= ((temp3 & 0x0300) >> 2); SiS6326SetTVReg(pScrn,0x13,tmp); } } } } int SiS_GetTVxposoffset(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->tvxpos; else #endif return (int)pSiS->tvxpos; } void SiS_SetTVyposoffset(ScrnInfoPtr pScrn, int val) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif pSiS->tvypos = val; #ifdef SISDUALHEAD if(pSiSEnt) pSiSEnt->tvypos = val; #endif if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) { if(pSiS->VBFlags & CRT2_TV) { if(pSiS->VBFlags & VB_CHRONTEL) { int y = pSiS->tvy; #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) y = pSiSEnt->tvy; #endif switch(pSiS->ChrontelType) { case CHRONTEL_700x: if((val >= -32) && (val <= 32)) { y -= val; if(y < 0) y = 0; SiS_SetCH700x(pSiS->SiS_Pr, (((y & 0xff) << 8) | 0x0b)); SiS_SetCH70xxANDOR(pSiS->SiS_Pr, ((y & 0x0100) | 0x08),0xFE); } break; case CHRONTEL_701x: /* TO DO */ break; } } else if(pSiS->VBFlags & VB_SISBRIDGE) { if((val >= -32) && (val <= 32)) { char p2_01, p2_02; val /= 4; p2_01 = pSiS->p2_01; p2_02 = pSiS->p2_02; #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) { p2_01 = pSiSEnt->p2_01; p2_02 = pSiSEnt->p2_02; } #endif p2_01 += (val * 2); p2_02 += (val * 2); while((p2_01 <= 0) || (p2_02 <= 0)) { p2_01 += 2; p2_02 += 2; } SISWaitRetraceCRT2(pScrn); outSISIDXREG(SISPART2,0x01,p2_01); outSISIDXREG(SISPART2,0x02,p2_02); } } } } else if(pSiS->Chipset == PCI_CHIP_SIS6326) { if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) { unsigned char tmp; int temp1, limit; tmp = SiS6326GetTVReg(pScrn,0x00); if(tmp & 0x04) { if((val >= -16) && (val <= 16)) { temp1 = (unsigned short)pSiS->tvy1; limit = (pSiS->SiS6326Flags & SIS6326_TVPAL) ? 625 : 525; if(val > 0) { temp1 += (val * 4); if(temp1 > limit) temp1 -= limit; } else { val = -val; temp1 -= (val * 2); if(temp1 <= 0) temp1 += (limit -1); } SiS6326SetTVReg(pScrn,0x11,(temp1 & 0xff)); tmp = SiS6326GetTVReg(pScrn,0x13); tmp &= ~0x30; tmp |= ((temp1 & 0x300) >> 4); SiS6326SetTVReg(pScrn,0x13,tmp); if(temp1 == 1) tmp = 0x10; else { if(pSiS->SiS6326Flags & SIS6326_TVPAL) { if((temp1 <= 3) || (temp1 >= (limit - 2))) tmp = 0x08; else if(temp1 < 22) tmp = 0x02; else tmp = 0x04; } else { if((temp1 <= 5) || (temp1 >= (limit - 4))) tmp = 0x08; else if(temp1 < 19) tmp = 0x02; else tmp = 0x04; } } SiS6326SetTVReg(pScrn,0x21,tmp); } } } } } int SiS_GetTVyposoffset(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; if(pSiSEnt && pSiS->DualHeadMode) return (int)pSiSEnt->tvypos; else #endif return (int)pSiS->tvypos; } /* TW: Disable CRT1 for saving bandwidth. This doesn't work with VESA; * VESA uses the bridge in SlaveMode and switching CRT1 off while the * bridge is in SlaveMode not that clever... */ void SiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif unsigned char usScratchCR17; Bool flag = FALSE; Bool doit = TRUE; int temp; #ifdef TWDEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT1off is %d\n", pSiS->CRT1off); #endif #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) { if(pSiS->VBFlags != pSiS->VBFlags_backup) { pSiS->VBFlags = pSiS->VBFlags_backup; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBFlags restored to %0lx\n", pSiS->VBFlags); } /* TW: -) We can't switch off CRT1 if bridge is in SlaveMode. * -) If we change to a SlaveMode-Mode (like 512x384), we * need to adapt VBFlags for eg. Xv. */ #ifdef SISDUALHEAD if(!pSiS->DualHeadMode) { #endif if(SiSBridgeIsInSlaveMode(pScrn)) { doit = FALSE; temp = pSiS->VBFlags; pSiS->VBFlags &= (~VB_DISPMODE_SINGLE); pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_DISP1); if(temp != pSiS->VBFlags) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBFlags changed to 0x%0lx\n", pSiS->VBFlags); } } #ifdef SISDUALHEAD } #endif if(doit) { inSISIDXREG(SISCR, 0x17, usScratchCR17); if(pSiS->CRT1off) { if(usScratchCR17 & 0x80) flag = TRUE; usScratchCR17 &= ~0x80; } else { if(!(usScratchCR17 & 0x80)) flag = TRUE; usScratchCR17 |= 0x80; } outSISIDXREG(SISCR, 0x17, usScratchCR17); /* TW: Reset only if status changed */ if(flag) { outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ usleep(10000); outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ } } } /* TW: Apply TV settings given by options Do this even in DualHeadMode: - if this is called by SetModeCRT1, CRT2 mode has been reset by SetModeCRT1 - if this is called by SetModeCRT2, CRT2 mode has changed (duh!) -> In both cases, the settings must be re-applied. */ if(pSiS->VBFlags & CRT2_TV) { int val; if(pSiS->VBFlags & VB_CHRONTEL) { int mychtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs; int mychtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo; int mychtvlumaflickerfilter = pSiS->chtvlumaflickerfilter; int mychtvchromabandwidth = pSiS->chtvchromabandwidth; int mychtvchromaflickerfilter = pSiS->chtvchromaflickerfilter; int mychtvcvbscolor = pSiS->chtvcvbscolor; int mychtvtextenhance = pSiS->chtvtextenhance; int mychtvcontrast = pSiS->chtvcontrast; int mytvxpos = pSiS->tvxpos; int mytvypos = pSiS->tvypos; #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) { mychtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs; mychtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo; mychtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter; mychtvchromabandwidth = pSiSEnt->chtvchromabandwidth; mychtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter; mychtvcvbscolor = pSiSEnt->chtvcvbscolor; mychtvtextenhance = pSiSEnt->chtvtextenhance; mychtvcontrast = pSiSEnt->chtvcontrast; mytvxpos = pSiSEnt->tvxpos; mytvypos = pSiSEnt->tvypos; } #endif if((val = mychtvlumabandwidthcvbs) != -1) { SiS_SetCHTVlumabandwidthcvbs(pScrn, val); } if((val = mychtvlumabandwidthsvideo) != -1) { SiS_SetCHTVlumabandwidthsvideo(pScrn, val); } if((val = mychtvlumaflickerfilter) != -1) { SiS_SetCHTVlumaflickerfilter(pScrn, val); } if((val = mychtvchromabandwidth) != -1) { SiS_SetCHTVchromabandwidth(pScrn, val); } if((val = mychtvchromaflickerfilter) != -1) { SiS_SetCHTVchromaflickerfilter(pScrn, val); } if((val = mychtvcvbscolor) != -1) { SiS_SetCHTVcvbscolor(pScrn, val); } if((val = mychtvtextenhance) != -1) { SiS_SetCHTVtextenhance(pScrn, val); } if((val = mychtvcontrast) != -1) { SiS_SetCHTVcontrast(pScrn, val); } /* Backup default TV position registers */ switch(pSiS->ChrontelType) { case CHRONTEL_700x: pSiS->tvx = SiS_GetCH700x(pSiS->SiS_Pr, 0x0a); pSiS->tvx |= (((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x02) >> 1) << 8); pSiS->tvy = SiS_GetCH700x(pSiS->SiS_Pr, 0x0b); pSiS->tvy |= ((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x01) << 8); #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) { pSiSEnt->tvx = pSiS->tvx; pSiSEnt->tvy = pSiS->tvy; } #endif break; case CHRONTEL_701x: /* TO DO */ break; } if((val = mytvxpos) != 0) { SiS_SetTVxposoffset(pScrn, val); } if((val = mytvypos) != 0) { SiS_SetTVyposoffset(pScrn, val); } } if(pSiS->VBFlags & VB_301) { int mysistvedgeenhance = pSiS->sistvedgeenhance; #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) { mysistvedgeenhance = pSiSEnt->sistvedgeenhance; } #endif if((val = mysistvedgeenhance) != -1) { SiS_SetSISTVedgeenhance(pScrn, val); } } if(pSiS->VBFlags & VB_SISBRIDGE) { int mysistvantiflicker = pSiS->sistvantiflicker; int mysistvsaturation = pSiS->sistvsaturation; int mytvxpos = pSiS->tvxpos; int mytvypos = pSiS->tvypos; #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) { mysistvantiflicker = pSiSEnt->sistvantiflicker; mysistvsaturation = pSiSEnt->sistvsaturation; mytvxpos = pSiSEnt->tvxpos; mytvypos = pSiSEnt->tvypos; } #endif /* Backup default TV position registers */ inSISIDXREG(SISPART2,0x2d,pSiS->p2_2d); inSISIDXREG(SISPART2,0x01,pSiS->p2_01); inSISIDXREG(SISPART2,0x02,pSiS->p2_02); #ifdef SISDUALHEAD if(pSiSEnt && pSiS->DualHeadMode) { pSiSEnt->p2_2d = pSiS->p2_2d; pSiSEnt->p2_01 = pSiS->p2_01; pSiSEnt->p2_02 = pSiS->p2_02; } #endif if((val = mysistvantiflicker) != -1) { SiS_SetSISTVantiflicker(pScrn, val); } if((val = mysistvsaturation) != -1) { SiS_SetSISTVsaturation(pScrn, val); } if((val = mytvxpos) != 0) { SiS_SetTVxposoffset(pScrn, val); } if((val = mytvypos) != 0) { SiS_SetTVyposoffset(pScrn, val); } } } } /* Post-set SiS6326 TV registers */ void SiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg) { SISPtr pSiS = SISPTR(pScrn); unsigned char tmp; int val; if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return; #ifdef UNLOCK_ALWAYS sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); #endif /* Backup default TV position registers */ pSiS->tvx1 = SiS6326GetTVReg(pScrn,0x3a); pSiS->tvx1 |= ((SiS6326GetTVReg(pScrn,0x3c) & 0x0f) << 8); pSiS->tvx2 = SiS6326GetTVReg(pScrn,0x26); pSiS->tvx2 |= ((SiS6326GetTVReg(pScrn,0x27) & 0xf0) << 4); pSiS->tvx3 = SiS6326GetTVReg(pScrn,0x12); pSiS->tvx3 |= ((SiS6326GetTVReg(pScrn,0x13) & 0xC0) << 2); pSiS->tvy1 = SiS6326GetTVReg(pScrn,0x11); pSiS->tvy1 |= ((SiS6326GetTVReg(pScrn,0x13) & 0x30) << 4); /* TW: Handle TVPosOffset options (BEFORE switching on TV) */ if((val = pSiS->tvxpos) != 0) { SiS_SetTVxposoffset(pScrn, val); } if((val = pSiS->tvypos) != 0) { SiS_SetTVyposoffset(pScrn, val); } /* TW: Switch on TV output. This is rather complicated, but * if we don't do it, TV output will flicker terribly. */ if(pSiS->SiS6326Flags & SIS6326_TVON) { orSISIDXREG(SISSR, 0x01, 0x20); tmp = SiS6326GetTVReg(pScrn,0x00); tmp &= ~0x04; while(!(inSISREG(SISINPSTAT) & 0x08)); /* Wait while NOT vb */ SiS6326SetTVReg(pScrn,0x00,tmp); for(val=0; val < 2; val++) { while(!(inSISREG(SISINPSTAT) & 0x08)); /* Wait while NOT vb */ while(inSISREG(SISINPSTAT) & 0x08); /* wait while vb */ } SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]); tmp = inSISREG(SISINPSTAT); outSISREG(SISAR, 0x20); tmp = inSISREG(SISINPSTAT); while(inSISREG(SISINPSTAT) & 0x01); while(!(inSISREG(SISINPSTAT) & 0x01)); andSISIDXREG(SISSR, 0x01, ~0x20); for(val=0; val < 10; val++) { while(!(inSISREG(SISINPSTAT) & 0x08)); /* Wait while NOT vb */ while(inSISREG(SISINPSTAT) & 0x08); /* wait while vb */ } andSISIDXREG(SISSR, 0x01, ~0x20); } tmp = SiS6326GetTVReg(pScrn,0x00); if(!(tmp & 0x04)) return; /* TW: Apply TV settings given by options */ if((val = pSiS->sis6326antiflicker) != -1) { SiS_SetSIS6326TVantiflicker(pScrn, val); } if((val = pSiS->sis6326enableyfilter) != -1) { SiS_SetSIS6326TVenableyfilter(pScrn, val); } if((val = pSiS->sis6326yfilterstrong) != -1) { SiS_SetSIS6326TVyfilterstrong(pScrn, val); } } /* Check if video bridge is in slave mode */ BOOLEAN SiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); unsigned char usScratchP1_00; if(!(pSiS->VBFlags & VB_VIDEOBRIDGE)) return FALSE; inSISIDXREG(SISPART1,0x00,usScratchP1_00); if( ((pSiS->VGAEngine == SIS_300_VGA) && (usScratchP1_00 & 0xa0) == 0x20) || ((pSiS->VGAEngine == SIS_315_VGA) && (usScratchP1_00 & 0x50) == 0x10) ) { return TRUE; } else { return FALSE; } } /* TW: Build a list of the VESA modes the BIOS reports as valid */ static void SiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe) { SISPtr pSiS = SISPTR(pScrn); int i = 0; while(vbe->VideoModePtr[i] != 0xffff) { sisModeInfoPtr m; VbeModeInfoBlock *mode; int id = vbe->VideoModePtr[i++]; int bpp; if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) continue; bpp = mode->BitsPerPixel; m = xnfcalloc(sizeof(sisModeInfoRec),1); m->width = mode->XResolution; m->height = mode->YResolution; m->bpp = bpp; m->n = id; m->next = pSiS->SISVESAModeList; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "BIOS reported VESA mode 0x%x: x:%i y:%i bpp:%i\n", m->n, m->width, m->height, m->bpp); pSiS->SISVESAModeList = m; VBEFreeModeInfo(mode); } } /* TW: Calc VESA mode from given resolution/depth */ static UShort SiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode) { SISPtr pSiS = SISPTR(pScrn); sisModeInfoPtr m = pSiS->SISVESAModeList; UShort i = (pScrn->bitsPerPixel+7)/8 - 1; UShort ModeIndex = 0; while(m) { if(pScrn->bitsPerPixel == m->bpp && mode->HDisplay == m->width && mode->VDisplay == m->height) return m->n; m = m->next; } xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "No valid BIOS VESA mode found for %dx%dx%d; searching built-in table.\n", mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel); switch(mode->HDisplay) { case 512: if(mode->VDisplay == 384) ModeIndex = VESAModeIndex_512x384[i]; break; case 640: if(mode->VDisplay == 480) ModeIndex = VESAModeIndex_640x480[i]; break; case 800: if(mode->VDisplay == 600) ModeIndex = VESAModeIndex_800x600[i]; break; case 1024: if(mode->VDisplay == 768) ModeIndex = VESAModeIndex_1024x768[i]; break; case 1280: if(mode->VDisplay == 1024) ModeIndex = VESAModeIndex_1280x1024[i]; break; case 1600: if(mode->VDisplay == 1200) ModeIndex = VESAModeIndex_1600x1200[i]; break; case 1920: if(mode->VDisplay == 1440) ModeIndex = VESAModeIndex_1920x1440[i]; break; } if(!ModeIndex) xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "No valid mode found for %dx%dx%d in built-in table either.\n", mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel); return(ModeIndex); } /* TW: Calculate the vertical refresh rate from a mode */ int SiSCalcVRate(DisplayModePtr mode) { float hsync, refresh = 0; if(mode->HSync > 0.0) hsync = mode->HSync; else if(mode->HTotal > 0) hsync = (float)mode->Clock / (float)mode->HTotal; else hsync = 0.0; if(mode->VTotal > 0) refresh = hsync * 1000.0 / mode->VTotal; if(mode->Flags & V_INTERLACE) refresh *= 2.0; if(mode->Flags & V_DBLSCAN) refresh /= 2.0; if(mode->VScan > 1) refresh /= mode->VScan; if(mode->VRefresh > 0.0) refresh = mode->VRefresh; if(hsync == 0 || refresh == 0) return(0); return((int)(refresh)); } /* TW: Calculate CR33 (rate index) for CRT1. * Calculation is done using currentmode, therefore it is * recommended to set VertRefresh and HorizSync to correct * values in config file. */ unsigned char SISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode) { SISPtr pSiS = SISPTR(pScrn); int i = 0; int irefresh; unsigned short xres = mode->HDisplay; unsigned short yres = mode->VDisplay; unsigned char index; BOOLEAN checksis730 = FALSE; irefresh = SiSCalcVRate(mode); if(!irefresh) { if(xres == 800 || xres == 1024 || xres == 1280) return 0x02; else return 0x01; } /* SiS730 has troubles on CRT2 if CRT1 is at 32bpp */ if( (pSiS->sishw_ext.jChipType == SIS_730) && (pSiS->VBFlags & VB_VIDEOBRIDGE) && (pSiS->CurrentLayout.bitsPerPixel == 32) ) { #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(pSiS->SecondHead) { checksis730 = TRUE; } } else #endif if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) { checksis730 = TRUE; } } #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "Debug: CalcVRate returned %d\n", irefresh); #endif /* We need the REAL refresh rate here */ if(mode->Flags & V_INTERLACE) irefresh /= 2; /* Do not multiply by 2 when DBLSCAN! */ #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "Debug: Rate after correction = %d\n", irefresh); #endif index = 0; while((sisx_vrate[i].idx != 0) && (sisx_vrate[i].xres <= xres)) { if((sisx_vrate[i].xres == xres) && (sisx_vrate[i].yres == yres)) { if((checksis730 == FALSE) || (sisx_vrate[i].SiS730valid32bpp == TRUE)) { if(sisx_vrate[i].refresh == irefresh) { index = sisx_vrate[i].idx; break; } else if(sisx_vrate[i].refresh > irefresh) { if((sisx_vrate[i].refresh - irefresh) <= 3) { index = sisx_vrate[i].idx; } else if( ((checksis730 == FALSE) || (sisx_vrate[i - 1].SiS730valid32bpp == TRUE)) && ((irefresh - sisx_vrate[i - 1].refresh) <= 2) && (sisx_vrate[i].idx != 1) ) { index = sisx_vrate[i - 1].idx; } break; } } } i++; } if(index > 0) return index; else { /* TW: Default Rate index */ if(xres == 800 || xres == 1024 || xres == 1280) return 0x02; else return 0x01; } } void SISWaitRetraceCRT1(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); int watchdog; unsigned char temp; inSISIDXREG(SISCR,0x17,temp); if(!(temp & 0x80)) return; watchdog = 65536; while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog); watchdog = 65536; while((inSISREG(SISINPSTAT) & 0x08) && --watchdog); } void SISWaitRetraceCRT2(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); int watchdog; unsigned char temp, reg; switch(pSiS->VGAEngine) { case SIS_300_VGA: reg = 0x28; break; case SIS_315_VGA: reg = 0x33; break; default: return; } watchdog = 65536; do { inSISIDXREG(SISPART1, reg, temp); if(temp & 0x80) break; } while(--watchdog); watchdog = 65536; do { inSISIDXREG(SISPART1, reg, temp); if(!(temp & 0x80)) break; } while(--watchdog); } static void SISWaitVBRetrace(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(pSiS->SecondHead) SISWaitRetraceCRT1(pScrn); else SISWaitRetraceCRT2(pScrn); } else { #endif if(pSiS->VBFlags & DISPTYPE_DISP1) { SISWaitRetraceCRT1(pScrn); } if(pSiS->VBFlags & DISPTYPE_DISP2) { if(!(SiSBridgeIsInSlaveMode(pScrn))) { SISWaitRetraceCRT2(pScrn); } } #ifdef SISDUALHEAD } #endif } void sisSaveUnlockExtRegisterLock(SISPtr pSiS, unsigned char *reg1, unsigned char *reg2) { register unsigned char val; unsigned long mylockcalls; pSiS->lockcalls++; mylockcalls = pSiS->lockcalls; /* check if already unlocked */ inSISIDXREG(SISSR, 0x05, val); if(val != 0xa1) { /* save State */ if(reg1) *reg1 = val; /* unlock */ outSISIDXREG(SISSR, 0x05, 0x86); inSISIDXREG(SISSR, 0x05, val); if(val != 0xA1) { #ifdef TWDEBUG unsigned char val1, val2; int i; #endif xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, "Failed to unlock sr registers (%p, %x, 0x%02x; %d)\n", pSiS, pSiS->RelIO, val, mylockcalls); #ifdef TWDEBUG for(i = 0; i <= 0x3f; i++) { inSISIDXREG(SISSR, i, val1); inSISIDXREG(0x3c4, i, val2); xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO, "SR%02d: RelIO=0x%02x 0x3c4=0x%02x (%d)\n", i, val1, val2, mylockcalls); } #endif if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) { /* Emergency measure: unlock at 0x3c4, and try to enable Relocated IO ports */ outSISIDXREG(0x3c4,0x05,0x86); andSISIDXREG(0x3c4,0x33,~0x20); outSISIDXREG(SISSR, 0x05, 0x86); } } } if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) { inSISIDXREG(SISCR, 0x80, val); if(val != 0xa1) { /* save State */ if(reg2) *reg2 = val; outSISIDXREG(SISCR, 0x80, 0x86); inSISIDXREG(SISCR, 0x80, val); if(val != 0xA1) { xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, "Failed to unlock cr registers (%p, %x, 0x%02x)\n", pSiS, pSiS->RelIO, val); } } } } void sisRestoreExtRegisterLock(SISPtr pSiS, unsigned char reg1, unsigned char reg2) { /* restore lock */ #ifndef UNLOCK_ALWAYS outSISIDXREG(SISSR, 0x05, reg1 == 0xA1 ? 0x86 : 0x00); if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) { outSISIDXREG(SISCR, 0x80, reg2 == 0xA1 ? 0x86 : 0x00); } #endif }