diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/video/sis/init301.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/video/sis/init301.c')
-rw-r--r-- | drivers/video/sis/init301.c | 12239 |
1 files changed, 12239 insertions, 0 deletions
diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c new file mode 100644 index 00000000000..2bc5b809791 --- /dev/null +++ b/drivers/video/sis/init301.c @@ -0,0 +1,12239 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Mode initializing code (CRT2 section) + * for SiS 300/305/540/630/730 and + * SiS 315/550/650/M650/651/661FX/M661xX/740/741(GX)/M741/330/660/M660/760/M760 + * (Universal module for Linux kernel framebuffer and XFree86/X.org 4.x) + * + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * 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 EXPRESSED 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 <thomas@winischhofer.net> + * + * Formerly based on non-functional code-fragements for 300 series by SiS, Inc. + * Used by permission. + * + * TW says: This code looks awful, I know. But please don't do anything about + * this otherwise debugging will be hell. + * The code is extremely fragile as regards the different chipsets, different + * video bridges and combinations thereof. If anything is changed, extreme + * care has to be taken that that change doesn't break it for other chipsets, + * bridges or combinations thereof. + * All comments in this file are by me, regardless if marked TW or not. + * + */ + +#if 1 +#define SET_EMI /* 302LV/ELV: Set EMI values */ +#endif + +#define COMPAL_HACK /* Needed for Compal 1400x1050 (EMI) */ +#define COMPAQ_HACK /* Needed for Inventec/Compaq 1280x1024 (EMI) */ +#define ASUS_HACK /* Needed for Asus A2H 1024x768 (EMI) */ + +#include "init301.h" + +#ifdef SIS300 +#include "oem300.h" +#endif + +#ifdef SIS315H +#include "oem310.h" +#endif + +#define SiS_I2CDELAY 1000 +#define SiS_I2CDELAYSHORT 150 + +static USHORT SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr); + +/*********************************************/ +/* HELPER: Lock/Unlock CRT2 */ +/*********************************************/ + +void +SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(HwInfo->jChipType >= SIS_315H) + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01); + else + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01); +} + +void +SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(HwInfo->jChipType >= SIS_315H) + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE); + else + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE); +} + +/*********************************************/ +/* HELPER: Write SR11 */ +/*********************************************/ + +static void +SiS_SetRegSR11ANDOR(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DataAND, USHORT DataOR) +{ + if(HwInfo->jChipType >= SIS_661) { + DataAND &= 0x0f; + DataOR &= 0x0f; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,DataAND,DataOR); +} + +/*********************************************/ +/* HELPER: Get Pointer to LCD structure */ +/*********************************************/ + +#ifdef SIS315H +static UCHAR * +GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + UCHAR *myptr = NULL; + USHORT romindex = 0, reg = 0, idx = 0; + + /* Use the BIOS tables only for LVDS panels; TMDS is unreliable + * due to the variaty of panels the BIOS doesn't know about. + * Exception: If the BIOS has better knowledge (such as in case + * of machines with a 301C and a panel that does not support DDC) + * use the BIOS data as well. + */ + + if((SiS_Pr->SiS_ROMNew) && + ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) || (!SiS_Pr->PanelSelfDetected))) { + + if(HwInfo->jChipType < SIS_661) reg = 0x3c; + else reg = 0x7d; + + idx = (SiS_GetReg(SiS_Pr->SiS_P3d4,reg) & 0x1f) * 26; + + if(idx < (8*26)) { + myptr = (UCHAR *)&SiS_LCDStruct661[idx]; + } + romindex = SISGETROMW(0x100); + if(romindex) { + romindex += idx; + myptr = &ROMAddr[romindex]; + } + } + return myptr; +} + +static USHORT +GetLCDStructPtr661_2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr = 0; + + /* Use the BIOS tables only for LVDS panels; TMDS is unreliable + * due to the variaty of panels the BIOS doesn't know about. + * Exception: If the BIOS has better knowledge (such as in case + * of machines with a 301C and a panel that does not support DDC) + * use the BIOS data as well. + */ + + if((SiS_Pr->SiS_ROMNew) && + ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) || (!SiS_Pr->PanelSelfDetected))) { + romptr = SISGETROMW(0x102); + romptr += ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) * SiS_Pr->SiS661LCD2TableSize); + } + + return(romptr); +} +#endif + +/*********************************************/ +/* Adjust Rate for CRT2 */ +/*********************************************/ + +static BOOLEAN +SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RRTI, USHORT *i, PSIS_HW_INFO HwInfo) +{ + USHORT checkmask=0,modeid,infoflag; + + modeid = SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + + checkmask |= SupportRAMDAC2; + if(HwInfo->jChipType >= SIS_315H) { + checkmask |= SupportRAMDAC2_135; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + checkmask |= SupportRAMDAC2_162; + if(SiS_Pr->SiS_VBType & VB_SIS301C) { + checkmask |= SupportRAMDAC2_202; + } + } + } + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + + checkmask |= SupportLCD; + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(modeid == 0x2e) checkmask |= Support64048060Hz; + } + } + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + + checkmask |= SupportHiVision; + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750|SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) { + + checkmask |= SupportTV; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + checkmask |= SupportTV1024; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + checkmask |= SupportYPbPr750p; + } + } + } + + } + + } else { /* LVDS */ + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + checkmask |= SupportCHTV; + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + checkmask |= SupportLCD; + } + + } + + /* Look backwards in table for matching CRT2 mode */ + for(; SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID == modeid; (*i)--) { + infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; + if(infoflag & checkmask) return TRUE; + if((*i) == 0) break; + } + + /* Look through the whole mode-section of the table from the beginning + * for a matching CRT2 mode if no mode was found yet. + */ + for((*i) = 0; ; (*i)++) { + if(SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID != modeid) break; + infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; + if(infoflag & checkmask) return TRUE; + } + return FALSE; +} + +/*********************************************/ +/* Get rate index */ +/*********************************************/ + +USHORT +SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo) +{ + SHORT LCDRefreshIndex[] = { 0x00, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00 }; + USHORT RRTI,i,backup_i; + USHORT modeflag,index,temp,backupindex; + + /* Do NOT check for UseCustomMode here, will skrew up FIFO */ + if(ModeNo == 0xfe) return 0; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(modeflag & HalfDCLK) return 0; + } + } + + if(ModeNo < 0x14) return 0xFFFF; + + index = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x33) >> SiS_Pr->SiS_SelectCRT2Rate) & 0x0F; + backupindex = index; + + if(index > 0) index--; + + if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_VBType & VB_NoLCD) index = 0; + else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index = backupindex = 0; + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) { + temp = LCDRefreshIndex[SiS_GetBIOSLCDResInfo(SiS_Pr)]; + if(index > temp) index = temp; + } + } + } else { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) index = 0; + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) index = 0; + } + } + } + + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + ModeNo = SiS_Pr->SiS_RefIndex[RRTI].ModeID; + + if(HwInfo->jChipType >= SIS_315H) { + if(!(SiS_Pr->SiS_VBInfo & DriverMode)) { + if( (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x105) || + (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x107) ) { + if(backupindex <= 1) RRTI++; + } + } + } + + i = 0; + do { + if(SiS_Pr->SiS_RefIndex[RRTI + i].ModeID != ModeNo) break; + temp = SiS_Pr->SiS_RefIndex[RRTI + i].Ext_InfoFlag; + temp &= ModeTypeMask; + if(temp < SiS_Pr->SiS_ModeType) break; + i++; + index--; + } while(index != 0xFFFF); + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + temp = SiS_Pr->SiS_RefIndex[RRTI + i - 1].Ext_InfoFlag; + if(temp & InterlaceMode) i++; + } + } + + i--; + + if((SiS_Pr->SiS_SetFlag & ProgrammingCRT2) && (!(SiS_Pr->SiS_VBInfo & DisableCRT2Display))) { + backup_i = i; + if(!(SiS_AdjustCRT2Rate(SiS_Pr, ModeNo, ModeIdIndex, RRTI, &i, HwInfo))) { + i = backup_i; + } + } + + return(RRTI + i); +} + +/*********************************************/ +/* STORE CRT2 INFO in CR34 */ +/*********************************************/ + +static void +SiS_SaveCRT2Info(SiS_Private *SiS_Pr, USHORT ModeNo) +{ + USHORT temp1,temp2; + + /* Store CRT1 ModeNo in CR34 */ + SiS_SetReg(SiS_Pr->SiS_P3d4,0x34,ModeNo); + temp1 = (SiS_Pr->SiS_VBInfo & SetInSlaveMode) >> 8; + temp2 = ~(SetInSlaveMode >> 8); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x31,temp2,temp1); +} + +/*********************************************/ +/* HELPER: GET SOME DATA FROM BIOS ROM */ +/*********************************************/ + +#ifdef SIS300 +static BOOLEAN +SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT temp,temp1; + + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); + temp1 = SISGETROMW(0x23b); + if(temp1 & temp) return TRUE; + } + } + return FALSE; +} + +static BOOLEAN +SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT temp,temp1; + + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); + temp1 = SISGETROMW(0x23d); + if(temp1 & temp) return TRUE; + } + } + return FALSE; +} +#endif + +/*********************************************/ +/* HELPER: DELAY FUNCTIONS */ +/*********************************************/ + +void +SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime) +{ + USHORT i, j; + + for(i=0; i<delaytime; i++) { + j += SiS_GetReg(SiS_Pr->SiS_P3c4,0x05); + } +} + +#if defined(SIS300) || defined(SIS315H) +static void +SiS_GenericDelay(SiS_Private *SiS_Pr, USHORT delay) +{ + USHORT temp,flag; + + flag = SiS_GetRegByte(0x61) & 0x10; + + while(delay) { + temp = SiS_GetRegByte(0x61) & 0x10; + if(temp == flag) continue; + flag = temp; + delay--; + } +} +#endif + +#ifdef SIS315H +static void +SiS_LongDelay(SiS_Private *SiS_Pr, USHORT delay) +{ + while(delay--) { + SiS_GenericDelay(SiS_Pr,0x19df); + } +} +#endif + +#if defined(SIS300) || defined(SIS315H) +static void +SiS_ShortDelay(SiS_Private *SiS_Pr, USHORT delay) +{ + while(delay--) { + SiS_GenericDelay(SiS_Pr,0x42); + } +} +#endif + +static void +SiS_PanelDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DelayTime) +{ +#if defined(SIS300) || defined(SIS315H) + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT PanelID, DelayIndex, Delay=0; +#endif + + if(HwInfo->jChipType < SIS_315H) { + +#ifdef SIS300 + + PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBType & VB_SIS301) PanelID &= 0xf7; + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x18) & 0x10)) PanelID = 0x12; + } + DelayIndex = PanelID >> 4; + if((DelayTime >= 2) && ((PanelID & 0x0f) == 1)) { + Delay = 3; + } else { + if(DelayTime >= 2) DelayTime -= 2; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x40) { + if(!(DelayTime & 0x01)) Delay = (USHORT)ROMAddr[0x225]; + else Delay = (USHORT)ROMAddr[0x226]; + } + } + } + SiS_ShortDelay(SiS_Pr, Delay); + +#endif /* SIS300 */ + + } else { + +#ifdef SIS315H + + if((HwInfo->jChipType >= SIS_661) || + (HwInfo->jChipType <= SIS_315PRO) || + (HwInfo->jChipType == SIS_330) || + (SiS_Pr->SiS_ROMNew)) { + + if(!(DelayTime & 0x01)) { + SiS_DDC2Delay(SiS_Pr, 0x1000); + } else { + SiS_DDC2Delay(SiS_Pr, 0x4000); + } + + } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* || + (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || + (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) { /* 315 series, LVDS; Special */ + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + if(SiS_Pr->SiS_CustomT == CUT_CLEVO1400) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1b) & 0x10)) PanelID = 0x12; + } + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { + DelayIndex = PanelID & 0x0f; + } else { + DelayIndex = PanelID >> 4; + } + if((DelayTime >= 2) && ((PanelID & 0x0f) == 1)) { + Delay = 3; + } else { + if(DelayTime >= 2) DelayTime -= 2; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[1]; + } + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + if(ROMAddr[0x13c] & 0x40) { + if(!(DelayTime & 0x01)) { + Delay = (USHORT)ROMAddr[0x17e]; + } else { + Delay = (USHORT)ROMAddr[0x17f]; + } + } + } + } + SiS_ShortDelay(SiS_Pr, Delay); + } + + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { /* 315 series, all bridges */ + + DelayIndex = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; + } + Delay <<= 8; + SiS_DDC2Delay(SiS_Pr, Delay); + + } + +#endif /* SIS315H */ + + } +} + +#ifdef SIS315H +static void +SiS_PanelDelayLoop(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT DelayTime, USHORT DelayLoop) +{ + int i; + for(i=0; i<DelayLoop; i++) { + SiS_PanelDelay(SiS_Pr, HwInfo, DelayTime); + } +} +#endif + +/*********************************************/ +/* HELPER: WAIT-FOR-RETRACE FUNCTIONS */ +/*********************************************/ + +void +SiS_WaitRetrace1(SiS_Private *SiS_Pr) +{ + USHORT watchdog; + + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return; + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80)) return; + + watchdog = 65535; + while((SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08) && --watchdog); + watchdog = 65535; + while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog); +} + +#if defined(SIS300) || defined(SIS315H) +static void +SiS_WaitRetrace2(SiS_Private *SiS_Pr, USHORT reg) +{ + USHORT watchdog; + + watchdog = 65535; + while((SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02) && --watchdog); + watchdog = 65535; + while((!(SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02)) && --watchdog); +} +#endif + +static void +SiS_WaitVBRetrace(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(HwInfo->jChipType < SIS_315H) { +#ifdef SIS300 + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return; + } + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x80)) { + SiS_WaitRetrace1(SiS_Pr); + } else { + SiS_WaitRetrace2(SiS_Pr, 0x25); + } +#endif + } else { +#ifdef SIS315H + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) { + SiS_WaitRetrace1(SiS_Pr); + } else { + SiS_WaitRetrace2(SiS_Pr, 0x30); + } +#endif + } +} + +static void +SiS_VBWait(SiS_Private *SiS_Pr) +{ + USHORT tempal,temp,i,j; + + temp = 0; + for(i=0; i<3; i++) { + for(j=0; j<100; j++) { + tempal = SiS_GetRegByte(SiS_Pr->SiS_P3da); + if(temp & 0x01) { + if((tempal & 0x08)) continue; + else break; + } else { + if(!(tempal & 0x08)) continue; + else break; + } + } + temp ^= 0x01; + } +} + +static void +SiS_VBLongWait(SiS_Private *SiS_Pr) +{ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_VBWait(SiS_Pr); + } else { + SiS_WaitRetrace1(SiS_Pr); + } +} + +/*********************************************/ +/* HELPER: MISC */ +/*********************************************/ + +#ifdef SIS300 +static BOOLEAN +SiS_Is301B(SiS_Private *SiS_Pr) +{ + if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return TRUE; + return FALSE; +} +#endif + +static BOOLEAN +SiS_CRT2IsLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType == SIS_730) { + flag = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13); + if(flag & 0x20) return TRUE; + } + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & 0x20) return TRUE; + return FALSE; +} + +BOOLEAN +SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ +#ifdef SIS315H + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + if((HwInfo->jChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableDualEdge) return TRUE; + } + } +#endif + return FALSE; +} + +BOOLEAN +SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ +#ifdef SIS315H + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if((flag & EnableDualEdge) && (flag & SetToLCDA)) return TRUE; + } +#endif + return FALSE; +} + +#ifdef SIS315H +static BOOLEAN +SiS_IsVAorLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(SiS_IsVAMode(SiS_Pr,HwInfo)) return TRUE; + if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) return TRUE; + return FALSE; +} +#endif + +static BOOLEAN +SiS_IsDualLink(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + if((SiS_CRT2IsLCD(SiS_Pr, HwInfo)) || + (SiS_IsVAMode(SiS_Pr, HwInfo))) { + if(SiS_Pr->SiS_LCDInfo & LCDDualLink) return TRUE; + } + } +#endif + return FALSE; +} + +#ifdef SIS315H +static BOOLEAN +SiS_TVEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return TRUE; + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS301LV302LV)) { + if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return TRUE; + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_LCDAEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) return TRUE; + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0x10) return TRUE; + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsNotM650orLater(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType == SIS_650) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f); + flag &= 0xF0; + /* Check for revision != A0 only */ + if((flag == 0xe0) || (flag == 0xc0) || + (flag == 0xb0) || (flag == 0x90)) return FALSE; + } else if(HwInfo->jChipType >= SIS_661) return FALSE; + return TRUE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableCHYPbPr) return TRUE; /* = YPrPb = 0x08 */ + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsChScart(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableCHScart) return TRUE; /* = Scart = 0x04 */ + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsTVOrYPbPrOrScart(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToTV) return TRUE; + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableCHYPbPr) return TRUE; /* = YPrPb = 0x08 */ + if(flag & EnableCHScart) return TRUE; /* = Scart = 0x04 - TW */ + } else { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToTV) return TRUE; + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_IsLCDOrLCDA(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(HwInfo->jChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToLCD) return TRUE; + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & SetToLCDA) return TRUE; + } else { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToLCD) return TRUE; + } + return FALSE; +} +#endif + +static BOOLEAN +SiS_BridgeIsOn(SiS_Private *SiS_Pr) +{ + USHORT flag; + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + return TRUE; + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + if((flag == 1) || (flag == 2)) return TRUE; + } + return FALSE; +} + +static BOOLEAN +SiS_BridgeIsEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + USHORT flag; + + if(SiS_BridgeIsOn(SiS_Pr)) { + flag = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + if(HwInfo->jChipType < SIS_315H) { + flag &= 0xa0; + if((flag == 0x80) || (flag == 0x20)) return TRUE; + } else { + flag &= 0x50; + if((flag == 0x40) || (flag == 0x10)) return TRUE; + } + } + return FALSE; +} + +static BOOLEAN +SiS_BridgeInSlavemode(SiS_Private *SiS_Pr) +{ + USHORT flag1; + + flag1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31); + if(flag1 & (SetInSlaveMode >> 8)) return TRUE; + return FALSE; +} + +/*********************************************/ +/* GET VIDEO BRIDGE CONFIG INFO */ +/*********************************************/ + +/* Setup general purpose IO for Chrontel communication */ +void +SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo) +{ + unsigned long acpibase; + unsigned short temp; + + if(!(SiS_Pr->SiS_ChSW)) return; + +#ifdef LINUX_KERNEL + SiS_SetRegLong(0xcf8,0x80000874); /* get ACPI base */ + acpibase = SiS_GetRegLong(0xcfc); +#else + acpibase = pciReadLong(0x00000800, 0x74); +#endif + acpibase &= 0xFFFF; + temp = SiS_GetRegShort((USHORT)(acpibase + 0x3c)); /* ACPI register 0x3c: GP Event 1 I/O mode select */ + temp &= 0xFEFF; + SiS_SetRegShort((USHORT)(acpibase + 0x3c), temp); + temp = SiS_GetRegShort((USHORT)(acpibase + 0x3c)); + temp = SiS_GetRegShort((USHORT)(acpibase + 0x3a)); /* ACPI register 0x3a: GP Pin Level (low/high) */ + temp &= 0xFEFF; + if(!(myvbinfo & SetCRT2ToTV)) temp |= 0x0100; + SiS_SetRegShort((USHORT)(acpibase + 0x3a), temp); + temp = SiS_GetRegShort((USHORT)(acpibase + 0x3a)); +} + +void +SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo, int checkcrt2mode) +{ + USHORT tempax,tempbx,temp; + USHORT modeflag, resinfo=0; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + SiS_Pr->SiS_SetFlag = 0; + + SiS_Pr->SiS_ModeType = modeflag & ModeTypeMask; + + tempbx = 0; + if(SiS_BridgeIsOn(SiS_Pr)) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); +#if 0 + if(HwInfo->jChipType < SIS_661) { + /* NO - YPbPr not set yet ! */ + if(SiS_Pr->SiS_YPbPr & <all ypbpr except 525i>) { + temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); /* 0x83 */ + temp |= SetCRT2ToHiVision; /* 0x80 */ + } + if(SiS_Pr->SiS_YPbPr & <ypbpr525i>) { + temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); /* 0x83 */ + temp |= SetCRT2ToSVIDEO; /* 0x08 */ + } + } +#endif + tempbx |= temp; + tempax = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) << 8; + tempax &= (DriverMode | LoadDACFlag | SetNotSimuMode | SetPALTV); + tempbx |= tempax; + +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISLCDA) { + if(ModeNo == 0x03) { + /* Mode 0x03 is never in driver mode */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x31,0xbf); + } + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8))) { + /* Reset LCDA setting if not driver mode */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); + } + if(IS_SIS650) { + if(SiS_Pr->SiS_UseLCDA) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xF0) { + if((ModeNo <= 0x13) || (!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8)))) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x38,(EnableDualEdge | SetToLCDA)); + } + } + } + } + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if((temp & (EnableDualEdge | SetToLCDA)) == (EnableDualEdge | SetToLCDA)) { + tempbx |= SetCRT2ToLCDA; + } + } + + if(SiS_Pr->SiS_VBType & (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)) { + tempbx &= ~(SetCRT2ToRAMDAC); + } + + if(HwInfo->jChipType >= SIS_661) { + tempbx &= ~(SetCRT2ToYPbPr525750 | SetCRT2ToHiVision); + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(SiS_Pr->SiS_VBType & VB_SISYPBPR) { + if(temp & 0x04) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; + if(temp == 0x60) tempbx |= SetCRT2ToHiVision; + else tempbx |= SetCRT2ToYPbPr525750; + } + } else if(SiS_Pr->SiS_VBType & VB_SISHIVISION) { + if(temp & 0x04) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; + if(temp == 0x60) tempbx |= SetCRT2ToHiVision; + } + } + } + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(temp & SetToLCDA) { + tempbx |= SetCRT2ToLCDA; + } + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(temp & EnableCHYPbPr) { + tempbx |= SetCRT2ToCHYPbPr; + } + } + } + } + +#endif /* SIS315H */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = SetCRT2ToSVIDEO | + SetCRT2ToAVIDEO | + SetCRT2ToSCART | + SetCRT2ToLCDA | + SetCRT2ToLCD | + SetCRT2ToRAMDAC | + SetCRT2ToHiVision | + SetCRT2ToYPbPr525750; + } else { + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + temp = SetCRT2ToAVIDEO | + SetCRT2ToSVIDEO | + SetCRT2ToSCART | + SetCRT2ToLCDA | + SetCRT2ToLCD | + SetCRT2ToCHYPbPr; + } else { + temp = SetCRT2ToLCDA | + SetCRT2ToLCD; + } + } else { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + temp = SetCRT2ToTV | SetCRT2ToLCD; + } else { + temp = SetCRT2ToLCD; + } + } + } + + if(!(tempbx & temp)) { + tempax = DisableCRT2Display; + tempbx = 0; + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + USHORT clearmask = ( DriverMode | + DisableCRT2Display | + LoadDACFlag | + SetNotSimuMode | + SetInSlaveMode | + SetPALTV | + SwitchCRT2 | + SetSimuScanMode ); + if(tempbx & SetCRT2ToLCDA) tempbx &= (clearmask | SetCRT2ToLCDA); + if(tempbx & SetCRT2ToRAMDAC) tempbx &= (clearmask | SetCRT2ToRAMDAC); + if(tempbx & SetCRT2ToLCD) tempbx &= (clearmask | SetCRT2ToLCD); + if(tempbx & SetC |