/* $XFree86$ */ /* $XdotOrg$ */ /* * Mode setup and basic video bridge detection * * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria. * * The SISInit() function for old series (except TV and FIFO calculation) * was previously based on code which was Copyright (C) 1998,1999 by Alan * Hourihane, Wigan, England. However, the code has been rewritten entirely * and is - it its current representation - not covered by this old copyright. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1) Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3) The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Author: Thomas Winischhofer * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sis.h" #define SIS_NEED_inSISREG #define SIS_NEED_outSISREG #define SIS_NEED_inSISIDXREG #define SIS_NEED_outSISIDXREG #define SIS_NEED_orSISIDXREG #define SIS_NEED_andSISIDXREG #include "sis_regs.h" #include "sis_dac.h" static Bool SISInit(ScrnInfoPtr pScrn, DisplayModePtr mode); static Bool SIS300Init(ScrnInfoPtr pScrn, DisplayModePtr mode); static int SIS6326DoSense(ScrnInfoPtr pScrn, int tempbh, int tempbl, int tempch, int tempcl); static void SISSense6326(ScrnInfoPtr pScrn); static void SiS6326TVDelay(ScrnInfoPtr pScrn, int delay); extern void SISSense30x(ScrnInfoPtr pScrn, Bool quiet); extern void SISSenseChrontel(ScrnInfoPtr pScrn, Bool quiet); /* Our very own vgaHW functions */ void SiSVGASave(ScrnInfoPtr pScrn, SISRegPtr save, int flags); void SiSVGARestore(ScrnInfoPtr pScrn, SISRegPtr restore, int flags); void SiSVGASaveFonts(ScrnInfoPtr pScrn); void SiSVGARestoreFonts(ScrnInfoPtr pScrn); void SISVGALock(SISPtr pSiS); void SiSVGAUnlock(SISPtr pSiS); void SiSVGAProtect(ScrnInfoPtr pScrn, Bool on); #ifdef SIS_PC_PLATFORM Bool SiSVGAMapMem(ScrnInfoPtr pScrn); void SiSVGAUnmapMem(ScrnInfoPtr pScrn); #endif Bool SiSVGASaveScreen(ScreenPtr pScreen, int mode); static Bool SiSVGAInit(ScrnInfoPtr pScrn, DisplayModePtr mode, int fixsync); const CARD8 SiS6326TVRegs1[14] = { 0x00,0x01,0x02,0x03,0x04,0x11,0x12,0x13,0x21,0x26,0x27,0x3a,0x3c,0x43 }; const CARD8 SiS6326TVRegs1_NTSC[6][14] = { {0x81,0x3f,0x49,0x1b,0xa9,0x03,0x00,0x09,0x08,0x7d,0x00,0x88,0x30,0x60}, {0x81,0x3f,0x49,0x1d,0xa0,0x03,0x00,0x09,0x08,0x7d,0x00,0x88,0x30,0x60}, {0x81,0x45,0x24,0x8e,0x26,0x0b,0x00,0x09,0x02,0xfe,0x00,0x09,0x51,0x60}, {0x81,0x45,0x24,0x8e,0x26,0x07,0x00,0x29,0x04,0x30,0x10,0x3b,0x61,0x60}, {0x81,0x3f,0x24,0x8e,0x26,0x09,0x00,0x09,0x02,0x30,0x10,0x3b,0x51,0x60}, /* 640x400, 640x480 */ {0x83,0x5d,0x21,0xbe,0x75,0x03,0x00,0x09,0x08,0x42,0x10,0x4d,0x61,0x79} /* 640x480u */ }; const CARD8 SiS6326TVRegs2_NTSC[6][54] = { {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C, 0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0xFC, 0xDF, 0x94, 0x1F, 0x4A, 0x03, 0x71, 0x07, 0x97, 0x10, 0x40, 0x48, 0x00, 0x26, 0xB6, 0x10, 0x5C, 0xEC, 0x21, 0x2E, 0xBE, 0x10, 0x64, 0xF4, 0x21, 0x13, 0x75, 0x08, 0x31, 0x6A, 0x01, 0xA0}, {0x11, 0x17, 0x03, 0x0A, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C, 0x0D, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0xFF, 0xDF, 0x94, 0x1F, 0x4A, 0x03, 0x71, 0x07, 0x97, 0x10, 0x40, 0x48, 0x00, 0x26, 0xB6, 0x10, 0x5C, 0xEC, 0x21, 0x2E, 0xBE, 0x10, 0x64, 0xF4, 0x21, 0x13, 0x75, 0x08, 0x31, 0x6A, 0x01, 0xA0}, {0x11, 0x17, 0x03, 0x0A, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C, 0x0D, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0xFF, 0xDF, 0x94, 0x3F, 0x8C, 0x06, 0xCE, 0x07, 0x27, 0x30, 0x73, 0x7B, 0x00, 0x48, 0x68, 0x30, 0xB2, 0xD2, 0x52, 0x50, 0x70, 0x30, 0xBA, 0xDA, 0x52, 0xDC, 0x02, 0xD1, 0x53, 0xF7, 0x02, 0xA0}, {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C, 0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0xDC, 0xDF, 0x94, 0x3F, 0x8C, 0x06, 0xCE, 0x07, 0x27, 0x30, 0x73, 0x7B, 0x00, 0x48, 0x68, 0x30, 0xB2, 0xD2, 0x52, 0x50, 0x70, 0x30, 0xBA, 0xDA, 0x52, 0x00, 0x02, 0xF5, 0x53, 0xF7, 0x02, 0xA0}, {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C, 0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0xDC, 0xDF, 0x94, 0x3F, 0x8C, 0x06, 0xCE, 0x07, 0x27, 0x30, 0x73, 0x7B, 0x00, 0x48, 0x68, 0x30, 0xB2, 0xD2, 0x52, 0x50, 0x70, 0x30, 0xBA, 0xDA, 0x52, 0xDC, 0x02, 0xD1, 0x53, 0xF7, 0x02, 0xA0}, {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C, /* 640x480u */ 0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0xDC, 0xDF, 0x94, 0xAF, 0x95, 0x06, 0xDD, 0x07, 0x5F, 0x30, 0x7E, 0x86, 0x00, 0x4C, 0xA4, 0x30, 0xE3, 0x3B, 0x62, 0x54, 0xAC, 0x30, 0xEB, 0x43, 0x62, 0x48, 0x34, 0x3D, 0x63, 0x29, 0x03, 0xA0} }; const CARD8 SiS6326TVRegs1_PAL[6][14] = { {0x81,0x2d,0xc8,0x07,0xb2,0x0b,0x00,0x09,0x02,0xed,0x00,0xf8,0x30,0x40}, {0x80,0x2d,0xa4,0x03,0xd9,0x0b,0x00,0x09,0x02,0xed,0x10,0xf8,0x71,0x40}, {0x81,0x2d,0xa4,0x03,0xd9,0x0b,0x00,0x09,0x02,0xed,0x10,0xf8,0x71,0x40}, /* 640x480 */ {0x81,0x2d,0xa4,0x03,0xd9,0x0b,0x00,0x09,0x02,0x8f,0x10,0x9a,0x71,0x40}, /* 800x600 */ {0x83,0x63,0xa1,0x7a,0xa3,0x0a,0x00,0x09,0x02,0xb5,0x11,0xc0,0x81,0x59}, /* 800x600u */ {0x81,0x63,0xa4,0x03,0xd9,0x01,0x00,0x09,0x10,0x9f,0x10,0xaa,0x71,0x59} /* 720x540 */ }; const CARD8 SiS6326TVRegs2_PAL[6][54] = { {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D, 0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94, 0xE5, 0xDF, 0x94, 0xEF, 0x5A, 0x03, 0x7F, 0x07, 0xFF, 0x10, 0x4E, 0x56, 0x00, 0x2B, 0x23, 0x20, 0xB4, 0xAC, 0x31, 0x33, 0x2B, 0x20, 0xBC, 0xB4, 0x31, 0x83, 0xE1, 0x78, 0x31, 0xD6, 0x01, 0xA0}, {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D, 0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94, 0xE5, 0xDF, 0x94, 0xDF, 0xB2, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x90, 0x98, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40, 0x6A, 0x5A, 0x73, 0x03, 0xC1, 0xF8, 0x63, 0xB6, 0x03, 0xA0}, {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D, /* 640x480 */ 0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94, 0xE5, 0xDF, 0x94, 0xDF, 0xB2, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x90, 0x98, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40, 0x6A, 0x5A, 0x73, 0x03, 0xC1, 0xF8, 0x63, 0xB6, 0x03, 0xA0}, {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D, /* 800x600 */ 0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94, 0xE5, 0xDF, 0x94, 0xDF, 0xB2, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x90, 0x98, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40, 0x6A, 0x5A, 0x73, 0xA0, 0xC1, 0x95, 0x73, 0xB6, 0x03, 0xA0}, {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D, /* 800x600u */ 0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94, 0xE5, 0xDF, 0x94, 0x7F, 0xBD, 0x08, 0x0E, 0x07, 0x47, 0x40, 0x9D, 0xA5, 0x00, 0x54, 0x94, 0x40, 0xA4, 0xE4, 0x73, 0x5C, 0x9C, 0x40, 0xAC, 0xEC, 0x73, 0x0B, 0x0E, 0x00, 0x84, 0x03, 0x04, 0xA0}, {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D, /* 720x540 */ 0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94, 0xE5, 0xDF, 0x94, 0xDF, 0xB0, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x9D, 0xA5, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40, 0x6A, 0x5A, 0x73, 0xA0, 0xC1, 0x95, 0x73, 0xB6, 0x03, 0xA0} }; const CARD8 SiS6326CR[9][15] = { {0x79,0x63,0x64,0x1d,0x6a,0x93,0x00,0x6f,0xf0,0x58,0x8a,0x57,0x57,0x70,0x20}, /* PAL 800x600 */ {0x79,0x4f,0x50,0x95,0x60,0x93,0x00,0x6f,0xba,0x14,0x86,0xdf,0xe0,0x30,0x00}, /* PAL 640x480 */ {0x5f,0x4f,0x50,0x82,0x53,0x9f,0x00,0x0b,0x3e,0xe9,0x8b,0xdf,0xe7,0x04,0x00}, /* NTSC 640x480 */ {0x5f,0x4f,0x50,0x82,0x53,0x9f,0x00,0x0b,0x3e,0xcb,0x8d,0x8f,0x96,0xe9,0x00}, /* NTSC 640x400 */ {0x83,0x63,0x64,0x1f,0x6d,0x9b,0x00,0x6f,0xf0,0x48,0x0a,0x23,0x57,0x70,0x20}, /* PAL 800x600u */ {0x79,0x59,0x5b,0x1d,0x66,0x93,0x00,0x6f,0xf0,0x42,0x04,0x1b,0x40,0x70,0x20}, /* PAL 720x540 */ {0x66,0x4f,0x51,0x0a,0x57,0x89,0x00,0x0b,0x3e,0xd9,0x0b,0xb6,0xe7,0x04,0x00}, /* NTSC 640x480u */ {0xce,0x9f,0x9f,0x92,0xa4,0x16,0x00,0x28,0x5a,0x00,0x04,0xff,0xff,0x29,0x39}, /* 1280x1024-75 */ {0x09,0xc7,0xc7,0x0d,0xd2,0x0a,0x01,0xe0,0x10,0xb0,0x04,0xaf,0xaf,0xe1,0x1f} /* 1600x1200-60 */ }; /* Initialize a display mode on 5597/5598, 6326 and 530/620 */ static Bool SISInit(ScrnInfoPtr pScrn, DisplayModePtr mode) { SISPtr pSiS = SISPTR(pScrn); SISRegPtr pReg = &pSiS->ModeReg; UChar temp; int mclk = pSiS->MemClock; int clock = mode->Clock; int width = mode->HDisplay; int height = mode->VDisplay; int rate = (int)SiSCalcVRate(mode); int buswidth = pSiS->BusWidth; unsigned int vclk[5]; UShort CRT_CPUthresholdLow, CRT_CPUthresholdHigh, CRT_ENGthreshold; double a, b, c; int d, factor, offset, fixsync = 1; int num, denum, div, sbit, scale; Bool sis6326tvmode, sis6326himode; /* Save the registers for further processing */ (*pSiS->SiSSave)(pScrn, pReg); /* Initialise the standard VGA registers */ if(!pSiS->UseVESA) { if(!SiSVGAInit(pScrn, mode, fixsync)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SISInit: SiSVGAInit() failed\n"); return FALSE; } } /* Determine if chosen mode is suitable for TV on the 6326 * and if the mode is one of our special hi-res modes. */ sis6326tvmode = FALSE; sis6326himode = FALSE; if(pSiS->Chipset == PCI_CHIP_SIS6326) { if(pSiS->SiS6326Flags & SIS6326_HASTV) { if((pSiS->SiS6326Flags & SIS6326_TVDETECTED) && ((strcmp(mode->name, "PAL800x600") == 0) || /* Special TV modes */ (strcmp(mode->name, "PAL800x600U") == 0) || (strcmp(mode->name, "PAL720x540") == 0) || (strcmp(mode->name, "PAL640x480") == 0) || (strcmp(mode->name, "NTSC640x480") == 0) || (strcmp(mode->name, "NTSC640x480U") == 0) || (strcmp(mode->name, "NTSC640x400") == 0))) { sis6326tvmode = TRUE; } else { pReg->sis6326tv[0x00] &= 0xfb; } } if((strcmp(mode->name, "SIS1280x1024-75") == 0) || /* Special high-res modes */ (strcmp(mode->name, "SIS1600x1200-60") == 0)) { sis6326himode = TRUE; } } #ifdef UNLOCK_ALWAYS outSISIDXREG(SISSR, 0x05, 0x86); #endif if(!pSiS->UseVESA) { pReg->sisRegs3C4[0x06] &= 0x01; } /* set interlace */ if(!(mode->Flags & V_INTERLACE)) { offset = pSiS->CurrentLayout.displayWidth >> 3; } else { offset = pSiS->CurrentLayout.displayWidth >> 2; if(!pSiS->UseVESA) { pReg->sisRegs3C4[0x06] |= 0x20; } } /* Enable Linear and Enhanced Gfx Mode */ if(!pSiS->UseVESA) { pReg->sisRegs3C4[0x06] |= 0x82; } /* Enable MMIO at PCI Register 14H (D[6:5]: 11) */ if(pSiS->oldChipset >= OC_SIS5597) { pReg->sisRegs3C4[0x0B] |= 0x60; } else { pReg->sisRegs3C4[0x0B] |= 0x20; pReg->sisRegs3C4[0x0B] &= ~0x40; } if(!pSiS->UseVESA) { /* Enable 32bit mem access (D7), read-ahead cache (D5) */ pReg->sisRegs3C4[0x0C] |= 0x80; if(pSiS->oldChipset > OC_SIS6225) { pReg->sisRegs3C4[0x0C] |= 0x20; } /* Some speed-up stuff */ switch(pSiS->Chipset) { case PCI_CHIP_SIS5597: /* enable host bus */ if(!pSiS->HostBus) { pReg->sisRegs3C4[0x34] &= ~0x08; } else { pReg->sisRegs3C4[0x34] |= 0x08; } /* fall through */ case PCI_CHIP_SIS6326: case PCI_CHIP_SIS530: /* Enable "dual segment register mode" (D2) and "i/o gating while * write buffer is not empty" (D3) */ pReg->sisRegs3C4[0x0B] |= 0x0C; } /* set colordepth */ if(pSiS->Chipset == PCI_CHIP_SIS530) { pReg->sisRegs3C4[0x09] &= 0x7F; } switch(pSiS->CurrentLayout.bitsPerPixel) { case 8: break; case 16: offset <<= 1; if(pSiS->CurrentLayout.depth == 15) pReg->sisRegs3C4[0x06] |= 0x04; else pReg->sisRegs3C4[0x06] |= 0x08; break; case 24: offset += (offset << 1); pReg->sisRegs3C4[0x06] |= 0x10; pReg->sisRegs3C4[0x0B] |= 0x90; break; case 32: if(pSiS->Chipset == PCI_CHIP_SIS530) { offset <<= 2; if(pSiS->oldChipset != OC_SIS620) { pReg->sisRegs3C4[0x06] |= 0x10; } pReg->sisRegs3C4[0x0B] |= 0x90; pReg->sisRegs3C4[0x09] |= 0x80; } else return FALSE; break; } } /* save screen pitch for acceleration functions */ pSiS->scrnOffset = pSiS->CurrentLayout.displayWidth * ((pSiS->CurrentLayout.bitsPerPixel + 7) / 8); /* Set accelerator dest color depth to 0 - not supported on 530/620 */ pSiS->DstColor = 0; if(!pSiS->UseVESA) { /* set linear framebuffer addresses */ switch(pScrn->videoRam) { case 512: temp = 0x00; break; case 1024: temp = 0x20; break; case 2048: temp = 0x40; break; case 4096: temp = 0x60; break; case 8192: temp = 0x80; break; default: temp = 0x20; } pReg->sisRegs3C4[0x20] = (pSiS->FbAddress & 0x07F80000) >> 19; pReg->sisRegs3C4[0x21] = ((pSiS->FbAddress & 0xF8000000) >> 27) | temp; /* Set screen offset */ pReg->sisRegs3D4[0x13] = offset & 0xFF; /* Set CR registers for our built-in TV and hi-res modes */ if((sis6326tvmode) || (sis6326himode)) { int index,i; /* We need our very private data for hi-res and TV modes */ if(sis6326himode) { if(strcmp(mode->name, "SIS1280x1024-75") == 0) index = 7; else index = 8; } else { if(pSiS->SiS6326Flags & SIS6326_TVPAL) { switch(width) { case 800: if((strcmp(mode->name, "PAL800x600U") == 0)) index = 4; else index = 0; break; case 720: index = 5; break; case 640: default: index = 1; } } else { switch(height) { case 400: index = 3; break; case 480: default: if((strcmp(mode->name, "NTSC640x480U") == 0)) index = 6; else index = 2; } } } for(i=0; i<=5; i++) { pReg->sisRegs3D4[i] = SiS6326CR[index][i]; } pReg->sisRegs3C4[0x12] = SiS6326CR[index][6]; pReg->sisRegs3D4[6] = SiS6326CR[index][7]; pReg->sisRegs3D4[7] = SiS6326CR[index][8]; pReg->sisRegs3D4[0x10] = SiS6326CR[index][9]; pReg->sisRegs3D4[0x11] = SiS6326CR[index][10]; pReg->sisRegs3D4[0x12] = SiS6326CR[index][11]; pReg->sisRegs3D4[0x15] = SiS6326CR[index][12]; pReg->sisRegs3D4[0x16] = SiS6326CR[index][13]; pReg->sisRegs3D4[9] &= ~0x20; pReg->sisRegs3D4[9] |= (SiS6326CR[index][14] & 0x20); pReg->sisRegs3C4[0x0A] = ((offset & 0xF00) >> 4) | (SiS6326CR[index][14] & 0x0f); } else { /* Set extended vertical overflow register */ pReg->sisRegs3C4[0x0A] = ( ((offset & 0xF00) >> 4) | (((mode->CrtcVTotal - 2) & 0x400) >> 10) | (((mode->CrtcVDisplay - 1) & 0x400) >> 9) | (((mode->CrtcVBlankStart - 1) & 0x400) >> 8) | (((mode->CrtcVSyncStart - fixsync) & 0x400) >> 7)); /* Set extended horizontal overflow register */ pReg->sisRegs3C4[0x12] &= 0xE0; pReg->sisRegs3C4[0x12] |= ( ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) | ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) | ((((mode->CrtcHBlankStart >> 3) - 1) & 0x100) >> 6) | ((((mode->CrtcHSyncStart >> 3) - fixsync)& 0x100) >> 5) | ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x40) >> 2)); } /* enable (or disable) line compare */ if(mode->CrtcVDisplay >= 1024) pReg->sisRegs3C4[0x38] |= 0x04; else pReg->sisRegs3C4[0x38] &= 0xFB; /* Enable (or disable) high speed DCLK (some 6326 and 530/620 only) */ if( ( (pSiS->Chipset == PCI_CHIP_SIS6326) && ( (pSiS->ChipRev == 0xd0) || (pSiS->ChipRev == 0xd1) || (pSiS->ChipRev == 0xd2) || (pSiS->ChipRev == 0x92) || (pSiS->Flags & A6326REVAB) ) ) || (pSiS->oldChipset > OC_SIS6326) ) { if( (pSiS->CurrentLayout.bitsPerPixel == 24) || (pSiS->CurrentLayout.bitsPerPixel == 32) || (mode->CrtcHDisplay >= 1280) ) pReg->sisRegs3C4[0x3E] |= 0x01; else pReg->sisRegs3C4[0x3E] &= 0xFE; } /* We use the internal VCLK */ pReg->sisRegs3C4[0x38] &= 0xFC; /* Programmable Clock */ pReg->sisRegs3C2 = inSISREG(SISMISCR) | 0x0C; #if 0 if(pSiS->oldChipset <= OC_SIS86202) { /* TODO: Handle SR07 for clock selection */ /* 86C201 does not even have a programmable clock... */ /* pReg->sisRegs3C4[0x07] &= 0x??; */ } #endif /* Set VCLK */ if((sis6326tvmode) || (sis6326himode)) { /* For our built-in modes, the calculation is not suitable */ if(sis6326himode) { if((strcmp(mode->name, "SIS1280x1024-75") == 0)) { pReg->sisRegs3C4[0x2A] = 0x5d; /* 1280x1024-75 */ pReg->sisRegs3C4[0x2B] = 0xa4; } else { pReg->sisRegs3C4[0x2A] = 0x59; /* 1600x1200-60 */ pReg->sisRegs3C4[0x2B] = 0xa3; } pReg->sisRegs3C4[0x13] &= ~0x40; } else { if(pSiS->SiS6326Flags & SIS6326_TVPAL) { /* PAL: 31.500 Mhz */ if((strcmp(mode->name, "PAL800x600U") == 0)) { pReg->sisRegs3C4[0x2A] = 0x46; pReg->sisRegs3C4[0x2B] = 0x49; } else { pReg->sisRegs3C4[0x2A] = 0xab; pReg->sisRegs3C4[0x2B] = 0xe9; } pReg->sisRegs3C4[0x13] &= ~0x40; } else { /* NTSC: 27.000 Mhz */ if((strcmp(mode->name, "NTSC640x480U") == 0)) { pReg->sisRegs3C4[0x2A] = 0x5a; pReg->sisRegs3C4[0x2B] = 0x65; } else { pReg->sisRegs3C4[0x2A] = 0x29; pReg->sisRegs3C4[0x2B] = 0xe2; } pReg->sisRegs3C4[0x13] |= 0x40; } } } else if(SiS_compute_vclk(clock, &num, &denum, &div, &sbit, &scale)) { pReg->sisRegs3C4[0x2A] = (num - 1) & 0x7f ; pReg->sisRegs3C4[0x2A] |= (div == 2) ? 0x80 : 0; pReg->sisRegs3C4[0x2B] = ((denum - 1) & 0x1f); pReg->sisRegs3C4[0x2B] |= (((scale -1) & 3) << 5); /* When setting VCLK, we should set SR13 first */ if(sbit) pReg->sisRegs3C4[0x13] |= 0x40; else pReg->sisRegs3C4[0x13] &= 0xBF; #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "2a: %x 2b: %x 13: %x clock %d\n", pReg->sisRegs3C4[0x2A], pReg->sisRegs3C4[0x2B], pReg->sisRegs3C4[0x13], clock); #endif } else { /* if SiS_compute_vclk cannot handle the requested clock, try sisCalcClock */ SiSCalcClock(pScrn, clock, 2, vclk); #define Midx 0 #define Nidx 1 #define VLDidx 2 #define Pidx 3 #define PSNidx 4 pReg->sisRegs3C4[0x2A] = (vclk[Midx] - 1) & 0x7f; pReg->sisRegs3C4[0x2A] |= ((vclk[VLDidx] == 2) ? 1 : 0) << 7; /* D[4:0]: denumerator */ pReg->sisRegs3C4[0x2B] = (vclk[Nidx] - 1) & 0x1f; if(vclk[Pidx] <= 4){ /* postscale 1,2,3,4 */ pReg->sisRegs3C4[0x2B] |= (vclk[Pidx] - 1) << 5; pReg->sisRegs3C4[0x13] &= 0xBF; } else { /* postscale 6,8 */ pReg->sisRegs3C4[0x2B] |= ((vclk[Pidx] / 2) - 1) << 5; pReg->sisRegs3C4[0x13] |= 0x40; } pReg->sisRegs3C4[0x2B] |= 0x80 ; /* gain for high frequency */ } /* High speed DAC */ if(clock > 135000) pReg->sisRegs3C4[0x07] |= 0x02; if(pSiS->oldChipset > OC_SIS6225) { /* 1 or 2 cycle DRAM (set by option FastVram) */ if(pSiS->newFastVram == -1) { if(pSiS->oldChipset == OC_SIS620) { /* Use different default on the 620 */ pReg->sisRegs3C4[0x34] |= 0x40; pReg->sisRegs3C4[0x34] &= ~0x80; } else { pReg->sisRegs3C4[0x34] |= 0x80; pReg->sisRegs3C4[0x34] &= ~0x40; } } else if(pSiS->newFastVram == 1) pReg->sisRegs3C4[0x34] |= 0xC0; else pReg->sisRegs3C4[0x34] &= ~0xC0; if(pSiS->oldChipset == OC_SIS620) { /* Enable SGRAM burst timing (= bit clear) on the 620 */ if(pSiS->Flags & SYNCDRAM) { pReg->sisRegs3C4[0x35] &= ~0x20; } else { pReg->sisRegs3C4[0x35] |= 0x20; } } } } /* VESA */ /* Logical line length */ pSiS->ValidWidth = TRUE; pReg->sisRegs3C4[0x27] &= 0xCF; if(pSiS->CurrentLayout.bitsPerPixel == 24) { /* "Invalid logical width" */ pReg->sisRegs3C4[0x27] |= 0x30; pSiS->ValidWidth = FALSE; } else { switch(pScrn->virtualX * (pSiS->CurrentLayout.bitsPerPixel >> 3)) { case 1024: pReg->sisRegs3C4[0x27] |= 0x00; break; case 2048: pReg->sisRegs3C4[0x27] |= 0x10; break; case 4096: pReg->sisRegs3C4[0x27] |= 0x20; break; default: /* Invalid logical width */ pReg->sisRegs3C4[0x27] |= 0x30; pSiS->ValidWidth = FALSE; break; } } /* Acceleration stuff */ if(!pSiS->NoAccel) { pReg->sisRegs3C4[0x27] |= 0x40; /* Enable engine programming registers */ if( (pSiS->TurboQueue) && /* Handle TurboQueue */ (pSiS->oldChipset > OC_SIS6225) && ( (pSiS->Chipset != PCI_CHIP_SIS530) || (pSiS->CurrentLayout.bitsPerPixel != 24) ) ) { pReg->sisRegs3C4[0x27] |= 0x80; /* Enable TQ */ if((pSiS->Chipset == PCI_CHIP_SIS530) || ((pSiS->Chipset == PCI_CHIP_SIS6326 && (pSiS->ChipRev == 0xd0 || pSiS->ChipRev == 0xd1 || pSiS->ChipRev == 0xd2 || pSiS->ChipRev == 0x92 || pSiS->ChipRev == 0x0a || pSiS->ChipRev == 0x1a || pSiS->ChipRev == 0x2a || pSiS->ChipRev == 0x0b || pSiS->ChipRev == 0x1b || pSiS->ChipRev == 0x2b) ) ) ) { /* pReg->sisRegs3C4[0x3D] |= 0x80; */ /* Queue is 62K (530/620 specs) */ pReg->sisRegs3C4[0x3D] &= 0x7F; /* Queue is 30K (530/620 specs) */ } /* Locate the TQ at the beginning of the last 64K block of * video RAM. The address is to be specified in 32K steps. */ pReg->sisRegs3C4[0x2C] = (pScrn->videoRam - 64) / 32; if(pSiS->Chipset != PCI_CHIP_SIS530) { /* 530/620: Reserved (don't touch) */ pReg->sisRegs3C4[0x3C] &= 0xFC; /* 6326: Queue is all for 2D */ } /* 5597: Must be 0 */ } else { pReg->sisRegs3C4[0x27] &= 0x7F; } } if(!pSiS->UseVESA) { /* No idea what this does. The Windows driver does it, so we do it as well */ if(pSiS->Chipset == PCI_CHIP_SIS6326) { if((pSiS->ChipRev == 0xd0) || (pSiS->ChipRev == 0xd1) || (pSiS->ChipRev == 0xd2) || (pSiS->ChipRev == 0x92) || (pSiS->Flags & A6326REVAB)) { if((pSiS->Flags & (SYNCDRAM | RAMFLAG)) == (SYNCDRAM | RAMFLAG)) { if(!(pReg->sisRegs3C4[0x0E] & 0x03)) { pReg->sisRegs3C4[0x3E] |= 0x02; } } } } /* Set memclock */ #if 0 /* We don't need to do this; the SetMClk option was not used since 4.0. */ if((pSiS->Chipset == PCI_CHIP_SIS5597) || (pSiS->Chipset == PCI_CHIP_SIS6326)) { if(pSiS->MemClock > 66000) { SiSCalcClock(pScrn, pSiS->MemClock, 1, vclk); pReg->sisRegs3C4[0x28] = (vclk[Midx] - 1) & 0x7f ; pReg->sisRegs3C4[0x28] |= ((vclk[VLDidx] == 2 ) ? 1 : 0 ) << 7 ; pReg->sisRegs3C4[0x29] = (vclk[Nidx] -1) & 0x1f ; /* bits [4:0] contain denumerator -MC */ if(vclk[Pidx] <= 4) { pReg->sisRegs3C4[0x29] |= (vclk[Pidx] - 1) << 5 ; /* postscale 1,2,3,4 */ pReg->sisRegs3C4[0x13] &= 0x7F; } else { pReg->sisRegs3C4[0x29] |= ((vclk[Pidx] / 2) - 1) << 5 ; /* postscale 6,8 */ pReg->sisRegs3C4[0x13] |= 0x80; } /* Check programmed memory clock. Enable only to check the above code */ /* mclk = 14318 * ((pReg->sisRegs3C4[0x28] & 0x7f) + 1); mclk /= ((pReg->sisRegs3C4[0x29] & 0x0f) + 1); if(!(pReg->sisRegs3C4[0x13] & 0x80)) { mclk /= (((pReg->sisRegs3C4[0x29] & 0x60) >> 5) + 1); } else { if((pReg->sisRegs3C4[0x29] & 0x60) == 0x40) mclk /= 6; if((pReg->sisRegs3C4[0x29] & 0x60) == 0x60) mclk /= 8; } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,2, "Setting memory clock to %.3f MHz\n", mclk/1000.0); */ } } #endif /* Set threshold values */ /* * CPU/CRT Threshold: FIFO * MCLK ___________ VCLK * cpu/engine <---o o--------->|___________| -----------> CRT * ^ ^ ^ ^ * \ / | | * \ / |< gap >| * \ / | | * selector switch Thrsh. low high * * CRT consumes the data in the FIFO during scanline display. When the * amount of data in the FIFO reaches the Threshold low value, the selector * switch will switch to the right, and the FIFO will be refilled with data. * When the amount of data in the FIFO reaches the Threshold high value, the * selector switch will switch to the left and allows the CPU and the chip * engines to access the video RAM. * * The Threshold low values should be increased at higher bpps, simply because * there is more data needed for the CRT. When Threshold low and high are very * close to each other, the selector switch will be activated more often, which * decreases performance. * */ switch(pSiS->Chipset) { case PCI_CHIP_SIS5597: factor = 65; break; case PCI_CHIP_SIS6326: factor = 30; break; case PCI_CHIP_SIS530: factor = (pSiS->Flags & UMA) ? 60 : 30; break; default: factor = (pScrn->videoRam > 1024) ? 24 : 12; } a = width * height * rate * 1.40 * factor * ((pSiS->CurrentLayout.bitsPerPixel + 1) / 8); b = (mclk / 1000) * 999488.0 * (buswidth / 8); c = ((a / b) + 1.0) / 2; d = (int)c + 2; CRT_CPUthresholdLow = d; if((pSiS->Flags & (RAMFLAG | SYNCDRAM)) == (RAMFLAG | SYNCDRAM)) { CRT_CPUthresholdLow += 2; } CRT_CPUthresholdHigh = CRT_CPUthresholdLow + 3; CRT_ENGthreshold = 0x0F; #if 0 /* See comment in sis_dac.c on why this is commented */ if(pSiS->Chipset == PCI_CHIP_SIS530) { if((pSiS->oldChipset == OC_SIS530A) && (pSiS->Flags & UMA) && (mclk == 100000) && (pSiS->Flags & ESS137xPRESENT)) { if(!(pSiS->Flags & SECRETFLAG)) index = 0; if((temp = SiS_CalcSpecial530Threshold(pSiS, mode, index)) { CRT_CPUthresholdLow = temp; break; } } } #endif switch(pSiS->Chipset) { case PCI_CHIP_SIS530: if(CRT_CPUthresholdLow > 0x1f) CRT_CPUthresholdLow = 0x1f; CRT_CPUthresholdHigh = 0x1f; break; case PCI_CHIP_SIS5597: case PCI_CHIP_SIS6326: default: if(CRT_CPUthresholdLow > 0x0f) CRT_CPUthresholdLow = 0x0f; if(CRT_CPUthresholdHigh > 0x0f) CRT_CPUthresholdHigh = 0x0f; } pReg->sisRegs3C4[0x08] = ((CRT_CPUthresholdLow & 0x0F) << 4) | (CRT_ENGthreshold & 0x0F); pReg->sisRegs3C4[0x09] &= 0xF0; pReg->sisRegs3C4[0x09] |= (CRT_CPUthresholdHigh & 0x0F); pReg->sisRegs3C4[0x3F] &= 0xEB; pReg->sisRegs3C4[0x3F] |= ((CRT_CPUthresholdHigh & 0x10) | ((CRT_CPUthresholdLow & 0x10) >> 2)); if(pSiS->oldChipset >= OC_SIS530A) { pReg->sisRegs3C4[0x3F] &= 0xDF; pReg->sisRegs3C4[0x3F] |= 0x58; } /* Set SiS6326 TV registers */ if((pSiS->Chipset == PCI_CHIP_SIS6326) && (sis6326tvmode)) { UChar tmp; int index=0, i, j, k; int fsc; if(pSiS->SiS6326Flags & SIS6326_TVPAL) { pReg->sisRegs3C4[0x0D] |= 0x04; switch(width) { case 800: if((strcmp(mode->name, "PAL800x600U") == 0)) index = 4; else index = 3; break; case 720: index = 5; break; case 640: default: index = 2; } for(i=0; i<14; i++) { pReg->sis6326tv[SiS6326TVRegs1[i]] = SiS6326TVRegs1_PAL[index][i]; } fsc = (SiS6326TVRegs1_PAL[index][2] << 16) | (SiS6326TVRegs1_PAL[index][3] << 8) | (SiS6326TVRegs1_PAL[index][4]); } else { pReg->sisRegs3C4[0x0D] &= ~0x04; if((strcmp(mode->name, "NTSC640x480U") == 0)) index = 5; else index = 4; for(i=0; i<14; i++) { pReg->sis6326tv[SiS6326TVRegs1[i]] = SiS6326TVRegs1_NTSC[index][i]; } fsc = (SiS6326TVRegs1_NTSC[index][2] << 16) | (SiS6326TVRegs1_NTSC[index][3] << 8) | (SiS6326TVRegs1_NTSC[index][4]); } if(pSiS->sis6326fscadjust) { fsc += pSiS->sis6326fscadjust; pReg->sis6326tv[2] = (fsc >> 16) & 0xff; pReg->sis6326tv[3] = (fsc >> 8) & 0xff; pReg->sis6326tv[4] = fsc & 0xff; } tmp = pReg->sis6326tv[0x43]; if(pSiS->SiS6326Flags & SIS6326_TVCVBS) tmp |= 0x10; tmp |= 0x08; pReg->sis6326tv[0x43] = tmp; j = 0; k = 0; for(i=0; i<=0x44; i++) { if(SiS6326TVRegs1[j] == i) { j++; continue; } if(pSiS->SiS6326Flags & SIS6326_TVPAL) { tmp = SiS6326TVRegs2_PAL[index][k]; } else { tmp = SiS6326TVRegs2_NTSC[index][k]; } pReg->sis6326tv[i] = tmp; k++; } pReg->sis6326tv[0x43] |= 0x08; if((pSiS->ChipRev == 0xc1) || (pSiS->ChipRev == 0xc2)) { pReg->sis6326tv[0x43] &= ~0x08; } tmp = pReg->sis6326tv[0]; tmp |= 0x18; if(pSiS->SiS6326Flags & SIS6326_TVCVBS) tmp &= ~0x10; if(pSiS->SiS6326Flags & SIS6326_TVSVIDEO) tmp &= ~0x08; tmp |= 0x04; pReg->sis6326tv[0] = tmp; } } /* VESA */ return TRUE; } /* Init a mode for SiS 300, 315, 330, 340 series * This function is now only used for setting up some * variables (eg. scrnOffset). */ Bool SIS300Init(ScrnInfoPtr pScrn, DisplayModePtr mode) { SISPtr pSiS = SISPTR(pScrn); SISRegPtr pReg = &pSiS->ModeReg; UShort temp; DisplayModePtr realmode = mode; PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SIS300Init()\n")); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "virtualX = %d depth = %d Logical width = %d\n", pScrn->virtualX, pSiS->CurrentLayout.bitsPerPixel, pScrn->virtualX * pSiS->CurrentLayout.bitsPerPixel/8); #ifdef SISMERGED if(pSiS->MergedFB) { realmode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1; } #endif /* Copy current register settings to structure */ (*pSiS->SiSSave)(pScrn, pReg); /* Calculate Offset/Display Pitch */ pSiS->scrnOffset = pSiS->CurrentLayout.displayWidth * ((pSiS->CurrentLayout.bitsPerPixel + 7) / 8); pSiS->scrnPitch = pSiS->scrnPitch2 = pSiS->scrnOffset; if(!(pSiS->VBFlags & CRT1_LCDA)) { if(realmode->Flags & V_INTERLACE) pSiS->scrnPitch <<= 1; } /* CRT2 mode can never be interlaced */ #ifdef UNLOCK_ALWAYS outSISIDXREG(SISSR, 0x05, 0x86); #endif switch(pSiS->CurrentLayout.bitsPerPixel) { case 8: pSiS->DstColor = 0x0000; pSiS->SiS310_AccelDepth = 0x00000000; break; case 16: if(pSiS->CurrentLayout.depth == 15) pSiS->DstColor = (short) 0x4000; else pSiS->DstColor = (short) 0x8000; pSiS->SiS310_AccelDepth = 0x00010000; break; case 32: pSiS->DstColor = (short) 0xC000; pSiS->SiS310_AccelDepth = 0x00020000; break; } /* Enable PCI LINEAR ADDRESSING (0x80), MMIO (0x01), PCI_IO (0x20) */ pReg->sisRegs3C4[0x20] = 0xA1; /* Now initialize TurboQueue. TB is always located at the very top of * the videoRAM (notably NOT the x framebuffer memory, which can/should * be limited by MaxXFbMem when using DRI). Also, enable the accelerators. */ if(!pSiS->NoAccel) { pReg->sisRegs3C4[0x1E] |= 0x42; /* Enable 2D accelerator */ pReg->sisRegs3C4[0x1E] |= 0x18; /* Enable 3D accelerator */ switch(pSiS->VGAEngine) { case SIS_300_VGA: if(pSiS->TurboQueue) { /* set Turbo Queue as 512k */ temp = ((pScrn->videoRam/64)-8); /* 8=512k, 4=256k, 2=128k, 1=64k */ pReg->sisRegs3C4[0x26] = temp & 0xFF; pReg->sisRegs3C4[0x27] = (pReg->sisRegs3C4[0x27] & 0xfc) | (((temp >> 8) & 3) | 0xF0); } /* line above new for saving D2&3 of status register */ break; case SIS_315_VGA: #ifndef SISVRAMQ /* See comments in sis_driver.c */ pReg->sisRegs3C4[0x27] = 0x1F; pReg->sisRegs3C4[0x26] = 0x22; pReg->sisMMIO85C0 = (pScrn->videoRam - 512) * 1024; #endif break; } } return TRUE; } static void SiS6326TVDelay(ScrnInfoPtr pScrn, int delay) { SISPtr pSiS = SISPTR(pScrn); int i; UChar temp; for(i=0; iSiS6326Flags &= (SIS6326_HASTV | SIS6326_TVPAL); temp = SiS6326GetTVReg(pScrn, 0x43); temp &= 0xfb; SiS6326SetTVReg(pScrn, 0x43, temp); result = SIS6326DoSense(pScrn, 0x01, 0xb0, 0x06, SIS6326_TVSVIDEO); /* 0x02 */ pSiS->SiS6326Flags |= result; result = SIS6326DoSense(pScrn, 0x01, 0xa0, 0x01, SIS6326_TVCVBS); /* 0x04 */ pSiS->SiS6326Flags |= result; temp = SiS6326GetTVReg(pScrn, 0x43); temp &= 0xfb; SiS6326SetTVReg(pScrn, 0x43, temp); if(pSiS->SiS6326Flags & (SIS6326_TVSVIDEO | SIS6326_TVCVBS)) { pSiS->SiS6326Flags |= SIS6326_TVDETECTED; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "SiS6326: Detected TV connected to %s output\n", (((pSiS->SiS6326Flags & (SIS6326_TVSVIDEO | SIS6326_TVCVBS)) == (SIS6326_TVSVIDEO | SIS6326_TVCVBS)) ? "both SVIDEO and COMPOSITE" : ((pSiS->SiS6326Flags & SIS6326_TVSVIDEO) ? "SVIDEO" : "COMPOSITE"))); } else { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "SiS6326: No TV detected\n"); } } static Bool SISIsUMC(SISPtr pSiS) { UShort p4_0f, p4_25, p4_27, temp; inSISIDXREG(SISPART4, 0x0f, p4_0f); inSISIDXREG(SISPART4, 0x25, p4_25); inSISIDXREG(SISPART4, 0x27, p4_27); andSISIDXREG(SISPART4, 0x0f, 0x7f); orSISIDXREG(SISPART4, 0x25, 0x08); andSISIDXREG(SISPART4, 0x27, 0xfd); inSISIDXREG(SISPART4, 0x26, temp); outSISIDXREG(SISPART4, 0x27, p4_27); outSISIDXREG(SISPART4, 0x25, p4_25); outSISIDXREG(SISPART4, 0x0f, p4_0f); return((temp & 0x08) ? TRUE : FALSE); } /* Detect video bridge and set VBFlags accordingly */ void SISVGAPreInit(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); int temp,temp1,temp2,sistypeidx; int upperlimitlvds, lowerlimitlvds; int upperlimitch, lowerlimitch; int chronteltype, chrontelidreg, upperlimitvb; static const char *detectvb = "Detected SiS%s video bridge (%s, ID %d; Rev 0x%x)\n"; #if 0 UChar sr17=0; #endif static const char *ChrontelTypeStr[] = { "7004", "7005", "7007", "7006", "7008", "7013", "7019", "7020", "(unknown)" }; static const char *SiSVBTypeStr[] = { "301", /* 0 */ "301B", /* 1 */ "301B-DH", /* 2 */ "301LV", /* 3 */ "302LV", /* 4 */ "301C", /* 5 */ "302ELV", /* 6 */ "302B" /* 7 */ }; switch(pSiS->Chipset) { case PCI_CHIP_SIS300: case PCI_CHIP_SIS540: case PCI_CHIP_SIS630: case PCI_CHIP_SIS550: case PCI_CHIP_SIS315: case PCI_CHIP_SIS315H: case PCI_CHIP_SIS315PRO: case PCI_CHIP_SIS650: case PCI_CHIP_SIS330: case PCI_CHIP_SIS660: case PCI_CHIP_SIS340: case PCI_CHIP_XGIXG20: case PCI_CHIP_XGIXG40: pSiS->ModeInit = SIS300Init; break; default: pSiS->ModeInit = SISInit; } if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) { UChar sr0d; inSISIDXREG(SISSR, 0x0d, sr0d); if(sr0d & 0x04) { pSiS->SiS6326Flags |= SIS6326_TVPAL; } SISSense6326(pScrn); } pSiS->VBFlags = pSiS->VBFlags2 = 0; /* reset VBFlags */ pSiS->SiS_Pr->SiS_UseLCDA = FALSE; pSiS->SiS_Pr->Backup = FALSE; /* Videobridges only available for 300/315/330/340 series */ if((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA)) return; /* No video bridge ever on XGI Z7 (XG20) */ if(pSiS->ChipType == XGI_20) return; inSISIDXREG(SISPART4, 0x00, temp); temp &= 0x0F; if(temp == 1) { inSISIDXREG(SISPART4, 0x01, temp1); temp1 &= 0xff; if(temp1 >= 0xC0) { if(SISIsUMC(pSiS)) pSiS->VBFlags2 |= VB2_SISUMC; } if(temp1 >= 0xE0) { inSISIDXREG(SISPART4, 0x39, temp2); if(temp2 == 0xff) { pSiS->VBFlags2 |= VB2_302LV; sistypeidx = 4; } else { pSiS->VBFlags2 |= VB2_301C; /* VB_302ELV; */ sistypeidx = 5; /* 6; */ } } else if(temp1 >= 0xD0) { pSiS->VBFlags2 |= VB2_301LV; sistypeidx = 3; } else if(temp1 >= 0xC0) { pSiS->VBFlags2 |= VB2_301C; sistypeidx = 5; } else if(temp1 >= 0xB0) { pSiS->VBFlags2 |= VB2_301B; sistypeidx = 1; inSISIDXREG(SISPART4, 0x23, temp2); if(!(temp2 & 0x02)) { pSiS->VBFlags2 |= VB2_30xBDH; sistypeidx = 2; } } else { pSiS->VBFlags2 |= VB2_301; sistypeidx = 0; } xf86DrvMsg(pScrn->scrnIndex, X_PROBED, detectvb, SiSVBTypeStr[sistypeidx], (pSiS->VBFlags2 & VB2_SISUMC) ? "UMC-0" : "Charter/UMC-1", 1, temp1); SISSense30x(pScrn, FALSE); } else if(temp == 2) { inSISIDXREG(SISPART4, 0x01, temp1); temp1 &= 0xff; if(temp1 >= 0xC0) { if(SISIsUMC(pSiS)) pSiS->VBFlags2 |= VB2_SISUMC; } if(temp1 >= 0xE0) { pSiS->VBFlags2 |= VB2_302LV; sistypeidx = 4; } else if(temp1 >= 0xD0) { pSiS->VBFlags2 |= VB2_301LV; sistypeidx = 3; } else { pSiS->VBFlags2 |= VB2_302B; sistypeidx = 7; } xf86DrvMsg(pScrn->scrnIndex, X_PROBED, detectvb, SiSVBTypeStr[sistypeidx], (pSiS->VBFlags2 & VB2_SISUMC) ? "UMC-0" : "Charter/UMC-1", 2, temp1); SISSense30x(pScrn, FALSE); } else if (temp == 3) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, detectvb, "303", "unsupported, unknown", temp, 0); } else { if(pSiS->NewCRLayout) { inSISIDXREG(SISCR, 0x38, temp); temp = (temp >> 5) & 0x07; } else { inSISIDXREG(SISCR, 0x37, temp); temp = (temp >> 1) & 0x07; } if(pSiS->VGAEngine == SIS_300_VGA) { lowerlimitlvds = 2; upperlimitlvds = 4; lowerlimitch = 4; upperlimitch = 5; chronteltype = 1; chrontelidreg = 0x25; upperlimitvb = upperlimitlvds; } else { lowerlimitlvds = 2; upperlimitlvds = 3; lowerlimitch = 3; upperlimitch = 3; chronteltype = 2; chrontelidreg = 0x4b; upperlimitvb = upperlimitlvds; if(pSiS->NewCRLayout) { upperlimitvb = 4; } } if((temp >= lowerlimitlvds) && (temp <= upperlimitlvds)) { pSiS->VBFlags2 |= VB2_LVDS; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected LVDS transmitter (External chip ID %d)\n", temp); } if((temp >= lowerlimitch) && (temp <= upperlimitch)) { /* Set global for init301.c */ pSiS->SiS_Pr->SiS_IF_DEF_CH70xx = chronteltype; if(chronteltype == 1) { /* Set general purpose IO for Chrontel communication */ SiS_SetChrontelGPIO(pSiS->SiS_Pr, 0x9c); } /* Read Chrontel version number */ temp1 = SiS_GetCH70xx(pSiS->SiS_Pr, chrontelidreg); if(chronteltype == 1) { /* See Chrontel TB31 for explanation */ temp2 = SiS_GetCH700x(pSiS->SiS_Pr, 0x0e); if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) { SiS_SetCH700x(pSiS->SiS_Pr, 0x0e, 0x0b); SiS_DDC2Delay(pSiS->SiS_Pr, 300); } temp2 = SiS_GetCH70xx(pSiS->SiS_Pr, chrontelidreg); if(temp2 != temp1) temp1 = temp2; } if(temp1 == 0xFFFF) { /* 0xFFFF = error reading DDC port */ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Detected Chrontel 70xx, but encountered error reading I2C port\n"); andSISIDXREG(SISCR, 0x32, ~0x07); pSiS->postVBCR32 &= ~0x07; } else if((temp1 >= 0x19) && (temp1 <= 200)) { /* We only support device ids 0x19-200; other values may indicate DDC problems */ pSiS->VBFlags2 |= VB2_CHRONTEL; switch (temp1) { case 0x32: temp2 = 0; pSiS->ChrontelType = CHRONTEL_700x; break; case 0x3A: temp2 = 1; pSiS->ChrontelType = CHRONTEL_700x; break; case 0x50: temp2 = 2; pSiS->ChrontelType = CHRONTEL_700x; break; case 0x2A: temp2 = 3; pSiS->ChrontelType = CHRONTEL_700x; break; case 0x40: temp2 = 4; pSiS->ChrontelType = CHRONTEL_700x; break; case 0x22: temp2 = 5; pSiS->ChrontelType = CHRONTEL_700x; break; case 0x19: temp2 = 6; pSiS->ChrontelType = CHRONTEL_701x; break; case 0x20: temp2 = 7; pSiS->ChrontelType = CHRONTEL_701x; break; /* ID for 7020? */ default: temp2 = 8; pSiS->ChrontelType = CHRONTEL_701x; break; } xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Chrontel %s TV encoder (ID 0x%02x; chip ID %d)\n", ChrontelTypeStr[temp2], temp1, temp); /* Sense connected TV's */ SISSenseChrontel(pScrn, FALSE); } else if(temp1 == 0) { /* This indicates a communication problem, but it only occures if there * is no TV attached. So we don't use TV in this case. */ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected Chrontel TV encoder in promiscuous state (DDC/I2C mix-up)\n"); andSISIDXREG(SISCR, 0x32, ~0x07); pSiS->postVBCR32 &= ~0x07; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chrontel: Unsupported device id (%d) detected\n",temp1); andSISIDXREG(SISCR, 0x32, ~0x07); pSiS->postVBCR32 &= ~0x07; } if(chronteltype == 1) { /* Set general purpose IO for Chrontel communication */ SiS_SetChrontelGPIO(pSiS->SiS_Pr, 0x00); } } if((pSiS->NewCRLayout) && (temp == 4)) { pSiS->VBFlags2 |= VB2_CONEXANT; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Conexant video bridge - UNSUPPORTED\n"); } if((pSiS->VGAEngine == SIS_300_VGA) && (temp == 3)) { pSiS->VBFlags2 |= VB2_TRUMPION; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Trumpion Zurac (I/II/III) LVDS scaler\n"); } if(temp > upperlimitvb) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Detected unknown bridge type (%d)\n", temp); } } /* Old BIOSes store the detected CRT2 type in SR17, 16 and 13 * instead of CR32. However, since our detection routines * store their results to CR32, we now copy the * remaining bits (for LCD and VGA) to CR32 for unified usage. * SR17[0] CRT1 [1] LCD [2] TV [3] VGA2 * [4] AVIDEO [5] SVIDEO * SR13[0] SCART [1] HiVision * SR16[5] PAL/NTSC [6] LCD-SCALE [7] OVERSCAN */ #if 0 inSISIDXREG(SISSR, 0x17, sr17); if( (pSiS->VGAEngine == SIS_300_VGA) && (pSiS->Chipset != PCI_CHIP_SIS300) && (sr17 & 0x0F) ) { UChar cr32; inSISIDXREG(SISCR, 0x32, cr32); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Converting SR17 (%02x) to CR32 (%02x)\n", sr17, cr32); if(sr17 & 0x01) { /* CRT1 */ orSISIDXREG(SISCR, 0x32, 0x20); pSiS->postVBCR32 |= 0x20; } else { andSISIDXREG(SISCR, 0x32, ~0x20); pSiS->postVBCR32 &= ~0x20; } if(sr17 & 0x02) { /* LCD */ orSISIDXREG(SISCR, 0x32, 0x08); pSiS->postVBCR32 |= 0x08; } else { andSISIDXREG(SISCR, 0x32, ~0x08); pSiS->postVBCR32 &= ~0x08; } /* No Hivision, no DVI here */ andSISIDXREG(SISCR,0x32,~0xc0); pSiS->postVBCR32 &= ~0xc0; } #endif /* Try to find out if the bridge uses LCDA for low resolution and * text modes. If sisfb saved this for us, use it. Otherwise, * check if we are running on a low mode on LCD and read the * relevant registers ourselves. */ if(pSiS->VGAEngine == SIS_315_VGA) { if(pSiS->VBFlags2 & VB2_SISLCDABRIDGE) { if(pSiS->sisfblcda != 0xff) { if((pSiS->sisfblcda & 0x03) == 0x03) { pSiS->SiS_Pr->SiS_UseLCDA = TRUE; pSiS->ChipFlags |= SiSCF_UseLCDA; } } else { inSISIDXREG(SISCR,0x34,temp); if(temp <= 0x13) { inSISIDXREG(SISCR,0x38,temp); if((temp & 0x03) == 0x03) { pSiS->SiS_Pr->SiS_UseLCDA = TRUE; pSiS->ChipFlags |= SiSCF_UseLCDA; pSiS->SiS_Pr->Backup = TRUE; } else { orSISIDXREG(SISPART1,0x2f,0x01); /* Unlock CRT2 */ inSISIDXREG(SISPART1,0x13,temp); if(temp & 0x04) { pSiS->SiS_Pr->SiS_UseLCDA = TRUE; pSiS->ChipFlags |= SiSCF_UseLCDA; pSiS->SiS_Pr->Backup = TRUE; } } } } if(pSiS->ChipFlags & SiSCF_UseLCDA) { xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 3, "BIOS uses LCDA for low resolution and text modes\n"); if(pSiS->SiS_Pr->Backup == TRUE) { inSISIDXREG(SISCR,0x34,pSiS->SiS_Pr->Backup_Mode); inSISIDXREG(SISPART1,0x14,pSiS->SiS_Pr->Backup_14); inSISIDXREG(SISPART1,0x15,pSiS->SiS_Pr->Backup_15); inSISIDXREG(SISPART1,0x16,pSiS->SiS_Pr->Backup_16); inSISIDXREG(SISPART1,0x17,pSiS->SiS_Pr->Backup_17); inSISIDXREG(SISPART1,0x18,pSiS->SiS_Pr->Backup_18); inSISIDXREG(SISPART1,0x19,pSiS->SiS_Pr->Backup_19); inSISIDXREG(SISPART1,0x1a,pSiS->SiS_Pr->Backup_1a); inSISIDXREG(SISPART1,0x1b,pSiS->SiS_Pr->Backup_1b); inSISIDXREG(SISPART1,0x1c,pSiS->SiS_Pr->Backup_1c); inSISIDXREG(SISPART1,0x1d,pSiS->SiS_Pr->Backup_1d); } } } } } static void SiS_WriteAttr(SISPtr pSiS, int index, int value) { (void)inSISREG(SISINPSTAT); index |= 0x20; outSISREG(SISAR, index); outSISREG(SISAR, value); } static int SiS_ReadAttr(SISPtr pSiS, int index) { (void)inSISREG(SISINPSTAT); index |= 0x20; outSISREG(SISAR, index); return(inSISREG(SISARR)); } static void SiS_EnablePalette(SISPtr pSiS) { (void)inSISREG(SISINPSTAT); outSISREG(SISAR, 0x00); pSiS->VGAPaletteEnabled = TRUE; } static void SiS_DisablePalette(SISPtr pSiS) { (void)inSISREG(SISINPSTAT); outSISREG(SISAR, 0x20); pSiS->VGAPaletteEnabled = FALSE; } void SISVGALock(SISPtr pSiS) { orSISIDXREG(SISCR, 0x11, 0x80); /* Protect CRTC[0-7] */ } void SiSVGAUnlock(SISPtr pSiS) { andSISIDXREG(SISCR, 0x11, 0x7f); /* Unprotect CRTC[0-7] */ } #define SIS_FONTS_SIZE (8 * 8192) void SiSVGASaveFonts(ScrnInfoPtr pScrn) { #ifdef SIS_PC_PLATFORM SISPtr pSiS = SISPTR(pScrn); pointer vgaMemBase = pSiS->VGAMemBase; UChar miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn; if((pSiS->fonts) || (vgaMemBase == NULL)) return; /* If in graphics mode, don't save anything */ attr10 = SiS_ReadAttr(pSiS, 0x10); if(attr10 & 0x01) return; if(!(pSiS->fonts = xalloc(SIS_FONTS_SIZE * 2))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not save console fonts, mem allocation failed\n"); return; } /* 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(vgaMemBase, pSiS->fonts, SIS_FONTS_SIZE); /* 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(vgaMemBase, pSiS->fonts + SIS_FONTS_SIZE, SIS_FONTS_SIZE); 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); #endif } static void SiSVGASaveMode(ScrnInfoPtr pScrn, SISRegPtr save) { SISPtr pSiS = SISPTR(pScrn); int i; save->sisRegMiscOut = inSISREG(SISMISCR); for(i = 0; i < 25; i++) { inSISIDXREG(SISCR, i, save->sisRegs3D4[i]); } SiS_EnablePalette(pSiS); for(i = 0; i < 21; i++) { save->sisRegsATTR[i] = SiS_ReadAttr(pSiS, i); } SiS_DisablePalette(pSiS); for(i = 0; i < 9; i++) { inSISIDXREG(SISGR, i, save->sisRegsGR[i]); } for(i = 1; i < 5; i++) { inSISIDXREG(SISSR, i, save->sisRegs3C4[i]); } } static void SiSVGASaveColormap(ScrnInfoPtr pScrn, SISRegPtr save) { SISPtr pSiS = SISPTR(pScrn); int i; if(pSiS->VGACMapSaved) return; outSISREG(SISPEL, 0xff); outSISREG(SISCOLIDXR, 0x00); for(i = 0; i < 768; i++) { save->sisDAC[i] = inSISREG(SISCOLDATA); (void)inSISREG(SISINPSTAT); (void)inSISREG(SISINPSTAT); } SiS_DisablePalette(pSiS); pSiS->VGACMapSaved = TRUE; } void SiSVGASave(ScrnInfoPtr pScrn, SISRegPtr save, int flags) { if(save == NULL) return; if(flags & SISVGA_SR_CMAP) SiSVGASaveColormap(pScrn, save); if(flags & SISVGA_SR_MODE) SiSVGASaveMode(pScrn, save); if(flags & SISVGA_SR_FONTS) SiSVGASaveFonts(pScrn); } void SiSVGARestoreFonts(ScrnInfoPtr pScrn) { #ifdef SIS_PC_PLATFORM SISPtr pSiS = SISPTR(pScrn); pointer vgaMemBase = pSiS->VGAMemBase; UChar miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn; if((!pSiS->fonts) || (vgaMemBase == NULL)) return; /* 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, vgaMemBase, SIS_FONTS_SIZE); 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 + SIS_FONTS_SIZE, vgaMemBase, SIS_FONTS_SIZE); 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); #endif } static void SiSVGARestoreMode(ScrnInfoPtr pScrn, SISRegPtr restore) { SISPtr pSiS = SISPTR(pScrn); int i; outSISREG(SISMISCW, restore->sisRegMiscOut); for(i = 1; i < 5; i++) { outSISIDXREG(SISSR, i, restore->sisRegs3C4[i]); } outSISIDXREG(SISCR, 17, restore->sisRegs3D4[17] & ~0x80); for(i = 0; i < 25; i++) { outSISIDXREG(SISCR, i, restore->sisRegs3D4[i]); } for(i = 0; i < 9; i++) { outSISIDXREG(SISGR, i, restore->sisRegsGR[i]); } SiS_EnablePalette(pSiS); for(i = 0; i < 21; i++) { SiS_WriteAttr(pSiS, i, restore->sisRegsATTR[i]); } SiS_DisablePalette(pSiS); } static void SiSVGARestoreColormap(ScrnInfoPtr pScrn, SISRegPtr restore) { SISPtr pSiS = SISPTR(pScrn); int i; if(!pSiS->VGACMapSaved) return; outSISREG(SISPEL, 0xff); outSISREG(SISCOLIDX, 0x00); for(i = 0; i < 768; i++) { outSISREG(SISCOLDATA, restore->sisDAC[i]); (void)inSISREG(SISINPSTAT); (void)inSISREG(SISINPSTAT); } SiS_DisablePalette(pSiS); } void SiSVGARestore(ScrnInfoPtr pScrn, SISRegPtr restore, int flags) { if(restore == NULL) return; if(flags & SISVGA_SR_MODE) SiSVGARestoreMode(pScrn, restore); if(flags & SISVGA_SR_FONTS) SiSVGARestoreFonts(pScrn); if(flags & SISVGA_SR_CMAP) SiSVGARestoreColormap(pScrn, restore); } static void SiS_SeqReset(SISPtr pSiS, Bool start) { if(start) { outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ } else { outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ } } void SiSVGAProtect(ScrnInfoPtr pScrn, Bool on) { SISPtr pSiS = SISPTR(pScrn); UChar tmp; if(!pScrn->vtSema) return; if(on) { inSISIDXREG(SISSR, 0x01, tmp); SiS_SeqReset(pSiS, TRUE); /* start synchronous reset */ outSISIDXREG(SISSR, 0x01, tmp | 0x20); /* disable display */ SiS_EnablePalette(pSiS); } else { andSISIDXREG(SISSR, 0x01, ~0x20); /* enable display */ SiS_SeqReset(pSiS, FALSE); /* clear synchronous reset */ SiS_DisablePalette(pSiS); } } #ifdef SIS_PC_PLATFORM Bool SiSVGAMapMem(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); /* Map only once */ if(pSiS->VGAMemBase) return TRUE; if(pSiS->VGAMapSize == 0) pSiS->VGAMapSize = (64 * 1024); if(pSiS->VGAMapPhys == 0) pSiS->VGAMapPhys = 0xA0000; #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0) pSiS->VGAMemBase = xf86MapDomainMemory(pScrn->scrnIndex, VIDMEM_MMIO_32BIT, pSiS->PciTag, pSiS->VGAMapPhys, pSiS->VGAMapSize); #else pSiS->VGAMemBase = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO_32BIT, pSiS->VGAMapPhys, pSiS->VGAMapSize); #endif return(pSiS->VGAMemBase != NULL); } void SiSVGAUnmapMem(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); if(pSiS->VGAMemBase == NULL) return; xf86UnMapVidMem(pScrn->scrnIndex, pSiS->VGAMemBase, pSiS->VGAMapSize); pSiS->VGAMemBase = NULL; } #endif #if 0 static CARD32 SiS_HBlankKGA(DisplayModePtr mode, SISRegPtr regp, int nBits, unsigned int Flags) { int nExtBits = (nBits < 6) ? 0 : nBits - 6; CARD32 ExtBits; CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 6; regp->sisRegs3D4[3] = (regp->sisRegs3D4[3] & ~0x1F) | (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F); regp->sisRegs3D4[5] = (regp->sisRegs3D4[5] & ~0x80) | ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2); ExtBits = ((mode->CrtcHBlankEnd >> 3) - 1) & ExtBitMask; if( (Flags & SISKGA_FIX_OVERSCAN) && ((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3))) { int i = (regp->sisRegs3D4[3] & 0x1F) | ((regp->sisRegs3D4[5] & 0x80) >> 2) | ExtBits; if(Flags & SISKGA_ENABLE_ON_ZERO) { if( (i-- > (((mode->CrtcHBlankStart >> 3) - 1) & (0x3F | ExtBitMask))) && (mode->CrtcHBlankEnd == mode->CrtcHTotal) ) { i = 0; } } else if (Flags & SISKGA_BE_TOT_DEC) i--; regp->sisRegs3D4[3] = (regp->sisRegs3D4[3] & ~0x1F) | (i & 0x1F); regp->sisRegs3D4[5] = (regp->sisRegs3D4[5] & ~0x80) | ((i << 2) & 0x80); ExtBits = i & ExtBitMask; } return ExtBits >> 6; } #endif static CARD32 SiS_VBlankKGA(DisplayModePtr mode, SISRegPtr regp, int nBits, unsigned int Flags) { CARD32 nExtBits = (nBits < 8) ? 0 : (nBits - 8); CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 8; CARD32 ExtBits = (mode->CrtcVBlankEnd - 1) & ExtBitMask; CARD32 BitMask = (nBits < 7) ? 0 : ((1 << nExtBits) - 1); int VBlankStart = (mode->CrtcVBlankStart - 1) & 0xFF; regp->sisRegs3D4[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; if((Flags & SISKGA_FIX_OVERSCAN) && (mode->CrtcVBlankEnd == mode->CrtcVTotal)) { int i = regp->sisRegs3D4[22] | ExtBits; if(Flags & SISKGA_ENABLE_ON_ZERO) { if( ((BitMask && ((i & BitMask) > (VBlankStart & BitMask))) || ((i > VBlankStart) && /* 8-bit case */ ((i & 0x7F) > (VBlankStart & 0x7F)))) && /* 7-bit case */ (!(regp->sisRegs3D4[9] & 0x9F)) ) { /* 1 scanline/row */ i = 0; } else { i--; } } else if(Flags & SISKGA_BE_TOT_DEC) i--; regp->sisRegs3D4[22] = i & 0xFF; ExtBits = i & 0xFF00; } return (ExtBits >> 8); } Bool SiSVGAInit(ScrnInfoPtr pScrn, DisplayModePtr mode, int fixsync) { SISPtr pSiS = SISPTR(pScrn); SISRegPtr regp = &pSiS->ModeReg; int depth = pScrn->depth; unsigned int i; /* Sync */ if((mode->Flags & (V_PHSYNC | V_NHSYNC)) && (mode->Flags & (V_PVSYNC | V_NVSYNC))) { regp->sisRegMiscOut = 0x23; if(mode->Flags & V_NHSYNC) regp->sisRegMiscOut |= 0x40; if(mode->Flags & V_NVSYNC) regp->sisRegMiscOut |= 0x80; } else { int VDisplay = mode->VDisplay; if(mode->Flags & V_DBLSCAN) VDisplay *= 2; if(mode->VScan > 1) VDisplay *= mode->VScan; if(VDisplay < 400) regp->sisRegMiscOut = 0xA3; /* +hsync -vsync */ else if (VDisplay < 480) regp->sisRegMiscOut = 0x63; /* -hsync +vsync */ else if (VDisplay < 768) regp->sisRegMiscOut = 0xE3; /* -hsync -vsync */ else regp->sisRegMiscOut = 0x23; /* +hsync +vsync */ } regp->sisRegMiscOut |= (mode->ClockIndex & 0x03) << 2; /* Seq */ if(depth == 4) regp->sisRegs3C4[0] = 0x02; else regp->sisRegs3C4[0] = 0x00; if(mode->Flags & V_CLKDIV2) regp->sisRegs3C4[1] = 0x09; else regp->sisRegs3C4[1] = 0x01; regp->sisRegs3C4[2] = 0x0F; regp->sisRegs3C4[3] = 0x00; if(depth < 8) regp->sisRegs3C4[4] = 0x06; else regp->sisRegs3C4[4] = 0x0E; /* CRTC */ regp->sisRegs3D4[0] = (mode->CrtcHTotal >> 3) - 5; regp->sisRegs3D4[1] = (mode->CrtcHDisplay >> 3) - 1; regp->sisRegs3D4[2] = (mode->CrtcHBlankStart >> 3) - 1; regp->sisRegs3D4[3] = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80; i = (((mode->CrtcHSkew << 2) + 0x10) & ~0x1F); if(i < 0x80) regp->sisRegs3D4[3] |= i; regp->sisRegs3D4[4] = (mode->CrtcHSyncStart >> 3) - fixsync; regp->sisRegs3D4[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) | (((mode->CrtcHSyncEnd >> 3) - fixsync) & 0x1F); regp->sisRegs3D4[6] = (mode->CrtcVTotal - 2) & 0xFF; regp->sisRegs3D4[7] = (((mode->CrtcVTotal - 2) & 0x100) >> 8) | (((mode->CrtcVDisplay - 1) & 0x100) >> 7) | (((mode->CrtcVSyncStart - fixsync) & 0x100) >> 6) | (((mode->CrtcVBlankStart - 1) & 0x100) >> 5) | 0x10 | (((mode->CrtcVTotal - 2) & 0x200) >> 4) | (((mode->CrtcVDisplay - 1) & 0x200) >> 3) | (((mode->CrtcVSyncStart - fixsync) & 0x200) >> 2); regp->sisRegs3D4[8] = 0x00; regp->sisRegs3D4[9] = (((mode->CrtcVBlankStart - 1) & 0x200) >> 4) | 0x40; if(mode->Flags & V_DBLSCAN) regp->sisRegs3D4[9] |= 0x80; if(mode->VScan >= 32) regp->sisRegs3D4[9] |= 0x1F; else if (mode->VScan > 1) regp->sisRegs3D4[9] |= mode->VScan - 1; regp->sisRegs3D4[10] = 0x00; regp->sisRegs3D4[11] = 0x00; regp->sisRegs3D4[12] = 0x00; regp->sisRegs3D4[13] = 0x00; regp->sisRegs3D4[14] = 0x00; regp->sisRegs3D4[15] = 0x00; regp->sisRegs3D4[16] = (mode->CrtcVSyncStart - fixsync) & 0xFF; regp->sisRegs3D4[17] = ((mode->CrtcVSyncEnd - fixsync) & 0x0F) | 0x20; regp->sisRegs3D4[18] = (mode->CrtcVDisplay - 1) & 0xFF; regp->sisRegs3D4[19] = pScrn->displayWidth >> 4; regp->sisRegs3D4[20] = 0x00; regp->sisRegs3D4[21] = (mode->CrtcVBlankStart - 1) & 0xFF; regp->sisRegs3D4[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; if(depth < 8) regp->sisRegs3D4[23] = 0xE3; else regp->sisRegs3D4[23] = 0xC3; regp->sisRegs3D4[24] = 0xFF; #if 0 SiS_HBlankKGA(mode, regp, 0, SISKGA_FIX_OVERSCAN | SISKGA_ENABLE_ON_ZERO); #endif SiS_VBlankKGA(mode, regp, 0, SISKGA_FIX_OVERSCAN | SISKGA_ENABLE_ON_ZERO); /* GR */ regp->sisRegsGR[0] = 0x00; regp->sisRegsGR[1] = 0x00; regp->sisRegsGR[2] = 0x00; regp->sisRegsGR[3] = 0x00; regp->sisRegsGR[4] = 0x00; if(depth == 4) regp->sisRegsGR[5] = 0x02; else regp->sisRegsGR[5] = 0x40; regp->sisRegsGR[6] = 0x05; /* only map 64k VGA memory !!!! */ regp->sisRegsGR[7] = 0x0F; regp->sisRegsGR[8] = 0xFF; /* Attr */ for(i = 0; i <= 15; i++) { /* standard colormap translation */ regp->sisRegsATTR[i] = i; } if(depth == 4) regp->sisRegsATTR[16] = 0x81; else regp->sisRegsATTR[16] = 0x41; if(depth >= 4) regp->sisRegsATTR[17] = 0xFF; else regp->sisRegsATTR[17] = 0x01; regp->sisRegsATTR[18] = 0x0F; regp->sisRegsATTR[19] = 0x00; regp->sisRegsATTR[20] = 0x00; return TRUE; } static void SISVGABlankScreen(ScrnInfoPtr pScrn, Bool on) { SISPtr pSiS = SISPTR(pScrn); UChar tmp; inSISIDXREG(SISSR, 0x01, tmp); if(on) tmp &= ~0x20; else tmp |= 0x20; SiS_SeqReset(pSiS, TRUE); outSISIDXREG(SISSR, 0x01, tmp); SiS_SeqReset(pSiS, FALSE); } Bool SiSVGASaveScreen(ScreenPtr pScreen, int mode) { ScrnInfoPtr pScrn = NULL; Bool on = xf86IsUnblank(mode); if(pScreen == NULL) return FALSE; pScrn = xf86Screens[pScreen->myNum]; if(pScrn->vtSema) { SISVGABlankScreen(pScrn, on); } return TRUE; } #undef SIS_FONTS_SIZE