init.c revision 74c14cd6
1/*
2 * Mode initializing code (CRT1 section) for
3 * for SiS 300/305/540/630/730,
4 *     SiS 315/550/[M]650/651/[M]661[FGM]X/[M]74x[GX]/330/[M]76x[GX],
5 *     XGI Volari V3XT/V5/V8, Z7
6 * (Universal module for Linux kernel framebuffer and X.org/XFree86 4.x)
7 *
8 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
9 *
10 * If distributed as part of the Linux kernel, the following license terms
11 * apply:
12 *
13 * * This program is free software; you can redistribute it and/or modify
14 * * it under the terms of the GNU General Public License as published by
15 * * the Free Software Foundation; either version 2 of the named License,
16 * * or any later version.
17 * *
18 * * This program is distributed in the hope that it will be useful,
19 * * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * * GNU General Public License for more details.
22 * *
23 * * You should have received a copy of the GNU General Public License
24 * * along with this program; if not, write to the Free Software
25 * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
26 *
27 * Otherwise, the following license terms apply:
28 *
29 * * Redistribution and use in source and binary forms, with or without
30 * * modification, are permitted provided that the following conditions
31 * * are met:
32 * * 1) Redistributions of source code must retain the above copyright
33 * *    notice, this list of conditions and the following disclaimer.
34 * * 2) Redistributions in binary form must reproduce the above copyright
35 * *    notice, this list of conditions and the following disclaimer in the
36 * *    documentation and/or other materials provided with the distribution.
37 * * 3) The name of the author may not be used to endorse or promote products
38 * *    derived from this software without specific prior written permission.
39 * *
40 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
41 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
43 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
44 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
46 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
47 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
48 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
49 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 *
51 * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
52 *
53 * Formerly based on non-functional code-fragements for 300 series by SiS, Inc.
54 * Used by permission.
55 */
56
57#ifdef HAVE_CONFIG_H
58#include "config.h"
59#endif
60
61#include "init.h"
62#include "sis_dac.h"
63
64#ifdef SIS300
65#include "300vtbl.h"
66#endif
67
68#ifdef SIS315H
69#include "310vtbl.h"
70#endif
71
72#if defined(ALLOC_PRAGMA)
73#pragma alloc_text(PAGE,SiSSetMode)
74#endif
75
76/*********************************************/
77/*         POINTER INITIALIZATION            */
78/*********************************************/
79
80#if defined(SIS300) || defined(SIS315H)
81static void
82InitCommonPointer(struct SiS_Private *SiS_Pr)
83{
84   SiS_Pr->SiS_SModeIDTable  = SiS_SModeIDTable;
85   SiS_Pr->SiS_StResInfo     = SiS_StResInfo;
86   SiS_Pr->SiS_ModeResInfo   = SiS_ModeResInfo;
87   SiS_Pr->SiS_StandTable    = SiS_StandTable;
88
89   SiS_Pr->SiS_NTSCTiming     = SiS_NTSCTiming;
90   SiS_Pr->SiS_PALTiming      = SiS_PALTiming;
91   SiS_Pr->SiS_HiTVSt1Timing  = SiS_HiTVSt1Timing;
92   SiS_Pr->SiS_HiTVSt2Timing  = SiS_HiTVSt2Timing;
93
94   SiS_Pr->SiS_HiTVExtTiming  = SiS_HiTVExtTiming;
95   SiS_Pr->SiS_HiTVGroup3Data = SiS_HiTVGroup3Data;
96   SiS_Pr->SiS_HiTVGroup3Simu = SiS_HiTVGroup3Simu;
97#if 0
98   SiS_Pr->SiS_HiTVTextTiming = SiS_HiTVTextTiming;
99   SiS_Pr->SiS_HiTVGroup3Text = SiS_HiTVGroup3Text;
100#endif
101
102   SiS_Pr->SiS_StPALData   = SiS_StPALData;
103   SiS_Pr->SiS_ExtPALData  = SiS_ExtPALData;
104   SiS_Pr->SiS_StNTSCData  = SiS_StNTSCData;
105   SiS_Pr->SiS_ExtNTSCData = SiS_ExtNTSCData;
106   SiS_Pr->SiS_St1HiTVData = SiS_StHiTVData;
107   SiS_Pr->SiS_St2HiTVData = SiS_St2HiTVData;
108   SiS_Pr->SiS_ExtHiTVData = SiS_ExtHiTVData;
109   SiS_Pr->SiS_St525iData  = SiS_StNTSCData;
110   SiS_Pr->SiS_St525pData  = SiS_St525pData;
111   SiS_Pr->SiS_St625iData  = SiS_StPALData;
112   SiS_Pr->SiS_St625pData  = SiS_StPALData;
113   SiS_Pr->SiS_St750pData  = SiS_St750pData;
114   SiS_Pr->SiS_Ext525iData = SiS_ExtNTSCData;
115   SiS_Pr->SiS_Ext525pData = SiS_ExtNTSCData;
116   SiS_Pr->SiS_Ext625iData = SiS_ExtPALData;
117   SiS_Pr->SiS_Ext625pData = SiS_ExtPALData;
118   SiS_Pr->SiS_Ext750pData = SiS_Ext750pData;
119
120   SiS_Pr->pSiS_OutputSelect = &SiS_OutputSelect;
121   SiS_Pr->pSiS_SoftSetting  = &SiS_SoftSetting;
122
123   SiS_Pr->SiS_LCD1280x720Data      = SiS_LCD1280x720Data;
124   SiS_Pr->SiS_StLCD1280x768_2Data  = SiS_StLCD1280x768_2Data;
125   SiS_Pr->SiS_ExtLCD1280x768_2Data = SiS_ExtLCD1280x768_2Data;
126   SiS_Pr->SiS_LCD1280x800Data      = SiS_LCD1280x800Data;
127   SiS_Pr->SiS_LCD1280x800_2Data    = SiS_LCD1280x800_2Data;
128   SiS_Pr->SiS_LCD1280x854Data      = SiS_LCD1280x854Data;
129   SiS_Pr->SiS_LCD1280x960Data      = SiS_LCD1280x960Data;
130   SiS_Pr->SiS_StLCD1400x1050Data   = SiS_StLCD1400x1050Data;
131   SiS_Pr->SiS_ExtLCD1400x1050Data  = SiS_ExtLCD1400x1050Data;
132   SiS_Pr->SiS_LCD1680x1050Data     = SiS_LCD1680x1050Data;
133   SiS_Pr->SiS_StLCD1600x1200Data   = SiS_StLCD1600x1200Data;
134   SiS_Pr->SiS_ExtLCD1600x1200Data  = SiS_ExtLCD1600x1200Data;
135   SiS_Pr->SiS_NoScaleData          = SiS_NoScaleData;
136
137   SiS_Pr->SiS_LVDS320x240Data_1   = SiS_LVDS320x240Data_1;
138   SiS_Pr->SiS_LVDS320x240Data_2   = SiS_LVDS320x240Data_2;
139   SiS_Pr->SiS_LVDS640x480Data_1   = SiS_LVDS640x480Data_1;
140   SiS_Pr->SiS_LVDS800x600Data_1   = SiS_LVDS800x600Data_1;
141   SiS_Pr->SiS_LVDS1024x600Data_1  = SiS_LVDS1024x600Data_1;
142   SiS_Pr->SiS_LVDS1024x768Data_1  = SiS_LVDS1024x768Data_1;
143
144   SiS_Pr->SiS_LVDSCRT1320x240_1     = SiS_LVDSCRT1320x240_1;
145   SiS_Pr->SiS_LVDSCRT1320x240_2     = SiS_LVDSCRT1320x240_2;
146   SiS_Pr->SiS_LVDSCRT1320x240_2_H   = SiS_LVDSCRT1320x240_2_H;
147   SiS_Pr->SiS_LVDSCRT1320x240_3     = SiS_LVDSCRT1320x240_3;
148   SiS_Pr->SiS_LVDSCRT1320x240_3_H   = SiS_LVDSCRT1320x240_3_H;
149   SiS_Pr->SiS_LVDSCRT1640x480_1     = SiS_LVDSCRT1640x480_1;
150   SiS_Pr->SiS_LVDSCRT1640x480_1_H   = SiS_LVDSCRT1640x480_1_H;
151#if 0
152   SiS_Pr->SiS_LVDSCRT11024x600_1    = SiS_LVDSCRT11024x600_1;
153   SiS_Pr->SiS_LVDSCRT11024x600_1_H  = SiS_LVDSCRT11024x600_1_H;
154   SiS_Pr->SiS_LVDSCRT11024x600_2    = SiS_LVDSCRT11024x600_2;
155   SiS_Pr->SiS_LVDSCRT11024x600_2_H  = SiS_LVDSCRT11024x600_2_H;
156#endif
157
158   SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData;
159   SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData;
160
161   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;    /* lowest value LVDS/LCDA */
162   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;   /* lowest value 301 */
163}
164#endif
165
166#ifdef SIS300
167static void
168InitTo300Pointer(struct SiS_Private *SiS_Pr)
169{
170   InitCommonPointer(SiS_Pr);
171
172   SiS_Pr->SiS_VBModeIDTable = SiS300_VBModeIDTable;
173   SiS_Pr->SiS_EModeIDTable  = SiS300_EModeIDTable;
174   SiS_Pr->SiS_RefIndex      = SiS300_RefIndex;
175   SiS_Pr->SiS_CRT1Table     = SiS300_CRT1Table;
176   if(SiS_Pr->ChipType == SIS_300) {
177      SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_300; /* 300 */
178   } else {
179      SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_630; /* 630, 730 */
180   }
181   SiS_Pr->SiS_VCLKData      = SiS300_VCLKData;
182   SiS_Pr->SiS_VBVCLKData    = (struct SiS_VBVCLKData *)SiS300_VCLKData;
183
184   SiS_Pr->SiS_SR15  = SiS300_SR15;
185
186   SiS_Pr->SiS_PanelDelayTbl     = SiS300_PanelDelayTbl;
187   SiS_Pr->SiS_PanelDelayTblLVDS = SiS300_PanelDelayTbl;
188
189   SiS_Pr->SiS_ExtLCD1024x768Data   = SiS300_ExtLCD1024x768Data;
190   SiS_Pr->SiS_St2LCD1024x768Data   = SiS300_St2LCD1024x768Data;
191   SiS_Pr->SiS_ExtLCD1280x1024Data  = SiS300_ExtLCD1280x1024Data;
192   SiS_Pr->SiS_St2LCD1280x1024Data  = SiS300_St2LCD1280x1024Data;
193
194   SiS_Pr->SiS_CRT2Part2_1024x768_1  = SiS300_CRT2Part2_1024x768_1;
195   SiS_Pr->SiS_CRT2Part2_1024x768_2  = SiS300_CRT2Part2_1024x768_2;
196   SiS_Pr->SiS_CRT2Part2_1024x768_3  = SiS300_CRT2Part2_1024x768_3;
197
198   SiS_Pr->SiS_CHTVUPALData  = SiS300_CHTVUPALData;
199   SiS_Pr->SiS_CHTVOPALData  = SiS300_CHTVOPALData;
200   SiS_Pr->SiS_CHTVUPALMData = SiS_CHTVUNTSCData;    /* not supported on 300 series */
201   SiS_Pr->SiS_CHTVOPALMData = SiS_CHTVONTSCData;    /* not supported on 300 series */
202   SiS_Pr->SiS_CHTVUPALNData = SiS300_CHTVUPALData;  /* not supported on 300 series */
203   SiS_Pr->SiS_CHTVOPALNData = SiS300_CHTVOPALData;  /* not supported on 300 series */
204   SiS_Pr->SiS_CHTVSOPALData = SiS300_CHTVSOPALData;
205
206   SiS_Pr->SiS_LVDS848x480Data_1   = SiS300_LVDS848x480Data_1;
207   SiS_Pr->SiS_LVDS848x480Data_2   = SiS300_LVDS848x480Data_2;
208   SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS300_LVDSBARCO1024Data_1;
209   SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS300_LVDSBARCO1366Data_1;
210   SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS300_LVDSBARCO1366Data_2;
211
212   SiS_Pr->SiS_PanelType04_1a = SiS300_PanelType04_1a;
213   SiS_Pr->SiS_PanelType04_2a = SiS300_PanelType04_2a;
214   SiS_Pr->SiS_PanelType04_1b = SiS300_PanelType04_1b;
215   SiS_Pr->SiS_PanelType04_2b = SiS300_PanelType04_2b;
216
217   SiS_Pr->SiS_CHTVCRT1UNTSC = SiS300_CHTVCRT1UNTSC;
218   SiS_Pr->SiS_CHTVCRT1ONTSC = SiS300_CHTVCRT1ONTSC;
219   SiS_Pr->SiS_CHTVCRT1UPAL  = SiS300_CHTVCRT1UPAL;
220   SiS_Pr->SiS_CHTVCRT1OPAL  = SiS300_CHTVCRT1OPAL;
221   SiS_Pr->SiS_CHTVCRT1SOPAL = SiS300_CHTVCRT1SOPAL;
222   SiS_Pr->SiS_CHTVReg_UNTSC = SiS300_CHTVReg_UNTSC;
223   SiS_Pr->SiS_CHTVReg_ONTSC = SiS300_CHTVReg_ONTSC;
224   SiS_Pr->SiS_CHTVReg_UPAL  = SiS300_CHTVReg_UPAL;
225   SiS_Pr->SiS_CHTVReg_OPAL  = SiS300_CHTVReg_OPAL;
226   SiS_Pr->SiS_CHTVReg_UPALM = SiS300_CHTVReg_UNTSC;  /* not supported on 300 series */
227   SiS_Pr->SiS_CHTVReg_OPALM = SiS300_CHTVReg_ONTSC;  /* not supported on 300 series */
228   SiS_Pr->SiS_CHTVReg_UPALN = SiS300_CHTVReg_UPAL;   /* not supported on 300 series */
229   SiS_Pr->SiS_CHTVReg_OPALN = SiS300_CHTVReg_OPAL;   /* not supported on 300 series */
230   SiS_Pr->SiS_CHTVReg_SOPAL = SiS300_CHTVReg_SOPAL;
231   SiS_Pr->SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC;
232   SiS_Pr->SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC;
233   SiS_Pr->SiS_CHTVVCLKUPAL  = SiS300_CHTVVCLKUPAL;
234   SiS_Pr->SiS_CHTVVCLKOPAL  = SiS300_CHTVVCLKOPAL;
235   SiS_Pr->SiS_CHTVVCLKUPALM = SiS300_CHTVVCLKUNTSC;  /* not supported on 300 series */
236   SiS_Pr->SiS_CHTVVCLKOPALM = SiS300_CHTVVCLKONTSC;  /* not supported on 300 series */
237   SiS_Pr->SiS_CHTVVCLKUPALN = SiS300_CHTVVCLKUPAL;   /* not supported on 300 series */
238   SiS_Pr->SiS_CHTVVCLKOPALN = SiS300_CHTVVCLKOPAL;   /* not supported on 300 series */
239   SiS_Pr->SiS_CHTVVCLKSOPAL = SiS300_CHTVVCLKSOPAL;
240}
241#endif
242
243#ifdef SIS315H
244static void
245InitTo310Pointer(struct SiS_Private *SiS_Pr)
246{
247   InitCommonPointer(SiS_Pr);
248
249   SiS_Pr->SiS_EModeIDTable  = SiS310_EModeIDTable;
250   SiS_Pr->SiS_RefIndex      = SiS310_RefIndex;
251   SiS_Pr->SiS_CRT1Table     = SiS310_CRT1Table;
252   if(SiS_Pr->ChipType >= SIS_340) {
253      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_340;  /* 340 + XGI */
254   } else if(SiS_Pr->ChipType >= SIS_761) {
255      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_761;  /* 761 - preliminary */
256   } else if(SiS_Pr->ChipType >= SIS_760) {
257      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_760;  /* 760 */
258   } else if(SiS_Pr->ChipType >= SIS_661) {
259      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_660;  /* 661/741 */
260   } else if(SiS_Pr->ChipType == SIS_330) {
261      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_330;  /* 330 */
262   } else if(SiS_Pr->ChipType > SIS_315PRO) {
263      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_650;  /* 550, 650, 740 */
264   } else {
265      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_315;  /* 315 */
266   }
267   if(SiS_Pr->ChipType >= SIS_340) {
268      SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1_340;
269   } else {
270      SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1;
271   }
272   SiS_Pr->SiS_VCLKData      = SiS310_VCLKData;
273   SiS_Pr->SiS_VBVCLKData    = SiS310_VBVCLKData;
274
275   SiS_Pr->SiS_SR15  = SiS310_SR15;
276
277   SiS_Pr->SiS_PanelDelayTbl     = SiS310_PanelDelayTbl;
278   SiS_Pr->SiS_PanelDelayTblLVDS = SiS310_PanelDelayTblLVDS;
279
280   SiS_Pr->SiS_St2LCD1024x768Data   = SiS310_St2LCD1024x768Data;
281   SiS_Pr->SiS_ExtLCD1024x768Data   = SiS310_ExtLCD1024x768Data;
282   SiS_Pr->SiS_St2LCD1280x1024Data  = SiS310_St2LCD1280x1024Data;
283   SiS_Pr->SiS_ExtLCD1280x1024Data  = SiS310_ExtLCD1280x1024Data;
284
285   SiS_Pr->SiS_CRT2Part2_1024x768_1  = SiS310_CRT2Part2_1024x768_1;
286
287   SiS_Pr->SiS_CHTVUPALData  = SiS310_CHTVUPALData;
288   SiS_Pr->SiS_CHTVOPALData  = SiS310_CHTVOPALData;
289   SiS_Pr->SiS_CHTVUPALMData = SiS310_CHTVUPALMData;
290   SiS_Pr->SiS_CHTVOPALMData = SiS310_CHTVOPALMData;
291   SiS_Pr->SiS_CHTVUPALNData = SiS310_CHTVUPALNData;
292   SiS_Pr->SiS_CHTVOPALNData = SiS310_CHTVOPALNData;
293   SiS_Pr->SiS_CHTVSOPALData = SiS310_CHTVSOPALData;
294
295   SiS_Pr->SiS_CHTVCRT1UNTSC = SiS310_CHTVCRT1UNTSC;
296   SiS_Pr->SiS_CHTVCRT1ONTSC = SiS310_CHTVCRT1ONTSC;
297   SiS_Pr->SiS_CHTVCRT1UPAL  = SiS310_CHTVCRT1UPAL;
298   SiS_Pr->SiS_CHTVCRT1OPAL  = SiS310_CHTVCRT1OPAL;
299   SiS_Pr->SiS_CHTVCRT1SOPAL = SiS310_CHTVCRT1OPAL;
300
301   SiS_Pr->SiS_CHTVReg_UNTSC = SiS310_CHTVReg_UNTSC;
302   SiS_Pr->SiS_CHTVReg_ONTSC = SiS310_CHTVReg_ONTSC;
303   SiS_Pr->SiS_CHTVReg_UPAL  = SiS310_CHTVReg_UPAL;
304   SiS_Pr->SiS_CHTVReg_OPAL  = SiS310_CHTVReg_OPAL;
305   SiS_Pr->SiS_CHTVReg_UPALM = SiS310_CHTVReg_UPALM;
306   SiS_Pr->SiS_CHTVReg_OPALM = SiS310_CHTVReg_OPALM;
307   SiS_Pr->SiS_CHTVReg_UPALN = SiS310_CHTVReg_UPALN;
308   SiS_Pr->SiS_CHTVReg_OPALN = SiS310_CHTVReg_OPALN;
309   SiS_Pr->SiS_CHTVReg_SOPAL = SiS310_CHTVReg_OPAL;
310
311   SiS_Pr->SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC;
312   SiS_Pr->SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC;
313   SiS_Pr->SiS_CHTVVCLKUPAL  = SiS310_CHTVVCLKUPAL;
314   SiS_Pr->SiS_CHTVVCLKOPAL  = SiS310_CHTVVCLKOPAL;
315   SiS_Pr->SiS_CHTVVCLKUPALM = SiS310_CHTVVCLKUPALM;
316   SiS_Pr->SiS_CHTVVCLKOPALM = SiS310_CHTVVCLKOPALM;
317   SiS_Pr->SiS_CHTVVCLKUPALN = SiS310_CHTVVCLKUPALN;
318   SiS_Pr->SiS_CHTVVCLKOPALN = SiS310_CHTVVCLKOPALN;
319   SiS_Pr->SiS_CHTVVCLKSOPAL = SiS310_CHTVVCLKOPAL;
320}
321#endif
322
323BOOLEAN
324SiSInitPtr(struct SiS_Private *SiS_Pr)
325{
326   if(SiS_Pr->ChipType < SIS_315H) {
327#ifdef SIS300
328      InitTo300Pointer(SiS_Pr);
329#else
330      return FALSE;
331#endif
332   } else {
333#ifdef SIS315H
334      InitTo310Pointer(SiS_Pr);
335#else
336      return FALSE;
337#endif
338   }
339   return TRUE;
340}
341
342/*********************************************/
343/*            HELPER: Get ModeID             */
344/*********************************************/
345
346#ifndef SIS_XORG_XF86
347static
348#endif
349unsigned short
350SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
351		int Depth, BOOLEAN FSTN, int LCDwidth, int LCDheight)
352{
353   unsigned short ModeIndex = 0;
354
355   switch(HDisplay)
356   {
357	case 320:
358		if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth];
359		else if(VDisplay == 240) {
360			if((VBFlags & CRT2_LCD) && (FSTN))
361				ModeIndex = ModeIndex_320x240_FSTN[Depth];
362			else
363				ModeIndex = ModeIndex_320x240[Depth];
364		}
365		break;
366	case 400:
367		if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 800) && (LCDwidth >= 600))) {
368			if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
369		}
370		break;
371	case 512:
372		if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 1024) && (LCDwidth >= 768))) {
373			if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
374		}
375		break;
376	case 640:
377		if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
378		else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
379		break;
380	case 720:
381		if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
382		else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
383		break;
384	case 768:
385		if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
386		break;
387	case 800:
388		if(VDisplay == 600)      ModeIndex = ModeIndex_800x600[Depth];
389		else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
390		break;
391	case 848:
392		if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
393		break;
394	case 856:
395		if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
396		break;
397	case 960:
398		if(VGAEngine == SIS_315_VGA) {
399			if(VDisplay == 540)      ModeIndex = ModeIndex_960x540[Depth];
400			else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth];
401		}
402		break;
403	case 1024:
404		if(VDisplay == 576)      ModeIndex = ModeIndex_1024x576[Depth];
405		else if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
406		else if(VGAEngine == SIS_300_VGA) {
407			if(VDisplay == 600) ModeIndex = ModeIndex_1024x600[Depth];
408		}
409		break;
410	case 1152:
411		if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth];
412		if(VGAEngine == SIS_300_VGA) {
413			if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth];
414		}
415		break;
416	case 1280:
417		switch(VDisplay) {
418			case 720:
419				ModeIndex = ModeIndex_1280x720[Depth];
420				break;
421			case 768:
422				if(VGAEngine == SIS_300_VGA) {
423					ModeIndex = ModeIndex_300_1280x768[Depth];
424				} else {
425					ModeIndex = ModeIndex_310_1280x768[Depth];
426				}
427				break;
428			case 800:
429				if(VGAEngine == SIS_315_VGA) {
430					ModeIndex = ModeIndex_1280x800[Depth];
431				}
432				break;
433			case 854:
434				if(VGAEngine == SIS_315_VGA) {
435					ModeIndex = ModeIndex_1280x854[Depth];
436				}
437				break;
438			case 960:
439				ModeIndex = ModeIndex_1280x960[Depth];
440				break;
441			case 1024:
442				ModeIndex = ModeIndex_1280x1024[Depth];
443				break;
444		}
445		break;
446	case 1360:
447		if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
448		if(VGAEngine == SIS_300_VGA) {
449			if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth];
450		}
451		break;
452	case 1400:
453		if(VGAEngine == SIS_315_VGA) {
454			if(VDisplay == 1050) {
455				ModeIndex = ModeIndex_1400x1050[Depth];
456			}
457		}
458		break;
459	case 1600:
460		if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
461		break;
462	case 1680:
463		if(VGAEngine == SIS_315_VGA) {
464			if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth];
465		}
466		break;
467	case 1920:
468		if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth];
469		else if(VGAEngine == SIS_315_VGA) {
470			if(VDisplay == 1080) ModeIndex = ModeIndex_1920x1080[Depth];
471		}
472		break;
473	case 2048:
474		if(VDisplay == 1536) {
475			if(VGAEngine == SIS_300_VGA) {
476				ModeIndex = ModeIndex_300_2048x1536[Depth];
477			} else {
478				ModeIndex = ModeIndex_310_2048x1536[Depth];
479			}
480		}
481		break;
482   }
483
484   return ModeIndex;
485}
486
487unsigned short
488SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
489		int Depth, BOOLEAN FSTN, unsigned short CustomT, int LCDwidth, int LCDheight,
490		unsigned int VBFlags2)
491{
492   unsigned short ModeIndex = 0;
493
494   if(VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
495
496      switch(HDisplay)
497      {
498	case 320:
499	     if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) {
500		if(VDisplay == 200) {
501		   if(!FSTN) ModeIndex = ModeIndex_320x200[Depth];
502		} else if(VDisplay == 240) {
503		   if(!FSTN) ModeIndex = ModeIndex_320x240[Depth];
504		   else if(VGAEngine == SIS_315_VGA) {
505		      ModeIndex = ModeIndex_320x240_FSTN[Depth];
506		   }
507		}
508	     }
509	     break;
510	case 400:
511	     if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) {
512		if(!((VGAEngine == SIS_300_VGA) && (VBFlags2 & VB2_TRUMPION))) {
513		   if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
514		}
515	     }
516	     break;
517	case 512:
518	     if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) {
519		if(!((VGAEngine == SIS_300_VGA) && (VBFlags2 & VB2_TRUMPION))) {
520		   if(LCDwidth >= 1024 && LCDwidth != 1152 && LCDheight >= 768) {
521		      if(VDisplay == 384) {
522		         ModeIndex = ModeIndex_512x384[Depth];
523		      }
524		   }
525		}
526	     }
527	     break;
528	case 640:
529	     if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth];
530	     else if(VDisplay == 400) {
531		if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856))
532		   ModeIndex = ModeIndex_640x400[Depth];
533	     }
534	     break;
535	case 800:
536	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
537	     break;
538	case 848:
539	     if(CustomT == CUT_PANEL848) {
540	        if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
541	     }
542	     break;
543	case 856:
544	     if(CustomT == CUT_PANEL856) {
545	        if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
546	     }
547	     break;
548	case 1024:
549	     if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
550	     else if(VGAEngine == SIS_300_VGA) {
551		if((VDisplay == 600) && (LCDheight == 600)) {
552		   ModeIndex = ModeIndex_1024x600[Depth];
553		}
554	     }
555	     break;
556	case 1152:
557	     if(VGAEngine == SIS_300_VGA) {
558		if((VDisplay == 768) && (LCDheight == 768)) {
559		   ModeIndex = ModeIndex_1152x768[Depth];
560		}
561	     }
562	     break;
563        case 1280:
564	     if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
565	     else if(VGAEngine == SIS_315_VGA) {
566		if((VDisplay == 768) && (LCDheight == 768)) {
567		   ModeIndex = ModeIndex_310_1280x768[Depth];
568		}
569	     }
570	     break;
571	case 1360:
572	     if(VGAEngine == SIS_300_VGA) {
573		if(CustomT == CUT_BARCO1366) {
574		   if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth];
575		}
576	     }
577	     if(CustomT == CUT_PANEL848) {
578		if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
579	     }
580	     break;
581	case 1400:
582	     if(VGAEngine == SIS_315_VGA) {
583		if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
584	     }
585	     break;
586	case 1600:
587	     if(VGAEngine == SIS_315_VGA) {
588		if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
589	     }
590	     break;
591      }
592
593   } else if(VBFlags2 & VB2_SISBRIDGE) {
594
595      switch(HDisplay)
596      {
597	case 320:
598	     if(VDisplay == 200)      ModeIndex = ModeIndex_320x200[Depth];
599	     else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth];
600	     break;
601	case 400:
602	     if(LCDwidth >= 800 && LCDheight >= 600) {
603		if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
604	     }
605	     break;
606	case 512:
607	     if(LCDwidth >= 1024 && LCDheight >= 768 && LCDwidth != 1152) {
608		if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
609	     }
610	     break;
611	case 640:
612	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
613	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
614	     break;
615	case 720:
616	     if(VGAEngine == SIS_315_VGA) {
617		if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
618		else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
619	     }
620	     break;
621	case 768:
622	     if(VGAEngine == SIS_315_VGA) {
623		if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
624	     }
625	     break;
626	case 800:
627	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
628	     if(VGAEngine == SIS_315_VGA) {
629		if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
630	     }
631	     break;
632	case 848:
633	     if(VGAEngine == SIS_315_VGA) {
634		if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
635	     }
636	     break;
637	case 856:
638	     if(VGAEngine == SIS_315_VGA) {
639		if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
640	     }
641	     break;
642	case 960:
643	     if(VGAEngine == SIS_315_VGA) {
644		if(VDisplay == 540)      ModeIndex = ModeIndex_960x540[Depth];
645		else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth];
646	     }
647	     break;
648	case 1024:
649	     if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
650	     if(VGAEngine == SIS_315_VGA) {
651		if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth];
652	     }
653	     break;
654	case 1152:
655	     if(VGAEngine == SIS_315_VGA) {
656		if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth];
657	     }
658	     break;
659	case 1280:
660	     switch(VDisplay) {
661	     case 720:
662		ModeIndex = ModeIndex_1280x720[Depth];
663	     case 768:
664		if(VGAEngine == SIS_300_VGA) {
665		   ModeIndex = ModeIndex_300_1280x768[Depth];
666		} else {
667		   ModeIndex = ModeIndex_310_1280x768[Depth];
668		}
669		break;
670	     case 800:
671		if(VGAEngine == SIS_315_VGA) {
672		   ModeIndex = ModeIndex_1280x800[Depth];
673		}
674		break;
675	     case 854:
676		if(VGAEngine == SIS_315_VGA) {
677		   ModeIndex = ModeIndex_1280x854[Depth];
678		}
679		break;
680	     case 960:
681		ModeIndex = ModeIndex_1280x960[Depth];
682		break;
683	     case 1024:
684		ModeIndex = ModeIndex_1280x1024[Depth];
685		break;
686	     }
687	     break;
688	case 1360:
689	     if(VGAEngine == SIS_315_VGA) {  /* OVER1280 only? */
690		if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
691	     }
692	     break;
693	case 1400:
694	     if(VGAEngine == SIS_315_VGA) {
695		if(VBFlags2 & VB2_LCDOVER1280BRIDGE) {
696		   if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
697		}
698	     }
699	     break;
700	case 1600:
701	     if(VGAEngine == SIS_315_VGA) {
702		if(VBFlags2 & VB2_LCDOVER1280BRIDGE) {
703		   if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
704		}
705	     }
706	     break;
707#ifndef VB_FORBID_CRT2LCD_OVER_1600
708	case 1680:
709	     if(VGAEngine == SIS_315_VGA) {
710		if(VBFlags2 & VB2_LCDOVER1280BRIDGE) {
711		   if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth];
712		}
713	     }
714	     break;
715	case 1920:
716	     if(VGAEngine == SIS_315_VGA) {
717		if(VBFlags2 & VB2_LCDOVER1600BRIDGE) {
718		   if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth];
719		}
720	     }
721	     break;
722	case 2048:
723	     if(VGAEngine == SIS_315_VGA) {
724		if(VBFlags2 & VB2_LCDOVER1600BRIDGE) {
725		   if(VDisplay == 1536) ModeIndex = ModeIndex_310_2048x1536[Depth];
726		}
727	     }
728	     break;
729#endif
730      }
731   }
732
733   return ModeIndex;
734}
735
736unsigned short
737SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, int Depth,
738			unsigned int VBFlags2)
739{
740   unsigned short ModeIndex = 0;
741
742   if(VBFlags2 & VB2_CHRONTEL) {
743
744      switch(HDisplay)
745      {
746	case 512:
747	     if(VGAEngine == SIS_315_VGA) {
748		if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
749	     }
750	     break;
751	case 640:
752	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
753	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
754	     break;
755	case 800:
756	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
757	     break;
758	case 1024:
759	     if(VGAEngine == SIS_315_VGA) {
760		if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
761	     }
762	     break;
763      }
764
765   } else if(VBFlags2 & VB2_SISTVBRIDGE) {
766
767      switch(HDisplay)
768      {
769	case 320:
770	     if(VDisplay == 200)      ModeIndex = ModeIndex_320x200[Depth];
771	     else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth];
772	     break;
773	case 400:
774	     if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
775	     break;
776	case 512:
777	     if(VBFlags2 & VB2_30xBLV) {
778	        if( ((VBFlags & TV_YPBPR) && (!(VBFlags & (TV_YPBPR525P | TV_YPBPR525I)))) ||
779		    (VBFlags & TV_HIVISION) 						||
780		    ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) {
781		   if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
782	        }
783	     }
784	     break;
785	case 640:
786	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
787	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
788	     break;
789	case 720:
790	     if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) {
791		if(VDisplay == 480) {
792		   ModeIndex = ModeIndex_720x480[Depth];
793		} else if(VDisplay == 576) {
794		   ModeIndex = ModeIndex_720x576[Depth];
795		}
796	     }
797             break;
798	case 768:
799	     if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) {
800		if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
801             }
802	     break;
803	case 800:
804	     if(VDisplay == 600)      ModeIndex = ModeIndex_800x600[Depth];
805	     else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
806	     break;
807	case 960:
808	     if(VGAEngine == SIS_315_VGA) {
809	        if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) {
810		   if(VDisplay == 600) {
811		      ModeIndex = ModeIndex_960x600[Depth];
812		   } else if(VDisplay == 540) {
813		      ModeIndex = ModeIndex_960x540[Depth];
814		   }
815		}
816	     }
817	     break;
818	case 1024:
819	     if((VBFlags2 & VB2_30xBLV) ||
820	        (VBFlags & TV_HIVISION) ||
821	        ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) {
822	        if(VDisplay == 768) {
823		   ModeIndex = ModeIndex_1024x768[Depth];
824		} else if(VDisplay == 576) {
825		   ModeIndex = ModeIndex_1024x576[Depth];
826		}
827	     }
828	     break;
829	case 1280:
830	     if(VDisplay == 720) {
831		if((VBFlags & TV_HIVISION) ||
832		   ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)))) {
833		   ModeIndex = ModeIndex_1280x720[Depth];
834		}
835	     } else if(VDisplay == 1024) {
836		if((VBFlags & TV_HIVISION) ||
837		   ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) {
838		   ModeIndex = ModeIndex_1280x1024[Depth];
839		}
840	     }
841	     break;
842      }
843   }
844   return ModeIndex;
845}
846
847unsigned short
848SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, int Depth,
849			unsigned int VBFlags2)
850{
851   if(!(VBFlags2 & VB2_SISVGA2BRIDGE)) return 0;
852
853   if(HDisplay >= 1920) return 0;
854
855   switch(HDisplay)
856   {
857	case 1600:
858		if(VDisplay == 1200) {
859			if(VGAEngine != SIS_315_VGA) return 0;
860			if(!(VBFlags2 & VB2_30xB)) return 0;
861		}
862		break;
863	case 1680:
864		if(VDisplay == 1050) {
865			if(VGAEngine != SIS_315_VGA) return 0;
866			if(!(VBFlags2 & VB2_30xB)) return 0;
867		}
868		break;
869   }
870
871   return SiS_GetModeID(VGAEngine, 0, HDisplay, VDisplay, Depth, FALSE, 0, 0);
872}
873
874
875/*********************************************/
876/*          HELPER: SetReg, GetReg           */
877/*********************************************/
878
879void
880SiS_SetReg(SISIOADDRESS port, unsigned short index, unsigned short data)
881{
882   OutPortByte(port, index);
883   OutPortByte(port + 1, data);
884}
885
886void
887SiS_SetRegByte(SISIOADDRESS port, unsigned short data)
888{
889   OutPortByte(port, data);
890}
891
892void
893SiS_SetRegShort(SISIOADDRESS port, unsigned short data)
894{
895   OutPortWord(port, data);
896}
897
898void
899SiS_SetRegLong(SISIOADDRESS port, unsigned int data)
900{
901   OutPortLong(port, data);
902}
903
904unsigned char
905SiS_GetReg(SISIOADDRESS port, unsigned short index)
906{
907   OutPortByte(port, index);
908   return(InPortByte(port + 1));
909}
910
911unsigned char
912SiS_GetRegByte(SISIOADDRESS port)
913{
914   return(InPortByte(port));
915}
916
917unsigned short
918SiS_GetRegShort(SISIOADDRESS port)
919{
920   return(InPortWord(port));
921}
922
923unsigned int
924SiS_GetRegLong(SISIOADDRESS port)
925{
926   return(InPortLong(port));
927}
928
929void
930SiS_SetRegANDOR(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND, unsigned short DataOR)
931{
932   unsigned short temp;
933
934   temp = SiS_GetReg(Port, Index);
935   temp = (temp & (DataAND)) | DataOR;
936   SiS_SetReg(Port, Index, temp);
937}
938
939void
940SiS_SetRegAND(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND)
941{
942   unsigned short temp;
943
944   temp = SiS_GetReg(Port, Index);
945   temp &= DataAND;
946   SiS_SetReg(Port, Index, temp);
947}
948
949void
950SiS_SetRegOR(SISIOADDRESS Port, unsigned short Index, unsigned short DataOR)
951{
952   unsigned short temp;
953
954   temp = SiS_GetReg(Port, Index);
955   temp |= DataOR;
956   SiS_SetReg(Port, Index, temp);
957}
958
959/*********************************************/
960/*      HELPER: DisplayOn, DisplayOff        */
961/*********************************************/
962
963void
964SiS_DisplayOn(struct SiS_Private *SiS_Pr)
965{
966   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xDF);
967}
968
969void
970SiS_DisplayOff(struct SiS_Private *SiS_Pr)
971{
972   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20);
973}
974
975
976/*********************************************/
977/*        HELPER: Init Port Addresses        */
978/*********************************************/
979
980void
981SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr)
982{
983   SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
984   SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
985   SiS_Pr->SiS_P3c0 = BaseAddr + 0x10;
986   SiS_Pr->SiS_P3ce = BaseAddr + 0x1e;
987   SiS_Pr->SiS_P3c2 = BaseAddr + 0x12;
988   SiS_Pr->SiS_P3ca = BaseAddr + 0x1a;
989   SiS_Pr->SiS_P3c6 = BaseAddr + 0x16;
990   SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
991   SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
992   SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
993   SiS_Pr->SiS_P3cb = BaseAddr + 0x1b;
994   SiS_Pr->SiS_P3cc = BaseAddr + 0x1c;
995   SiS_Pr->SiS_P3cd = BaseAddr + 0x1d;
996   SiS_Pr->SiS_P3da = BaseAddr + 0x2a;
997   SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04;
998   SiS_Pr->SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10;
999   SiS_Pr->SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12;
1000   SiS_Pr->SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14;
1001   SiS_Pr->SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2;
1002   SiS_Pr->SiS_DDC_Port  = BaseAddr + 0x14;
1003   SiS_Pr->SiS_VidCapt   = BaseAddr + SIS_VIDEO_CAPTURE;
1004   SiS_Pr->SiS_VidPlay   = BaseAddr + SIS_VIDEO_PLAYBACK;
1005}
1006
1007/*********************************************/
1008/*             HELPER: GetSysFlags           */
1009/*********************************************/
1010
1011static void
1012SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
1013{
1014   unsigned char cr5f, temp1, temp2;
1015
1016   /* 661 and newer: NEVER write non-zero to SR11[7:4] */
1017   /* (SR11 is used for DDC and in enable/disablebridge) */
1018   SiS_Pr->SiS_SensibleSR11 = FALSE;
1019   SiS_Pr->SiS_MyCR63 = 0x63;
1020   if(SiS_Pr->ChipType >= SIS_330) {
1021      SiS_Pr->SiS_MyCR63 = 0x53;
1022      if(SiS_Pr->ChipType >= SIS_661) {
1023         SiS_Pr->SiS_SensibleSR11 = TRUE;
1024      }
1025   }
1026
1027   /* You should use the macros, not these flags directly */
1028
1029   SiS_Pr->SiS_SysFlags = 0;
1030   if(SiS_Pr->ChipType == SIS_650) {
1031      cr5f = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0;
1032      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x5c,0x07);
1033      temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
1034      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x5c,0xf8);
1035      temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
1036      if((!temp1) || (temp2)) {
1037	 switch(cr5f) {
1038	    case 0x80:
1039	    case 0x90:
1040	    case 0xc0:
1041	       SiS_Pr->SiS_SysFlags |= SF_IsM650;
1042	       break;
1043	    case 0xa0:
1044	    case 0xb0:
1045	    case 0xe0:
1046	       SiS_Pr->SiS_SysFlags |= SF_Is651;
1047	       break;
1048	 }
1049      } else {
1050	 switch(cr5f) {
1051	    case 0x90:
1052	       temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
1053	       switch(temp1) {
1054		  case 0x00: SiS_Pr->SiS_SysFlags |= SF_IsM652; break;
1055		  case 0x40: SiS_Pr->SiS_SysFlags |= SF_IsM653; break;
1056		  default:   SiS_Pr->SiS_SysFlags |= SF_IsM650; break;
1057	       }
1058	       break;
1059	    case 0xb0:
1060	       SiS_Pr->SiS_SysFlags |= SF_Is652;
1061	       break;
1062	    default:
1063	       SiS_Pr->SiS_SysFlags |= SF_IsM650;
1064	       break;
1065	 }
1066      }
1067   }
1068
1069   if(SiS_Pr->ChipType >= SIS_760 && SiS_Pr->ChipType <= SIS_761) {
1070      if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x30) {
1071         SiS_Pr->SiS_SysFlags |= SF_760LFB;
1072      }
1073      if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0xf0) {
1074         SiS_Pr->SiS_SysFlags |= SF_760UMA;
1075      }
1076   }
1077}
1078
1079/*********************************************/
1080/*         HELPER: Init PCI & Engines        */
1081/*********************************************/
1082
1083static void
1084SiSInitPCIetc(struct SiS_Private *SiS_Pr)
1085{
1086   switch(SiS_Pr->ChipType) {
1087#ifdef SIS300
1088   case SIS_300:
1089   case SIS_540:
1090   case SIS_630:
1091   case SIS_730:
1092      /* Set - PCI LINEAR ADDRESSING ENABLE (0x80)
1093       *     - RELOCATED VGA IO ENABLED (0x20)
1094       *     - MMIO ENABLED (0x01)
1095       * Leave other bits untouched.
1096       */
1097      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x20,0xa1);
1098      /*  - Enable 2D (0x40)
1099       *  - Enable 3D (0x02)
1100       *  - Enable 3D Vertex command fetch (0x10) ?
1101       *  - Enable 3D command parser (0x08) ?
1102       */
1103      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x5A);
1104      break;
1105#endif
1106#ifdef SIS315H
1107   case SIS_315H:
1108   case SIS_315:
1109   case SIS_315PRO:
1110   case SIS_650:
1111   case SIS_740:
1112   case SIS_330:
1113   case SIS_661:
1114   case SIS_741:
1115   case SIS_660:
1116   case SIS_760:
1117   case SIS_761:
1118   case SIS_340:
1119   case XGI_40:
1120      /* See above */
1121      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x20,0xa1);
1122      /*  - Enable 3D G/L transformation engine (0x80)
1123       *  - Enable 2D (0x40)
1124       *  - Enable 3D vertex command fetch (0x10)
1125       *  - Enable 3D command parser (0x08)
1126       *  - Enable 3D (0x02)
1127       */
1128      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0xDA);
1129      break;
1130   case XGI_20:
1131   case SIS_550:
1132      /* See above */
1133      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x20,0xa1);
1134      /* No 3D engine ! */
1135      /*  - Enable 2D (0x40)
1136       *  - disable 3D
1137       */
1138      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0x60,0x40);
1139      break;
1140#endif
1141   default:
1142      break;
1143   }
1144}
1145
1146/*********************************************/
1147/*             HELPER: SetLVDSetc            */
1148/*********************************************/
1149
1150#ifdef SIS_LINUX_KERNEL
1151static
1152#endif
1153void
1154SiSSetLVDSetc(struct SiS_Private *SiS_Pr)
1155{
1156   unsigned short temp;
1157
1158   SiS_Pr->SiS_IF_DEF_LVDS = 0;
1159   SiS_Pr->SiS_IF_DEF_TRUMPION = 0;
1160   SiS_Pr->SiS_IF_DEF_CH70xx = 0;
1161   SiS_Pr->SiS_IF_DEF_CONEX = 0;
1162
1163   SiS_Pr->SiS_ChrontelInit = 0;
1164
1165   if(SiS_Pr->ChipType == XGI_20) return;
1166
1167   /* Check for SiS30x first */
1168   temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
1169   if((temp == 1) || (temp == 2)) return;
1170
1171   switch(SiS_Pr->ChipType) {
1172#ifdef SIS300
1173   case SIS_540:
1174   case SIS_630:
1175   case SIS_730:
1176	temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x37) & 0x0e) >> 1;
1177	if((temp >= 2) && (temp <= 5))	SiS_Pr->SiS_IF_DEF_LVDS = 1;
1178	if(temp == 3)			SiS_Pr->SiS_IF_DEF_TRUMPION = 1;
1179	if((temp == 4) || (temp == 5)) {
1180		/* Save power status (and error check) - UNUSED */
1181		SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e);
1182		SiS_Pr->SiS_IF_DEF_CH70xx = 1;
1183	}
1184	break;
1185#endif
1186#ifdef SIS315H
1187   case SIS_550:
1188   case SIS_650:
1189   case SIS_740:
1190   case SIS_330:
1191	temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x37) & 0x0e) >> 1;
1192	if((temp >= 2) && (temp <= 3))	SiS_Pr->SiS_IF_DEF_LVDS = 1;
1193	if(temp == 3)			SiS_Pr->SiS_IF_DEF_CH70xx = 2;
1194	break;
1195   case SIS_661:
1196   case SIS_741:
1197   case SIS_660:
1198   case SIS_760:
1199   case SIS_761:
1200   case SIS_340:
1201   case XGI_20:
1202   case XGI_40:
1203	temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & 0xe0) >> 5;
1204	if((temp >= 2) && (temp <= 3)) 	SiS_Pr->SiS_IF_DEF_LVDS = 1;
1205	if(temp == 3)			SiS_Pr->SiS_IF_DEF_CH70xx = 2;
1206	if(temp == 4)			SiS_Pr->SiS_IF_DEF_CONEX = 1;  /* Not yet supported */
1207	break;
1208#endif
1209   default:
1210	break;
1211   }
1212}
1213
1214/*********************************************/
1215/*          HELPER: Enable DSTN/FSTN         */
1216/*********************************************/
1217
1218void
1219SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable)
1220{
1221   SiS_Pr->SiS_IF_DEF_DSTN = enable ? 1 : 0;
1222}
1223
1224void
1225SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable)
1226{
1227   SiS_Pr->SiS_IF_DEF_FSTN = enable ? 1 : 0;
1228}
1229
1230/*********************************************/
1231/*            HELPER: Get modeflag           */
1232/*********************************************/
1233
1234unsigned short
1235SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
1236		unsigned short ModeIdIndex)
1237{
1238   if(SiS_Pr->UseCustomMode) {
1239      return SiS_Pr->CModeFlag;
1240   } else if(ModeNo <= 0x13) {
1241      return SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
1242   } else {
1243      return SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
1244   }
1245}
1246
1247/*********************************************/
1248/*        HELPER: Determine ROM usage        */
1249/*********************************************/
1250
1251BOOLEAN
1252SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr)
1253{
1254   unsigned char  *ROMAddr  = SiS_Pr->VirtualRomBase;
1255   unsigned short romversoffs, romvmaj = 1, romvmin = 0;
1256
1257   if(SiS_Pr->ChipType >= XGI_20) {
1258      /* XGI ROMs don't qualify */
1259      return FALSE;
1260   } else if(SiS_Pr->ChipType >= SIS_761) {
1261      /* I very much assume 761, 340 and newer will use new layout */
1262      return TRUE;
1263   } else if(SiS_Pr->ChipType >= SIS_661) {
1264      if((ROMAddr[0x1a] == 'N') &&
1265	 (ROMAddr[0x1b] == 'e') &&
1266	 (ROMAddr[0x1c] == 'w') &&
1267	 (ROMAddr[0x1d] == 'V')) {
1268	 return TRUE;
1269      }
1270      romversoffs = ROMAddr[0x16] | (ROMAddr[0x17] << 8);
1271      if(romversoffs) {
1272	 if((ROMAddr[romversoffs+1] == '.') || (ROMAddr[romversoffs+4] == '.')) {
1273	    romvmaj = ROMAddr[romversoffs] - '0';
1274	    romvmin = ((ROMAddr[romversoffs+2] -'0') * 10) + (ROMAddr[romversoffs+3] - '0');
1275	 }
1276      }
1277      if((romvmaj != 0) || (romvmin >= 92)) {
1278	 return TRUE;
1279      }
1280   } else if(IS_SIS650740) {
1281      if((ROMAddr[0x1a] == 'N') &&
1282	 (ROMAddr[0x1b] == 'e') &&
1283	 (ROMAddr[0x1c] == 'w') &&
1284	 (ROMAddr[0x1d] == 'V')) {
1285	 return TRUE;
1286      }
1287   }
1288   return FALSE;
1289}
1290
1291static void
1292SiSDetermineROMUsage(struct SiS_Private *SiS_Pr)
1293{
1294   unsigned char  *ROMAddr  = SiS_Pr->VirtualRomBase;
1295   unsigned short romptr = 0;
1296
1297   SiS_Pr->SiS_UseROM = FALSE;
1298   SiS_Pr->SiS_ROMNew = FALSE;
1299   SiS_Pr->SiS_PWDOffset = 0;
1300
1301   if(SiS_Pr->ChipType >= XGI_20) return;
1302
1303   if((ROMAddr) && (SiS_Pr->UseROM)) {
1304      if(SiS_Pr->ChipType == SIS_300) {
1305	 /* 300: We check if the code starts below 0x220 by
1306	  * checking the jmp instruction at the beginning
1307	  * of the BIOS image.
1308	  */
1309	 if((ROMAddr[3] == 0xe9) && ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a)
1310	    SiS_Pr->SiS_UseROM = TRUE;
1311      } else if(SiS_Pr->ChipType < SIS_315H) {
1312	 /* Sony's VAIO BIOS 1.09 follows the standard, so perhaps
1313	  * the others do as well
1314	  */
1315	 SiS_Pr->SiS_UseROM = TRUE;
1316      } else {
1317	 /* 315/330 series stick to the standard(s) */
1318	 SiS_Pr->SiS_UseROM = TRUE;
1319	 if((SiS_Pr->SiS_ROMNew = SiSDetermineROMLayout661(SiS_Pr))) {
1320	    SiS_Pr->SiS_EMIOffset = 14;
1321	    SiS_Pr->SiS_PWDOffset = 17;
1322	    SiS_Pr->SiS661LCD2TableSize = 36;
1323	    /* Find out about LCD data table entry size */
1324	    if((romptr = SISGETROMW(0x0102))) {
1325	       if(ROMAddr[romptr + (32 * 16)] == 0xff)
1326		  SiS_Pr->SiS661LCD2TableSize = 32;
1327	       else if(ROMAddr[romptr + (34 * 16)] == 0xff)
1328		  SiS_Pr->SiS661LCD2TableSize = 34;
1329	       else if(ROMAddr[romptr + (36 * 16)] == 0xff)	   /* 0.94, 2.05.00+ */
1330		  SiS_Pr->SiS661LCD2TableSize = 36;
1331	       else if( (ROMAddr[romptr + (38 * 16)] == 0xff) ||   /* 2.00.00 - 2.02.00 */
1332		 	(ROMAddr[0x6F] & 0x01) ) {		   /* 2.03.00 - <2.05.00 */
1333		  SiS_Pr->SiS661LCD2TableSize = 38;		   /* UMC data layout abandoned at 2.05.00 */
1334		  SiS_Pr->SiS_EMIOffset = 16;
1335		  SiS_Pr->SiS_PWDOffset = 19;
1336	       }
1337	    }
1338	 }
1339      }
1340   }
1341}
1342
1343/*********************************************/
1344/*        HELPER: SET SEGMENT REGISTERS      */
1345/*********************************************/
1346
1347static void
1348SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
1349{
1350   unsigned short temp;
1351
1352   value &= 0x00ff;
1353   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0xf0;
1354   temp |= (value >> 4);
1355   SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp);
1356   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0xf0;
1357   temp |= (value & 0x0f);
1358   SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp);
1359}
1360
1361static void
1362SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
1363{
1364   unsigned short temp;
1365
1366   value &= 0x00ff;
1367   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0x0f;
1368   temp |= (value & 0xf0);
1369   SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp);
1370   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0x0f;
1371   temp |= (value << 4);
1372   SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp);
1373}
1374
1375static void
1376SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
1377{
1378   SiS_SetSegRegLower(SiS_Pr, value);
1379   SiS_SetSegRegUpper(SiS_Pr, value);
1380}
1381
1382static void
1383SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
1384{
1385   SiS_SetSegmentReg(SiS_Pr, 0);
1386}
1387
1388static void
1389SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
1390{
1391   unsigned short temp = value >> 8;
1392
1393   temp &= 0x07;
1394   temp |= (temp << 4);
1395   SiS_SetReg(SiS_Pr->SiS_P3c4,0x1d,temp);
1396   SiS_SetSegmentReg(SiS_Pr, value);
1397}
1398
1399static void
1400SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
1401{
1402   SiS_SetSegmentRegOver(SiS_Pr, 0);
1403}
1404
1405static void
1406SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
1407{
1408   if((IS_SIS65x) || (SiS_Pr->ChipType >= SIS_661)) {
1409      SiS_ResetSegmentReg(SiS_Pr);
1410      SiS_ResetSegmentRegOver(SiS_Pr);
1411   }
1412}
1413
1414/*********************************************/
1415/*             HELPER: GetVBType             */
1416/*********************************************/
1417
1418#ifdef SIS_LINUX_KERNEL
1419static
1420#endif
1421void
1422SiS_GetVBType(struct SiS_Private *SiS_Pr)
1423{
1424   unsigned short flag = 0, rev = 0, nolcd = 0;
1425   unsigned short p4_0f, p4_25, p4_27;
1426
1427   SiS_Pr->SiS_VBType = 0;
1428
1429   if((SiS_Pr->SiS_IF_DEF_LVDS) || (SiS_Pr->SiS_IF_DEF_CONEX))
1430      return;
1431
1432   if(SiS_Pr->ChipType == XGI_20)
1433      return;
1434
1435   flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
1436
1437   if(flag > 3)
1438      return;
1439
1440   rev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01);
1441
1442   if(flag >= 2) {
1443      SiS_Pr->SiS_VBType = VB_SIS302B;
1444   } else if(flag == 1) {
1445      if(rev >= 0xC0) {
1446	 SiS_Pr->SiS_VBType = VB_SIS301C;
1447      } else if(rev >= 0xB0) {
1448	 SiS_Pr->SiS_VBType = VB_SIS301B;
1449	 /* Check if 30xB DH version (no LCD support, use Panel Link instead) */
1450	 nolcd = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x23);
1451	 if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD;
1452      } else {
1453	 SiS_Pr->SiS_VBType = VB_SIS301;
1454      }
1455   }
1456   if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) {
1457      if(rev >= 0xE0) {
1458	 flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39);
1459	 if(flag == 0xff) SiS_Pr->SiS_VBType = VB_SIS302LV;
1460	 else 	 	  SiS_Pr->SiS_VBType = VB_SIS301C;  /* VB_SIS302ELV; */
1461      } else if(rev >= 0xD0) {
1462	 SiS_Pr->SiS_VBType = VB_SIS301LV;
1463      }
1464   }
1465   if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) {
1466      p4_0f = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0f);
1467      p4_25 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x25);
1468      p4_27 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x27);
1469      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0x7f);
1470      SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x25,0x08);
1471      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,0xfd);
1472      if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x08) {
1473         SiS_Pr->SiS_VBType |= VB_UMC;
1474      }
1475      SiS_SetReg(SiS_Pr->SiS_Part4Port,0x27,p4_27);
1476      SiS_SetReg(SiS_Pr->SiS_Part4Port,0x25,p4_25);
1477      SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0f,p4_0f);
1478   }
1479}
1480
1481/*********************************************/
1482/*           HELPER: Check RAM size          */
1483/*********************************************/
1484
1485#ifdef SIS_LINUX_KERNEL
1486static BOOLEAN
1487SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
1488		unsigned short ModeIdIndex)
1489{
1490   unsigned short AdapterMemSize = SiS_Pr->VideoMemorySize / (1024*1024);
1491   unsigned short modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex);
1492   unsigned short memorysize = ((modeflag & MemoryInfoFlag) >> MemorySizeShift) + 1;
1493
1494   if(!AdapterMemSize) return TRUE;
1495
1496   if(AdapterMemSize < memorysize) return FALSE;
1497   return TRUE;
1498}
1499#endif
1500
1501/*********************************************/
1502/*           HELPER: Get DRAM type           */
1503/*********************************************/
1504
1505#ifdef SIS315H
1506static unsigned char
1507SiS_Get310DRAMType(struct SiS_Private *SiS_Pr)
1508{
1509   unsigned char data;
1510
1511   if((*SiS_Pr->pSiS_SoftSetting) & SoftDRAMType) {
1512      data = (*SiS_Pr->pSiS_SoftSetting) & 0x03;
1513   } else {
1514      if(SiS_Pr->ChipType >= XGI_20) {
1515         /* Do I need this? SR17 seems to be zero anyway... */
1516	 data = 0;
1517      } else if(SiS_Pr->ChipType >= SIS_340) {
1518	 /* TODO */
1519	 data = 0;
1520      } if(SiS_Pr->ChipType >= SIS_661) {
1521	 if(SiS_Pr->SiS_ROMNew) {
1522	    data = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0xc0) >> 6);
1523	 } else {
1524	    data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07;
1525	 }
1526      } else if(IS_SIS550650740) {
1527	 data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x07;
1528      } else {	/* 315, 330 */
1529	 data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x03;
1530	 if(SiS_Pr->ChipType == SIS_330) {
1531	    if(data > 1) {
1532	       switch(SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0x30) {
1533	       case 0x00: data = 1; break;
1534	       case 0x10: data = 3; break;
1535	       case 0x20: data = 3; break;
1536	       case 0x30: data = 2; break;
1537	       }
1538	    } else {
1539	       data = 0;
1540	    }
1541	 }
1542      }
1543   }
1544
1545   return data;
1546}
1547
1548static unsigned short
1549SiS_GetMCLK(struct SiS_Private *SiS_Pr)
1550{
1551   unsigned char  *ROMAddr = SiS_Pr->VirtualRomBase;
1552   unsigned short index;
1553
1554   index = SiS_Get310DRAMType(SiS_Pr);
1555   if(SiS_Pr->ChipType >= SIS_661) {
1556      if(SiS_Pr->SiS_ROMNew) {
1557	 return((unsigned short)(SISGETROMW((0x90 + (index * 5) + 3))));
1558      }
1559      return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
1560   } else if(index >= 4) {
1561      return(SiS_Pr->SiS_MCLKData_1[index - 4].CLOCK);
1562   } else {
1563      return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
1564   }
1565}
1566#endif
1567
1568/*********************************************/
1569/*           HELPER: ClearBuffer             */
1570/*********************************************/
1571
1572#ifdef SIS_LINUX_KERNEL
1573static void
1574SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
1575{
1576   unsigned char  SISIOMEMTYPE *memaddr = SiS_Pr->VideoMemoryAddress;
1577   unsigned int   memsize = SiS_Pr->VideoMemorySize;
1578   unsigned short SISIOMEMTYPE *pBuffer;
1579   int i;
1580
1581   if(!memaddr || !memsize) return;
1582
1583   if(SiS_Pr->SiS_ModeType >= ModeEGA) {
1584      if(ModeNo > 0x13) {
1585	 SiS_SetMemory(memaddr, memsize, 0);
1586      } else {
1587	 pBuffer = (unsigned short SISIOMEMTYPE *)memaddr;
1588	 for(i = 0; i < 0x4000; i++) writew(0x0000, &pBuffer[i]);
1589      }
1590   } else if(SiS_Pr->SiS_ModeType < ModeCGA) {
1591      pBuffer = (unsigned short SISIOMEMTYPE *)memaddr;
1592      for(i = 0; i < 0x4000; i++) writew(0x0720, &pBuffer[i]);
1593   } else {
1594      SiS_SetMemory(memaddr, 0x8000, 0);
1595   }
1596}
1597#endif
1598
1599/*********************************************/
1600/*           HELPER: SearchModeID            */
1601/*********************************************/
1602
1603BOOLEAN
1604SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
1605		unsigned short *ModeIdIndex)
1606{
1607   unsigned char VGAINFO = SiS_Pr->SiS_VGAINFO;
1608
1609   if((*ModeNo) <= 0x13) {
1610
1611      if((*ModeNo) <= 0x05) (*ModeNo) |= 0x01;
1612
1613      for((*ModeIdIndex) = 0; ;(*ModeIdIndex)++) {
1614	 if(SiS_Pr->SiS_SModeIDTable[(*ModeIdIndex)].St_ModeID == (*ModeNo)) break;
1615	 if(SiS_Pr->SiS_SModeIDTable[(*ModeIdIndex)].St_ModeID == 0xFF) return FALSE;
1616      }
1617
1618      if((*ModeNo) == 0x07) {
1619	  if(VGAINFO & 0x10) (*ModeIdIndex)++;   /* 400 lines */
1620	  /* else 350 lines */
1621      }
1622      if((*ModeNo) <= 0x03) {
1623	 if(!(VGAINFO & 0x80)) (*ModeIdIndex)++;
1624	 if(VGAINFO & 0x10)    (*ModeIdIndex)++; /* 400 lines  */
1625	 /* else 350 lines  */
1626      }
1627      /* else 200 lines  */
1628
1629   } else {
1630
1631      for((*ModeIdIndex) = 0; ;(*ModeIdIndex)++) {
1632	 if(SiS_Pr->SiS_EModeIDTable[(*ModeIdIndex)].Ext_ModeID == (*ModeNo)) break;
1633	 if(SiS_Pr->SiS_EModeIDTable[(*ModeIdIndex)].Ext_ModeID == 0xFF) return FALSE;
1634      }
1635
1636   }
1637   return TRUE;
1638}
1639
1640/*********************************************/
1641/*            HELPER: GetModePtr             */
1642/*********************************************/
1643
1644unsigned short
1645SiS_GetModePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
1646{
1647   unsigned short index;
1648
1649   if(ModeNo <= 0x13) {
1650      index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
1651   } else {
1652      if(SiS_Pr->SiS_ModeType <= ModeEGA) index = 0x1B;
1653      else index = 0x0F;
1654   }
1655   return index;
1656}
1657
1658/*********************************************/
1659/*         HELPERS: Get some indices         */
1660/*********************************************/
1661
1662unsigned short
1663SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide)
1664{
1665   if(SiS_Pr->SiS_RefIndex[Index].Ext_InfoFlag & HaveWideTiming) {
1666      if(UseWide == 1) {
1667         return SiS_Pr->SiS_RefIndex[Index].Ext_CRTVCLK_WIDE;
1668      } else {
1669         return SiS_Pr->SiS_RefIndex[Index].Ext_CRTVCLK_NORM;
1670      }
1671   } else {
1672      return SiS_Pr->SiS_RefIndex[Index].Ext_CRTVCLK;
1673   }
1674}
1675
1676unsigned short
1677SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide)
1678{
1679   if(SiS_Pr->SiS_RefIndex[Index].Ext_InfoFlag & HaveWideTiming) {
1680      if(UseWide == 1) {
1681         return SiS_Pr->SiS_RefIndex[Index].Ext_CRT1CRTC_WIDE;
1682      } else {
1683         return SiS_Pr->SiS_RefIndex[Index].Ext_CRT1CRTC_NORM;
1684      }
1685   } else {
1686      return SiS_Pr->SiS_RefIndex[Index].Ext_CRT1CRTC;
1687   }
1688}
1689
1690/*********************************************/
1691/*           HELPER: LowModeTests            */
1692/*********************************************/
1693
1694static BOOLEAN
1695SiS_DoLowModeTest(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
1696{
1697   unsigned short temp, temp1, temp2;
1698
1699   if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12))
1700      return TRUE;
1701   temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x11);
1702   SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80);
1703   temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00);
1704   SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,0x55);
1705   temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00);
1706   SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,temp1);
1707   SiS_SetReg(SiS_Pr->SiS_P3d4,0x11,temp);
1708   if((SiS_Pr->ChipType >= SIS_315H) ||
1709      (SiS_Pr->ChipType == SIS_300)) {
1710      if(temp2 == 0x55) return FALSE;
1711      else return TRUE;
1712   } else {
1713      if(temp2 != 0x55) return TRUE;
1714      else {
1715	 SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
1716	 return FALSE;
1717      }
1718   }
1719}
1720
1721static void
1722SiS_SetLowModeTest(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
1723{
1724   if(SiS_DoLowModeTest(SiS_Pr, ModeNo)) {
1725      SiS_Pr->SiS_SetFlag |= LowModeTests;
1726   }
1727}
1728
1729/*********************************************/
1730/*        HELPER: OPEN/CLOSE CRT1 CRTC       */
1731/*********************************************/
1732
1733static void
1734SiS_OpenCRTC(struct SiS_Private *SiS_Pr)
1735{
1736   if(IS_SIS650) {
1737      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
1738      if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20);
1739      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
1740   } else if(IS_SIS661741660760) {
1741      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x61,0xf7);
1742      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
1743      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
1744      if(!SiS_Pr->SiS_ROMNew) {
1745	 SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef);
1746      }
1747   }
1748}
1749
1750static void
1751SiS_CloseCRTC(struct SiS_Private *SiS_Pr)
1752{
1753#if 0 /* This locks some CRTC registers. We don't want that. */
1754   unsigned short temp1 = 0, temp2 = 0;
1755
1756   if(IS_SIS661741660760) {
1757      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
1758         temp1 = 0xa0; temp2 = 0x08;
1759      }
1760      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x51,0x1f,temp1);
1761      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x56,0xe7,temp2);
1762   }
1763#endif
1764}
1765
1766static void
1767SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
1768{
1769   /* Enable CRT1 gating */
1770   SiS_SetRegAND(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0xbf);
1771#if 0
1772   if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) {
1773      if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) ||
1774         (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) {
1775         SiS_SetRegOR(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0x40);
1776      }
1777   }
1778#endif
1779}
1780
1781/*********************************************/
1782/*           HELPER: GetColorDepth           */
1783/*********************************************/
1784
1785unsigned short
1786SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
1787		unsigned short ModeIdIndex)
1788{
1789   static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
1790   unsigned short modeflag;
1791   short index;
1792
1793   /* Do NOT check UseCustomMode, will skrew up FIFO */
1794   if(ModeNo == 0xfe) {
1795      modeflag = SiS_Pr->CModeFlag;
1796   } else if(ModeNo <= 0x13) {
1797      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
1798   } else {
1799      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
1800   }
1801
1802   index = (modeflag & ModeTypeMask) - ModeEGA;
1803   if(index < 0) index = 0;
1804   return ColorDepth[index];
1805}
1806
1807/*********************************************/
1808/*             HELPER: GetOffset             */
1809/*********************************************/
1810
1811unsigned short
1812SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
1813		unsigned short ModeIdIndex, unsigned short RRTI)
1814{
1815   unsigned short xres, temp, colordepth, infoflag;
1816
1817   if(SiS_Pr->UseCustomMode) {
1818      infoflag = SiS_Pr->CInfoFlag;
1819      xres = SiS_Pr->CHDisplay;
1820   } else {
1821      infoflag = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag;
1822      xres = SiS_Pr->SiS_RefIndex[RRTI].XRes;
1823   }
1824
1825   colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex);
1826
1827   temp = xres / 16;
1828   if(infoflag & InterlaceMode) temp <<= 1;
1829   temp *= colordepth;
1830   if(xres % 16) temp += (colordepth >> 1);
1831
1832   return temp;
1833}
1834
1835/*********************************************/
1836/*                   SEQ                     */
1837/*********************************************/
1838
1839static void
1840SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
1841{
1842   unsigned char SRdata;
1843   int i;
1844
1845   SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03);
1846
1847   /* or "display off"  */
1848   SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
1849
1850   /* determine whether to force x8 dotclock */
1851   if((SiS_Pr->SiS_VBType & VB_SISVB) || (SiS_Pr->SiS_IF_DEF_LVDS)) {
1852
1853      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
1854         if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)    SRdata |= 0x01;
1855      } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) SRdata |= 0x01;
1856
1857   }
1858
1859   SiS_SetReg(SiS_Pr->SiS_P3c4,0x01,SRdata);
1860
1861   for(i = 2; i <= 4; i++) {
1862      SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
1863      SiS_SetReg(SiS_Pr->SiS_P3c4,i,SRdata);
1864   }
1865}
1866
1867/*********************************************/
1868/*                  MISC                     */
1869/*********************************************/
1870
1871static void
1872SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
1873{
1874   unsigned char Miscdata;
1875
1876   Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
1877
1878   if(SiS_Pr->ChipType < SIS_661) {
1879      if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
1880	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
1881	   Miscdata |= 0x0C;
1882	 }
1883      }
1884   }
1885
1886   SiS_SetRegByte(SiS_Pr->SiS_P3c2,Miscdata);
1887}
1888
1889/*********************************************/
1890/*                  CRTC                     */
1891/*********************************************/
1892
1893static void
1894SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
1895{
1896   unsigned char  CRTCdata;
1897   unsigned short i;
1898
1899   /* Unlock CRTC */
1900   SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
1901
1902   for(i = 0; i <= 0x18; i++) {
1903      CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
1904      SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata);
1905   }
1906
1907   if(SiS_Pr->ChipType >= SIS_661) {
1908      SiS_OpenCRTC(SiS_Pr);
1909      for(i = 0x13; i <= 0x14; i++) {
1910	 CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
1911	 SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata);
1912      }
1913   } else if( ( (SiS_Pr->ChipType == SIS_630) ||
1914	        (SiS_Pr->ChipType == SIS_730) )  &&
1915	      (SiS_Pr->ChipRevision >= 0x30) ) {
1916      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
1917	 if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
1918	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x18,0xFE);
1919	 }
1920      }
1921   }
1922}
1923
1924/*********************************************/
1925/*                   ATT                     */
1926/*********************************************/
1927
1928static void
1929SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
1930{
1931   unsigned char  ARdata;
1932   unsigned short i;
1933
1934   for(i = 0; i <= 0x13; i++) {
1935      ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
1936
1937      if(i == 0x13) {
1938	 /* Pixel shift. If screen on LCD or TV is shifted left or right,
1939	  * this might be the cause.
1940	  */
1941	 if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
1942	    if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ARdata = 0;
1943	 }
1944	 if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
1945	    if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
1946	       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
1947		  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0;
1948	       }
1949	    }
1950	 }
1951	 if(SiS_Pr->ChipType >= SIS_661) {
1952	    if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) {
1953	       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0;
1954	    }
1955	 } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
1956	    if(SiS_Pr->ChipType >= SIS_315H) {
1957	       if(IS_SIS550650740660) {
1958		  /* 315, 330 don't do this */
1959		  if(SiS_Pr->SiS_VBType & VB_SIS30xB) {
1960		     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0;
1961		  } else {
1962		     ARdata = 0;
1963		  }
1964	       }
1965	    } else {
1966	       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0;
1967	    }
1968	 }
1969      }
1970      SiS_GetRegByte(SiS_Pr->SiS_P3da);		/* reset 3da  */
1971      SiS_SetRegByte(SiS_Pr->SiS_P3c0,i);	/* set index  */
1972      SiS_SetRegByte(SiS_Pr->SiS_P3c0,ARdata);	/* set data   */
1973   }
1974
1975   SiS_GetRegByte(SiS_Pr->SiS_P3da);		/* reset 3da  */
1976   SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x14);	/* set index  */
1977   SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x00);	/* set data   */
1978
1979   SiS_GetRegByte(SiS_Pr->SiS_P3da);
1980   SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x20);	/* Enable Attribute  */
1981   SiS_GetRegByte(SiS_Pr->SiS_P3da);
1982}
1983
1984/*********************************************/
1985/*                   GRC                     */
1986/*********************************************/
1987
1988static void
1989SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
1990{
1991   unsigned char  GRdata;
1992   unsigned short i;
1993
1994   for(i = 0; i <= 0x08; i++) {
1995      GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
1996      SiS_SetReg(SiS_Pr->SiS_P3ce,i,GRdata);
1997   }
1998
1999   if(SiS_Pr->SiS_ModeType > ModeVGA) {
2000      /* 256 color disable */
2001      SiS_SetRegAND(SiS_Pr->SiS_P3ce,0x05,0xBF);
2002   }
2003}
2004
2005/*********************************************/
2006/*          CLEAR EXTENDED REGISTERS         */
2007/*********************************************/
2008
2009static void
2010SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
2011{
2012   unsigned short i;
2013
2014   for(i = 0x0A; i <= 0x0E; i++) {
2015      SiS_SetReg(SiS_Pr->SiS_P3c4,i,0x00);
2016   }
2017
2018   if(SiS_Pr->ChipType >= SIS_315H) {
2019      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE);
2020      if(ModeNo <= 0x13) {
2021	 if(ModeNo == 0x06 || ModeNo >= 0x0e) {
2022	    SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e,0x20);
2023	 }
2024      }
2025   }
2026}
2027
2028/*********************************************/
2029/*                 RESET VCLK                */
2030/*********************************************/
2031
2032static void
2033SiS_ResetCRT1VCLK(struct SiS_Private *SiS_Pr)
2034{
2035   if(SiS_Pr->ChipType >= SIS_315H) {
2036      if(SiS_Pr->ChipType < SIS_661) {
2037	 if(SiS_Pr->SiS_IF_DEF_LVDS == 0) return;
2038      }
2039   } else {
2040      if((SiS_Pr->SiS_IF_DEF_LVDS == 0) &&
2041	 (!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) ) {
2042	 return;
2043      }
2044   }
2045
2046   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x20);
2047   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[1].SR2B);
2048   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[1].SR2C);
2049   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80);
2050   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10);
2051   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[0].SR2B);
2052   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[0].SR2C);
2053   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80);
2054}
2055
2056/*********************************************/
2057/*                  SYNC                     */
2058/*********************************************/
2059
2060static void
2061SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short RRTI)
2062{
2063   unsigned short sync;
2064
2065   if(SiS_Pr->UseCustomMode) {
2066      sync = SiS_Pr->CInfoFlag >> 8;
2067   } else {
2068      sync = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag >> 8;
2069   }
2070
2071   sync &= 0xC0;
2072   sync |= 0x2f;
2073   SiS_SetRegByte(SiS_Pr->SiS_P3c2,sync);
2074}
2075
2076/*********************************************/
2077/*                  CRTC/2                   */
2078/*********************************************/
2079
2080static void
2081SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
2082		unsigned short ModeIdIndex, unsigned short RRTI)
2083{
2084   unsigned short temp, i, j, modeflag;
2085   unsigned char  *crt1data = NULL;
2086
2087   modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex);
2088
2089   if(SiS_Pr->UseCustomMode) {
2090
2091      crt1data = &SiS_Pr->CCRT1CRTC[0];
2092
2093   } else {
2094
2095      temp = SiS_GetRefCRT1CRTC(SiS_Pr, RRTI, SiS_Pr->SiS_UseWide);
2096
2097      /* Alternate for 1600x1200 LCDA */
2098      if((temp == 0x20) && (SiS_Pr->Alternate1600x1200)) temp = 0x57;
2099
2100      crt1data = (unsigned char *)&SiS_Pr->SiS_CRT1Table[temp].CR[0];
2101
2102   }
2103
2104   /* unlock cr0-7 */
2105   SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
2106
2107   for(i = 0, j = 0; i <= 7; i++, j++) {
2108      SiS_SetReg(SiS_Pr->SiS_P3d4,j,crt1data[i]);
2109   }
2110   for(j = 0x10; i <= 10; i++, j++) {
2111      SiS_SetReg(SiS_Pr->SiS_P3d4,j,crt1data[i]);
2112   }
2113   for(j = 0x15; i <= 12; i++, j++) {
2114      SiS_SetReg(SiS_Pr->SiS_P3d4,j,crt1data[i]);
2115   }
2116   for(j = 0x0A; i <= 15; i++, j++) {
2117      SiS_SetReg(SiS_Pr->SiS_P3c4,j,crt1data[i]);
2118   }
2119
2120   SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,crt1data[16] & 0xE0);
2121
2122   temp = (crt1data[16] & 0x01) << 5;
2123   if(modeflag & DoubleScanMode) temp |= 0x80;
2124   SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp);
2125
2126   if(SiS_Pr->SiS_ModeType > ModeVGA) {
2127      SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F);
2128   }
2129
2130#ifdef SIS315H
2131   if(SiS_Pr->ChipType == XGI_20) {
2132      SiS_SetReg(SiS_Pr->SiS_P3d4,0x04,crt1data[4] - 1);
2133      if(!(temp = crt1data[5] & 0x1f)) {
2134         SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0c,0xfb);
2135      }
2136      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x05,0xe0,((temp - 1) & 0x1f));
2137      temp = (crt1data[16] >> 5) + 3;
2138      if(temp > 7) temp -= 7;
2139      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0e,0x1f,(temp << 5));
2140   }
2141#endif
2142}
2143
2144/*********************************************/
2145/*               OFFSET & PITCH              */
2146/*********************************************/
2147/*  (partly overruled by SetPitch() in XF86) */
2148/*********************************************/
2149
2150static void
2151SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
2152		unsigned short ModeIdIndex, unsigned short RRTI)
2153{
2154   unsigned short temp, DisplayUnit, infoflag;
2155
2156   if(SiS_Pr->UseCustomMode) {
2157      infoflag = SiS_Pr->CInfoFlag;
2158   } else {
2159      infoflag = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag;
2160   }
2161
2162   DisplayUnit = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, RRTI);
2163
2164   temp = (DisplayUnit >> 8) & 0x0f;
2165   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,temp);
2166
2167   SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,DisplayUnit & 0xFF);
2168
2169   if(infoflag & InterlaceMode) DisplayUnit >>= 1;
2170
2171   DisplayUnit <<= 5;
2172   temp = (DisplayUnit >> 8) + 1;
2173   if(DisplayUnit & 0xff) temp++;
2174   if(SiS_Pr->ChipType == XGI_20) {
2175      if(ModeNo == 0x4a || ModeNo == 0x49) temp--;
2176   }
2177   SiS_SetReg(SiS_Pr->SiS_P3c4,0x10,temp);
2178}
2179
2180/*********************************************/
2181/*                  VCLK                     */
2182/*********************************************/
2183
2184static void
2185SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
2186		unsigned short ModeIdIndex, unsigned short RRTI)
2187{
2188   unsigned short index = 0, clka, clkb;
2189
2190   if(SiS_Pr->UseCustomMode) {
2191      clka = SiS_Pr->CSR2B;
2192      clkb = SiS_Pr->CSR2C;
2193   } else {
2194      index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RRTI);
2195      if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) &&
2196	 (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
2197	 /* Alternate for 1600x1200 LCDA */
2198	 if((index == 0x21) && (SiS_Pr->Alternate1600x1200)) index = 0x72;
2199	 clka = SiS_Pr->SiS_VBVCLKData[index].Part4_A;
2200	 clkb = SiS_Pr->SiS_VBVCLKData[index].Part4_B;
2201      } else {
2202	 clka = SiS_Pr->SiS_VCLKData[index].SR2B;
2203	 clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
2204      }
2205   }
2206
2207   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF);
2208
2209   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2b,clka);
2210   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,clkb);
2211
2212   if(SiS_Pr->ChipType >= SIS_315H) {
2213#ifdef SIS315H
2214      SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01);
2215      if(SiS_Pr->ChipType == XGI_20) {
2216         unsigned short mf = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex);
2217	 if(mf & HalfDCLK) {
2218	    SiS_SetReg(SiS_Pr->SiS_P3c4,0x2b,SiS_GetReg(SiS_Pr->SiS_P3c4,0x2b));
2219	    clkb = SiS_GetReg(SiS_Pr->SiS_P3c4,0x2c);
2220	    clkb = (((clkb & 0x1f) << 1) + 1) | (clkb & 0xe0);
2221	    SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,clkb);
2222	 }
2223      }
2224#endif
2225   } else {
2226      SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80);
2227   }
2228}
2229
2230/*********************************************/
2231/*                  FIFO                     */
2232/*********************************************/
2233
2234#ifdef SIS300
2235void
2236SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1,
2237		unsigned short *idx2)
2238{
2239   unsigned short temp1, temp2;
2240   static const unsigned char ThTiming[8] = {
2241		1, 2, 2, 3, 0, 1, 1, 2
2242   };
2243
2244   temp1 = temp2 = (SiS_GetReg(SiS_Pr->SiS_P3c4,0x18) & 0x62) >> 1;
2245   (*idx2) = (unsigned short)(ThTiming[((temp2 >> 3) | temp1) & 0x07]);
2246   (*idx1) = (unsigned short)(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) >> 6) & 0x03;
2247   (*idx1) |= (unsigned short)(((SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) >> 4) & 0x0c));
2248   (*idx1) <<= 1;
2249}
2250
2251static unsigned short
2252SiS_GetFIFOThresholdA300(unsigned short idx1, unsigned short idx2)
2253{
2254   static const unsigned char ThLowA[8 * 3] = {
2255		61, 3,52, 5,68, 7,100,11,
2256		43, 3,42, 5,54, 7, 78,11,
2257		34, 3,37, 5,47, 7, 67,11
2258   };
2259
2260   return (unsigned short)((ThLowA[idx1 + 1] * idx2) + ThLowA[idx1]);
2261}
2262
2263unsigned short
2264SiS_GetFIFOThresholdB300(unsigned short idx1, unsigned short idx2)
2265{
2266   static const unsigned char ThLowB[8 * 3] = {
2267		81, 4,72, 6,88, 8,120,12,
2268		55, 4,54, 6,66, 8, 90,12,
2269		42, 4,45, 6,55, 8, 75,12
2270   };
2271
2272   return (unsigned short)((ThLowB[idx1 + 1] * idx2) + ThLowB[idx1]);
2273}
2274
2275static unsigned short
2276SiS_DoCalcDelay(struct SiS_Private *SiS_Pr, unsigned short MCLK, unsigned short VCLK,
2277		unsigned short colordepth, unsigned short key)
2278{
2279   unsigned short idx1, idx2;
2280   unsigned int   longtemp = VCLK * colordepth;
2281
2282   SiS_GetFIFOThresholdIndex300(SiS_Pr, &idx1, &idx2);
2283
2284   if(key == 0) {
2285      longtemp *= SiS_GetFIFOThresholdA300(idx1, idx2);
2286   } else {
2287      longtemp *= SiS_GetFIFOThresholdB300(idx1, idx2);
2288   }
2289   idx1 = longtemp % (MCLK * 16);
2290   longtemp /= (MCLK * 16);
2291   if(idx1) longtemp++;
2292   return (unsigned short)longtemp;
2293}
2294
2295static unsigned short
2296SiS_CalcDelay(struct SiS_Private *SiS_Pr, unsigned short VCLK,
2297		unsigned short colordepth, unsigned short MCLK)
2298{
2299   unsigned short temp1, temp2;
2300
2301   temp2 = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0);
2302   temp1 = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1);
2303   if(temp1 < 4) temp1 = 4;
2304   temp1 -= 4;
2305   if(temp2 < temp1) temp2 = temp1;
2306   return temp2;
2307}
2308
2309static void
2310SiS_SetCRT1FIFO_300(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
2311		unsigned short RefreshRateTableIndex)
2312{
2313   unsigned short ThresholdLow = 0;
2314   unsigned short temp, index, VCLK, MCLK, colorth;
2315   static const unsigned short colortharray[6] = { 1, 1, 2, 2, 3, 4 };
2316
2317   if(ModeNo > 0x13) {
2318
2319      /* Get VCLK  */
2320      if(SiS_Pr->UseCustomMode) {
2321	 VCLK = SiS_Pr->CSRClock;
2322      } else {
2323	 index = SiS_GetRefCRTVCLK(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWide);
2324	 VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
2325      }
2326
2327      /* Get half colordepth */
2328      colorth = colortharray[(SiS_Pr->SiS_ModeType - ModeEGA)];
2329
2330      /* Get MCLK  */
2331      index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A) & 0x07;
2332      MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;
2333
2334      temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xc3;
2335      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,temp);
2336
2337      do {
2338	 ThresholdLow = SiS_CalcDelay(SiS_Pr, VCLK, colorth, MCLK) + 1;
2339	 if(ThresholdLow < 0x13) break;
2340	 SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc);
2341	 ThresholdLow = 0x13;
2342	 temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) >> 6;
2343	 if(!temp) break;
2344	 SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,((temp - 1) << 6));
2345      } while(0);
2346
2347   } else ThresholdLow = 2;
2348
2349   /* Write CRT/CPU threshold low, CRT/Engine threshold high */
2350   temp = (ThresholdLow << 4) | 0x0f;
2351   SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,temp);
2352
2353   temp = (ThresholdLow & 0x10) << 1;
2354   if(ModeNo > 0x13) temp |= 0x40;
2355   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp);
2356
2357   /* What is this? */
2358   SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09);
2359
2360   /* Write CRT/CPU threshold high */
2361   temp = ThresholdLow + 3;
2362   if(temp > 0x0f) temp = 0x0f;
2363   SiS_SetReg(SiS_Pr->SiS_P3c4,0x09,temp);
2364}
2365
2366unsigned short
2367SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index)
2368{
2369   static const unsigned char LatencyFactor[] = {
2370		97, 88, 86, 79, 77,  0,       /* 64  bit    BQ=2   */
2371		 0, 87, 85, 78, 76, 54,       /* 64  bit    BQ=1   */
2372		97, 88, 86, 79, 77,  0,       /* 128 bit    BQ=2   */
2373		 0, 79, 77, 70, 68, 48,       /* 128 bit    BQ=1   */
2374		80, 72, 69, 63, 61,  0,       /* 64  bit    BQ=2   */
2375		 0, 70, 68, 61, 59, 37,       /* 64  bit    BQ=1   */
2376		86, 77, 75, 68, 66,  0,       /* 128 bit    BQ=2   */
2377		 0, 68, 66, 59, 57, 37        /* 128 bit    BQ=1   */
2378   };
2379   static const unsigned char LatencyFactor730[] = {
2380		 69, 63, 61,
2381		 86, 79, 77,
2382		103, 96, 94,
2383		120,113,111,
2384		137,130,128
2385   };
2386
2387   if(SiS_Pr->ChipType == SIS_730) {
2388      return (unsigned short)LatencyFactor730[index];
2389   } else {
2390      return (unsigned short)LatencyFactor[index];
2391   }
2392}
2393
2394static unsigned short
2395SiS_CalcDelay2(struct SiS_Private *SiS_Pr, unsigned char key)
2396{
2397   unsigned short index;
2398
2399   if(SiS_Pr->ChipType == SIS_730) {
2400      index = ((key & 0x0f) * 3) + ((key & 0xc0) >> 6);
2401   } else {
2402      index = (key & 0xe0) >> 5;
2403      if(key & 0x10)    index +=  6;
2404      if(!(key & 0x01)) index += 24;
2405      if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x80) index += 12;
2406   }
2407   return SiS_GetLatencyFactor630(SiS_Pr, index);
2408}
2409
2410static void
2411SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
2412                    unsigned short RefreshRateTableIndex)
2413{
2414   unsigned short  ThresholdLow = 0;
2415   unsigned short  i, data, VCLK, MCLK16, colorth = 0;
2416   unsigned int    templ, datal;
2417   const unsigned char *queuedata = NULL;
2418   static const unsigned char FQBQData[21] = {
2419		0x01,0x21,0x41,0x61,0x81,
2420		0x31,0x51,0x71,0x91,0xb1,
2421		0x00,0x20,0x40,0x60,0x80,
2422		0x30,0x50,0x70,0x90,0xb0,
2423		0xff
2424   };
2425   static const unsigned char FQBQData730[16] = {
2426		0x34,0x74,0xb4,
2427		0x23,0x63,0xa3,
2428		0x12,0x52,0x92,
2429		0x01,0x41,0x81,
2430		0x00,0x40,0x80,
2431		0xff
2432   };
2433   static const unsigned short colortharray[6] = {
2434		1, 1, 2, 2, 3, 4
2435   };
2436
2437   i = 0;
2438
2439   if(ModeNo > 0x13) {
2440
2441      /* Get VCLK  */
2442      if(SiS_Pr->UseCustomMode) {
2443	 VCLK = SiS_Pr->CSRClock;
2444      } else {
2445	 data = SiS_GetRefCRTVCLK(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWide);
2446	 VCLK = SiS_Pr->SiS_VCLKData[data].CLOCK;
2447      }
2448
2449      /* Get MCLK * 16 */
2450      data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A) & 0x07;
2451      MCLK16 = SiS_Pr->SiS_MCLKData_0[data].CLOCK * 16;
2452
2453      /* Get half colordepth */
2454      colorth = colortharray[(SiS_Pr->SiS_ModeType - ModeEGA)];
2455
2456      if(SiS_Pr->ChipType == SIS_730) {
2457	 queuedata = &FQBQData730[0];
2458      } else {
2459	 queuedata = &FQBQData[0];
2460      }
2461
2462      do {
2463	 templ = SiS_CalcDelay2(SiS_Pr, queuedata[i]) * VCLK * colorth;
2464
2465	 datal = templ % MCLK16;
2466	 templ = (templ / MCLK16) + 1;
2467	 if(datal) templ++;
2468
2469	 if(templ > 0x13) {
2470	    if(queuedata[i + 1] == 0xFF) {
2471	       ThresholdLow = 0x13;
2472	       break;
2473	    }
2474	    i++;
2475	 } else {
2476	    ThresholdLow = templ;
2477	    break;
2478	 }
2479      } while(queuedata[i] != 0xFF);
2480
2481   } else {
2482
2483      if(SiS_Pr->ChipType != SIS_730) i = 9;
2484      ThresholdLow = 0x02;
2485
2486   }
2487
2488   /* Write CRT/CPU threshold low, CRT/Engine threshold high */
2489   data = ((ThresholdLow & 0x0f) << 4) | 0x0f;
2490   SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,data);
2491
2492   data = (ThresholdLow & 0x10) << 1;
2493   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data);
2494
2495   /* What is this? */
2496   SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09);
2497
2498   /* Write CRT/CPU threshold high (gap = 3) */
2499   data = ThresholdLow + 3;
2500   if(data > 0x0f) data = 0x0f;
2501   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data);
2502
2503  /* Write foreground and background queue */
2504#ifdef SIS_LINUX_KERNEL
2505   templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50);
2506#else
2507   templ = sis_pci_read_host_bridge_u32(0x50);
2508#endif
2509
2510   if(SiS_Pr->ChipType == SIS_730) {
2511
2512      templ &= 0xfffff9ff;
2513      templ |= ((queuedata[i] & 0xc0) << 3);
2514
2515   } else {
2516
2517      templ &= 0xf0ffffff;
2518      if( (ModeNo <= 0x13) &&
2519          (SiS_Pr->ChipType == SIS_630) &&
2520	  (SiS_Pr->ChipRevision >= 0x30) ) {
2521	 templ |= 0x0b000000;
2522      } else {
2523         templ |= ((queuedata[i] & 0xf0) << 20);
2524      }
2525
2526   }
2527
2528#ifdef SIS_LINUX_KERNEL
2529   sisfb_write_nbridge_pci_dword(SiS_Pr, 0x50, templ);
2530   templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xA0);
2531#else
2532   sis_pci_write_host_bridge_u32(0x50, templ);
2533   templ = sis_pci_read_host_bridge_u32(0xA0);
2534#endif
2535
2536   /* GUI grant timer (PCI config 0xA3) */
2537   if(SiS_Pr->ChipType == SIS_730) {
2538
2539      templ &= 0x00ffffff;
2540      datal = queuedata[i] << 8;
2541      templ |= (((datal & 0x0f00) | ((datal & 0x3000) >> 8)) << 20);
2542
2543   } else {
2544
2545      templ &= 0xf0ffffff;
2546      templ |= ((queuedata[i] & 0x0f) << 24);
2547
2548   }
2549
2550#ifdef SIS_LINUX_KERNEL
2551   sisfb_write_nbridge_pci_dword(SiS_Pr, 0xA0, templ);
2552#else
2553   sis_pci_write_host_bridge_u32(0xA0, templ);
2554#endif
2555}
2556#endif /* SIS300 */
2557
2558#ifdef SIS315H
2559static void
2560SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
2561{
2562   unsigned short modeflag;
2563
2564   /* disable auto-threshold */
2565   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE);
2566
2567   modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex);
2568
2569   SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE);
2570   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
2571   if(ModeNo > 0x13) {
2572      if(SiS_Pr->ChipType >= XGI_20) {
2573	 SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34);
2574	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
2575      } else if(SiS_Pr->ChipType >= SIS_661) {
2576	 if(!(modeflag & HalfDCLK)) {
2577	    SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34);
2578	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
2579	 }
2580      } else {
2581	 if((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
2582	    SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34);
2583	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
2584	 }
2585      }
2586   }
2587}
2588#endif
2589
2590/*********************************************/
2591/*              MODE REGISTERS               */
2592/*********************************************/
2593
2594static void
2595SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
2596		unsigned short RefreshRateTableIndex, unsigned short ModeIdIndex)
2597{
2598   unsigned short data = 0, VCLK = 0, index = 0;
2599
2600   if(ModeNo > 0x13) {
2601      if(SiS_Pr->UseCustomMode) {
2602         VCLK = SiS_Pr->CSRClock;
2603      } else {
2604         index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
2605         VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
2606      }
2607   }
2608
2609   if(SiS_Pr->ChipType < SIS_315H) {
2610#ifdef SIS300
2611      if(VCLK > 150) data |= 0x80;
2612      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data);
2613
2614      data = 0x00;
2615      if(VCLK >= 150) data |= 0x08;
2616      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data);
2617#endif
2618   } else if(SiS_Pr->ChipType < XGI_20) {
2619#ifdef SIS315H
2620      if(VCLK >= 166) data |= 0x0c;
2621      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
2622
2623      if(VCLK >= 166) {
2624         SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7);
2625      }
2626#endif
2627   } else {
2628#ifdef SIS315H
2629      if(VCLK >= 200) data |= 0x0c;
2630      if(SiS_Pr->ChipType == XGI_20) data &= ~0x04;
2631      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
2632      if(SiS_Pr->ChipType != XGI_20) {
2633         data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xe7;
2634	 if(VCLK < 200) data |= 0x10;
2635	 SiS_SetReg(SiS_Pr->SiS_P3c4,0x1f,data);
2636      }
2637#endif
2638   }
2639
2640   /* DAC speed */
2641   if(SiS_Pr->ChipType >= SIS_661) {
2642
2643      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xE8,0x10);
2644
2645   } else {
2646
2647      data = 0x03;
2648      if(VCLK >= 260)      data = 0x00;
2649      else if(VCLK >= 160) data = 0x01;
2650      else if(VCLK >= 135) data = 0x02;
2651
2652      if(SiS_Pr->ChipType == SIS_540) {
2653         if((VCLK == 203) || (VCLK < 234)) data = 0x02;
2654      }
2655
2656      if(SiS_Pr->ChipType < SIS_315H) {
2657         SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data);
2658      } else {
2659         if(SiS_Pr->ChipType > SIS_315PRO) {
2660            if(ModeNo > 0x13) data &= 0xfc;
2661         }
2662         SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data);
2663      }
2664
2665   }
2666}
2667
2668static void
2669SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
2670		unsigned short ModeIdIndex, unsigned short RRTI)
2671{
2672   unsigned short data, infoflag = 0, modeflag, resindex;
2673#ifdef SIS315H
2674   unsigned char  *ROMAddr  = SiS_Pr->VirtualRomBase;
2675   unsigned short data2, data3;
2676#endif
2677
2678   modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex);
2679
2680   if(SiS_Pr->UseCustomMode) {
2681      infoflag = SiS_Pr->CInfoFlag;
2682   } else {
2683      resindex = SiS_GetResInfo(SiS_Pr, ModeNo, ModeIdIndex);
2684      if(ModeNo > 0x13) {
2685	 infoflag = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag;
2686      }
2687   }
2688
2689   /* Disable DPMS */
2690   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F);
2691
2692   data = 0;
2693   if(ModeNo > 0x13) {
2694      if(SiS_Pr->SiS_ModeType > ModeEGA) {
2695         data |= 0x02;
2696         data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
2697      }
2698      if(infoflag & InterlaceMode) data |= 0x20;
2699   }
2700   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data);
2701
2702   if(SiS_Pr->ChipType != SIS_300) {
2703      data = 0;
2704      if(infoflag & InterlaceMode) {
2705	 /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
2706	 int hrs = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x04) |
2707		    ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x0b) & 0xc0) << 2)) - 3;
2708	 int hto = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x00) |
2709		    ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x0b) & 0x03) << 8)) + 5;
2710	 data = hrs - (hto >> 1) + 3;
2711      }
2712      SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,data);
2713      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,((data >> 8) & 0x03));
2714   }
2715
2716   if(modeflag & HalfDCLK) {
2717      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08);
2718   }
2719
2720   data = 0;
2721   if(modeflag & LineCompareOff) data = 0x08;
2722   if(SiS_Pr->ChipType == SIS_300) {
2723      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xF7,data);
2724   } else {
2725      if(SiS_Pr->ChipType >= XGI_20) data |= 0x20;
2726      if(SiS_Pr->SiS_ModeType == ModeEGA) {
2727	 if(ModeNo > 0x13) {
2728	    data |= 0x40;
2729	 }
2730      }
2731      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data);
2732   }
2733
2734#ifdef SIS315H
2735   if(SiS_Pr->ChipType >= SIS_315H) {
2736      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb);
2737   }
2738
2739   if(SiS_Pr->ChipType == SIS_315PRO) {
2740
2741      data = SiS_Pr->SiS_SR15[(2 * 4) + SiS_Get310DRAMType(SiS_Pr)];
2742      if(SiS_Pr->SiS_ModeType == ModeText) {
2743	 data &= 0xc7;
2744      } else {
2745	 data2 = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, RRTI) >> 1;
2746	 if(infoflag & InterlaceMode) data2 >>= 1;
2747	 data3 = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex) >> 1;
2748	 if(data3) data2 /= data3;
2749	 if(data2 >= 0x50) {
2750	    data &= 0x0f;
2751	    data |= 0x50;
2752	 }
2753      }
2754      SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data);
2755
2756   } else if((SiS_Pr->ChipType == SIS_330) || (SiS_Pr->SiS_SysFlags & SF_760LFB)) {
2757
2758      data = SiS_Get310DRAMType(SiS_Pr);
2759      if(SiS_Pr->ChipType == SIS_330) {
2760	 data = SiS_Pr->SiS_SR15[(2 * 4) + data];
2761      } else {
2762	 if(SiS_Pr->SiS_ROMNew)	     data = ROMAddr[0xf6];
2763	 else if(SiS_Pr->SiS_UseROM) data = ROMAddr[0x100 + data];
2764	 else			     data = 0xba;
2765      }
2766      if(SiS_Pr->SiS_ModeType <= ModeEGA) {
2767	 data &= 0xc7;
2768      } else {
2769	 if(SiS_Pr->UseCustomMode) {
2770	    data2 = SiS_Pr->CSRClock;
2771	 } else {
2772	    data2 = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RRTI);
2773	    data2 = SiS_Pr->SiS_VCLKData[data2].CLOCK;
2774	 }
2775
2776	 data3 = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex) >> 1;
2777	 if(data3) data2 *= data3;
2778
2779	 data2 = ((unsigned int)(SiS_GetMCLK(SiS_Pr) * 1024)) / data2;
2780
2781	 if(SiS_Pr->ChipType == SIS_330) {
2782	    if(SiS_Pr->SiS_ModeType != Mode16Bpp) {
2783	       if     (data2 >= 0x19c) data = 0xba;
2784	       else if(data2 >= 0x140) data = 0x7a;
2785	       else if(data2 >= 0x101) data = 0x3a;
2786	       else if(data2 >= 0xf5)  data = 0x32;
2787	       else if(data2 >= 0xe2)  data = 0x2a;
2788	       else if(data2 >= 0xc4)  data = 0x22;
2789	       else if(data2 >= 0xac)  data = 0x1a;
2790	       else if(data2 >= 0x9e)  data = 0x12;
2791	       else if(data2 >= 0x8e)  data = 0x0a;
2792	       else                    data = 0x02;
2793	    } else {
2794	       if(data2 >= 0x127)      data = 0xba;
2795	       else                    data = 0x7a;
2796	    }
2797	 } else {  /* 76x+LFB */
2798	    if     (data2 >= 0x190) data = 0xba;
2799	    else if(data2 >= 0xff)  data = 0x7a;
2800	    else if(data2 >= 0xd3)  data = 0x3a;
2801	    else if(data2 >= 0xa9)  data = 0x1a;
2802	    else if(data2 >= 0x93)  data = 0x0a;
2803	    else                    data = 0x02;
2804	 }
2805      }
2806      SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data);
2807
2808   }
2809      /* XGI: Nothing. */
2810      /* TODO: Check SiS340 */
2811#endif
2812
2813   data = 0x60;
2814   if(SiS_Pr->SiS_ModeType != ModeText) {
2815      data ^= 0x60;
2816      if(SiS_Pr->SiS_ModeType != ModeEGA) {
2817         data ^= 0xA0;
2818      }
2819   }
2820   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data);
2821
2822   SiS_SetVCLKState(SiS_Pr, ModeNo, RRTI, ModeIdIndex);
2823
2824#ifdef SIS315H
2825   if(((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) ||
2826       (SiS_Pr->ChipType == XGI_40)) {
2827      if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
2828         SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x2c);
2829      } else {
2830         SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x6c);
2831      }
2832   } else if(SiS_Pr->ChipType == XGI_20) {
2833      if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
2834         SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x33);
2835      } else {
2836         SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x73);
2837      }
2838      SiS_SetReg(SiS_Pr->SiS_P3d4,0x51,0x02);
2839   }
2840#endif
2841}
2842
2843#ifdef SIS315H
2844static void
2845SiS_SetupDualChip(struct SiS_Private *SiS_Pr)
2846{
2847#if 0
2848   /* TODO: Find out about IOAddress2 */
2849   SISIOADDRESS P2_3c2 = SiS_Pr->IOAddress2 + 0x12;
2850   SISIOADDRESS P2_3c4 = SiS_Pr->IOAddress2 + 0x14;
2851   SISIOADDRESS P2_3ce = SiS_Pr->IOAddress2 + 0x1e;
2852   int i;
2853
2854   if((SiS_Pr->ChipRevision != 0) ||
2855      (!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x04)))
2856      return;
2857
2858   for(i = 0; i <= 4; i++) {					/* SR00 - SR04 */
2859      SiS_SetReg(P2_3c4,i,SiS_GetReg(SiS_Pr->SiS_P3c4,i));
2860   }
2861   for(i = 0; i <= 8; i++) {					/* GR00 - GR08 */
2862      SiS_SetReg(P2_3ce,i,SiS_GetReg(SiS_Pr->SiS_P3ce,i));
2863   }
2864   SiS_SetReg(P2_3c4,0x05,0x86);
2865   SiS_SetReg(P2_3c4,0x06,SiS_GetReg(SiS_Pr->SiS_P3c4,0x06));	/* SR06 */
2866   SiS_SetReg(P2_3c4,0x21,SiS_GetReg(SiS_Pr->SiS_P3c4,0x21));	/* SR21 */
2867   SiS_SetRegByte(P2_3c2,SiS_GetRegByte(SiS_Pr->SiS_P3cc));	/* MISC */
2868   SiS_SetReg(P2_3c4,0x05,0x00);
2869#endif
2870}
2871#endif
2872
2873/*********************************************/
2874/*                 LOAD DAC                  */
2875/*********************************************/
2876
2877static void
2878SiS_WriteDAC(struct SiS_Private *SiS_Pr, SISIOADDRESS DACData, unsigned short shiftflag,
2879             unsigned short dl, unsigned short ah, unsigned short al, unsigned short dh)
2880{
2881   unsigned short d1, d2, d3;
2882
2883   switch(dl) {
2884   case  0: d1 = dh; d2 = ah; d3 = al; break;
2885   case  1: d1 = ah; d2 = al; d3 = dh; break;
2886   default: d1 = al; d2 = dh; d3 = ah;
2887   }
2888   SiS_SetRegByte(DACData, (d1 << shiftflag));
2889   SiS_SetRegByte(DACData, (d2 << shiftflag));
2890   SiS_SetRegByte(DACData, (d3 << shiftflag));
2891}
2892
2893void
2894SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
2895{
2896   unsigned short data, data2, time, i, j, k, m, n, o;
2897   unsigned short si, di, bx, sf;
2898   SISIOADDRESS DACAddr, DACData;
2899   const unsigned char *table = NULL;
2900
2901   data = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex) & DACInfoFlag;
2902
2903   j = time = 64;
2904   if(data == 0x00)      table = SiS_MDA_DAC;
2905   else if(data == 0x08) table = SiS_CGA_DAC;
2906   else if(data == 0x10) table = SiS_EGA_DAC;
2907   else if(data == 0x18) {
2908      j = 16;
2909      time = 256;
2910      table = SiS_VGA_DAC;
2911   }
2912
2913   if( ( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&        /* 301B-DH LCD */
2914         (SiS_Pr->SiS_VBType & VB_NoLCD) )        ||
2915       (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)       ||   /* LCDA */
2916       (!(SiS_Pr->SiS_SetFlag & ProgrammingCRT2)) ) {  /* Programming CRT1 */
2917      SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
2918      DACAddr = SiS_Pr->SiS_P3c8;
2919      DACData = SiS_Pr->SiS_P3c9;
2920      sf = 0;
2921   } else {
2922      DACAddr = SiS_Pr->SiS_Part5Port;
2923      DACData = SiS_Pr->SiS_Part5Port + 1;
2924      sf = 2;
2925   }
2926
2927   SiS_SetRegByte(DACAddr,0x00);
2928
2929   for(i = 0; i < j; i++) {
2930      data = table[i];
2931      for(k = 0; k < 3; k++) {
2932	data2 = 0;
2933	if(data & 0x01) data2 += 0x2A;
2934	if(data & 0x02) data2 += 0x15;
2935	SiS_SetRegByte(DACData, (data2 << sf));
2936	data >>= 2;
2937      }
2938   }
2939
2940   if(time == 256) {
2941      for(i = 16; i < 32; i++) {
2942	 data = table[i] << sf;
2943	 for(k = 0; k < 3; k++) SiS_SetRegByte(DACData, data);
2944      }
2945      si = 32;
2946      for(m = 0; m < 9; m++) {
2947	 di = si;
2948	 bx = si + 4;
2949	 for(n = 0; n < 3; n++) {
2950	    for(o = 0; o < 5; o++) {
2951	       SiS_WriteDAC(SiS_Pr, DACData, sf, n, table[di], table[bx], table[si]);
2952	       si++;
2953	    }
2954	    si -= 2;
2955	    for(o = 0; o < 3; o++) {
2956	       SiS_WriteDAC(SiS_Pr, DACData, sf, n, table[di], table[si], table[bx]);
2957	       si--;
2958	    }
2959	 }            /* for n < 3 */
2960	 si += 5;
2961      }               /* for m < 9 */
2962   }
2963}
2964
2965/*********************************************/
2966/*         SET CRT1 REGISTER GROUP           */
2967/*********************************************/
2968
2969static void
2970SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
2971{
2972   unsigned short StandTableIndex, RefreshRateTableIndex;
2973
2974   SiS_Pr->SiS_CRT1Mode = ModeNo;
2975
2976   StandTableIndex = SiS_GetModePtr(SiS_Pr, ModeNo, ModeIdIndex);
2977
2978   if(SiS_Pr->SiS_SetFlag & LowModeTests) {
2979      if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2)) {
2980         SiS_DisableBridge(SiS_Pr);
2981      }
2982   }
2983
2984   SiS_ResetSegmentRegisters(SiS_Pr);
2985
2986   SiS_SetSeqRegs(SiS_Pr, StandTableIndex);
2987   SiS_SetMiscRegs(SiS_Pr, StandTableIndex);
2988   SiS_SetCRTCRegs(SiS_Pr, StandTableIndex);
2989   SiS_SetATTRegs(SiS_Pr, StandTableIndex);
2990   SiS_SetGRCRegs(SiS_Pr, StandTableIndex);
2991   SiS_ClearExt1Regs(SiS_Pr, ModeNo);
2992   SiS_ResetCRT1VCLK(SiS_Pr);
2993
2994   SiS_Pr->SiS_SelectCRT2Rate = 0;
2995   SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
2996
2997#ifdef SIS_XORG_XF86
2998   xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n",
2999                    SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo);
3000#endif
3001
3002   if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
3003      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
3004         SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
3005      }
3006   }
3007
3008   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
3009      SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
3010   }
3011
3012   RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex);
3013
3014   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
3015      SiS_Pr->SiS_SetFlag &= ~ProgrammingCRT2;
3016   }
3017
3018   if(RefreshRateTableIndex != 0xFFFF) {
3019      SiS_SetCRT1Sync(SiS_Pr, RefreshRateTableIndex);
3020      SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
3021      SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
3022      SiS_SetCRT1VCLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
3023   }
3024
3025   switch(SiS_Pr->ChipType) {
3026#ifdef SIS300
3027   case SIS_300:
3028      SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo, RefreshRateTableIndex);
3029      break;
3030   case SIS_540:
3031   case SIS_630:
3032   case SIS_730:
3033      SiS_SetCRT1FIFO_630(SiS_Pr, ModeNo, RefreshRateTableIndex);
3034      break;
3035#endif
3036   default:
3037#ifdef SIS315H
3038      if(SiS_Pr->ChipType == XGI_20) {
3039         unsigned char sr2b = 0, sr2c = 0;
3040         switch(ModeNo) {
3041	 case 0x00:
3042	 case 0x01: sr2b = 0x4e; sr2c = 0xe9; break;
3043	 case 0x04:
3044	 case 0x05:
3045	 case 0x0d: sr2b = 0x1b; sr2c = 0xe3; break;
3046	 }
3047	 if(sr2b) {
3048            SiS_SetReg(SiS_Pr->SiS_P3c4,0x2b,sr2b);
3049	    SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,sr2c);
3050	    SiS_SetRegByte(SiS_Pr->SiS_P3c2,(SiS_GetRegByte(SiS_Pr->SiS_P3cc) | 0x0c));
3051	 }
3052      }
3053      SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex);
3054#endif
3055      break;
3056   }
3057
3058   SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
3059
3060#ifdef SIS315H
3061   if(SiS_Pr->ChipType == XGI_40) {
3062      SiS_SetupDualChip(SiS_Pr);
3063   }
3064#endif
3065
3066   SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex);
3067
3068#ifdef SIS_LINUX_KERNEL
3069   if(SiS_Pr->SiS_flag_clearbuffer) {
3070      SiS_ClearBuffer(SiS_Pr, ModeNo);
3071   }
3072#endif
3073
3074   if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) {
3075      SiS_WaitRetrace1(SiS_Pr);
3076      SiS_DisplayOn(SiS_Pr);
3077   }
3078}
3079
3080/*********************************************/
3081/*       HELPER: VIDEO BRIDGE PROG CLK       */
3082/*********************************************/
3083
3084static void
3085SiS_InitVB(struct SiS_Private *SiS_Pr)
3086{
3087   unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
3088
3089   SiS_Pr->Init_P4_0E = 0;
3090   if(SiS_Pr->SiS_ROMNew) {
3091      SiS_Pr->Init_P4_0E = ROMAddr[0x82];
3092   } else if(SiS_Pr->ChipType >= XGI_40) {
3093      if(SiS_Pr->SiS_XGIROM) {
3094         SiS_Pr->Init_P4_0E = ROMAddr[0x80];
3095      }
3096   }
3097}
3098
3099static void
3100SiS_ResetVB(struct SiS_Private *SiS_Pr)
3101{
3102#ifdef SIS315H
3103   unsigned char  *ROMAddr = SiS_Pr->VirtualRomBase;
3104   unsigned short temp;
3105
3106   /* VB programming clock */
3107   if(SiS_Pr->SiS_UseROM) {
3108      if(SiS_Pr->ChipType < SIS_330) {
3109	 temp = ROMAddr[VB310Data_1_2_Offset] | 0x40;
3110	 if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40;
3111	 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
3112      } else if(SiS_Pr->ChipType >= SIS_661 && SiS_Pr->ChipType < XGI_20) {
3113	 temp = ROMAddr[0x7e] | 0x40;
3114	 if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40;
3115	 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
3116      }
3117   } else if(SiS_Pr->ChipType >= XGI_40) {
3118      temp = 0x40;
3119      if(SiS_Pr->SiS_XGIROM) temp |= ROMAddr[0x7e];
3120      /* Can we do this on any chipset? */
3121      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
3122   }
3123#endif
3124}
3125
3126/*********************************************/
3127/*    HELPER: SET VIDEO/CAPTURE REGISTERS    */
3128/*********************************************/
3129
3130static void
3131SiS_StrangeStuff(struct SiS_Private *SiS_Pr)
3132{
3133   /* SiS65x and XGI set up some sort of "lock mode" for text
3134    * which locks CRT2 in some way to CRT1 timing. Disable
3135    * this here.
3136    */
3137#ifdef SIS315H
3138   if((IS_SIS651) || (IS_SISM650) ||
3139      SiS_Pr->ChipType == SIS_340 ||
3140      SiS_Pr->ChipType == XGI_40) {
3141      SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x3f, 0x00);   /* Fiddle with capture regs */
3142      SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x00, 0x00);
3143      SiS_SetReg(SiS_Pr->SiS_VidPlay, 0x00, 0x86);   /* (BIOS does NOT unlock) */
3144      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x30, 0xfe); /* Fiddle with video regs */
3145      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x3f, 0xef);
3146   }
3147   /* !!! This does not support modes < 0x13 !!! */
3148#endif
3149}
3150
3151/*********************************************/
3152/*     HELPER: SET AGP TIMING FOR SiS760     */
3153/*********************************************/
3154
3155static void
3156SiS_Handle760(struct SiS_Private *SiS_Pr)
3157{
3158#ifdef SIS315H
3159   unsigned int somebase;
3160   unsigned char temp1, temp2, temp3;
3161
3162   if( (SiS_Pr->ChipType != SIS_760)                         ||
3163       ((SiS_GetReg(SiS_Pr->SiS_P3d4, 0x5c) & 0xf8) != 0x80) ||
3164       (!(SiS_Pr->SiS_SysFlags & SF_760LFB))                 ||
3165       (!(SiS_Pr->SiS_SysFlags & SF_760UMA)) )
3166      return;
3167
3168#ifdef SIS_LINUX_KERNEL
3169   somebase = sisfb_read_mio_pci_word(SiS_Pr, 0x74);
3170#else
3171   somebase = sis_pci_read_device_u32(2, 0x74);
3172#endif
3173   somebase &= 0xffff;
3174
3175   if(somebase == 0) return;
3176
3177   temp3 = SiS_GetRegByte((somebase + 0x85)) & 0xb7;
3178
3179   if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
3180      temp1 = 0x21;
3181      temp2 = 0x03;
3182      temp3 |= 0x08;
3183   } else {
3184      temp1 = 0x25;
3185      temp2 = 0x0b;
3186   }
3187
3188#ifdef SIS_LINUX_KERNEL
3189   sisfb_write_nbridge_pci_byte(SiS_Pr, 0x7e, temp1);
3190   sisfb_write_nbridge_pci_byte(SiS_Pr, 0x8d, temp2);
3191#else
3192   sis_pci_write_host_bridge_u8(0x7e, temp1);
3193   sis_pci_write_host_bridge_u8(0x8d, temp2);
3194#endif
3195
3196   SiS_SetRegByte((somebase + 0x85), temp3);
3197#endif
3198}
3199
3200/*********************************************/
3201/*      X.org/XFree86: SET SCREEN PITCH      */
3202/*********************************************/
3203
3204#ifdef SIS_XORG_XF86
3205static void
3206SiS_SetPitchCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
3207{
3208   SISPtr pSiS = SISPTR(pScrn);
3209   unsigned short HDisplay = pSiS->scrnPitch >> 3;
3210
3211   SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,(HDisplay & 0xFF));
3212   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,(HDisplay >> 8));
3213}
3214
3215static void
3216SiS_SetPitchCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
3217{
3218   SISPtr pSiS = SISPTR(pScrn);
3219   unsigned short HDisplay = pSiS->scrnPitch2 >> 3;
3220
3221    /* Unlock CRT2 */
3222   if(pSiS->VGAEngine == SIS_315_VGA)
3223      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01);
3224   else
3225      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01);
3226
3227   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(HDisplay & 0xFF));
3228   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0xF0,(HDisplay >> 8));
3229}
3230
3231static void
3232SiS_SetPitch(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
3233{
3234   SISPtr pSiS = SISPTR(pScrn);
3235   BOOLEAN isslavemode = FALSE;
3236
3237   if( (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
3238       ( ((pSiS->VGAEngine == SIS_300_VGA) &&
3239	  (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
3240	 ((pSiS->VGAEngine == SIS_315_VGA) &&
3241	  (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) {
3242      isslavemode = TRUE;
3243   }
3244
3245   /* We need to set pitch for CRT1 if bridge is in slave mode, too */
3246   if((pSiS->VBFlags & DISPTYPE_DISP1) || (isslavemode)) {
3247      SiS_SetPitchCRT1(SiS_Pr, pScrn);
3248   }
3249   /* We must not set the pitch for CRT2 if bridge is in slave mode */
3250   if((pSiS->VBFlags & DISPTYPE_DISP2) && (!isslavemode)) {
3251      SiS_SetPitchCRT2(SiS_Pr, pScrn);
3252   }
3253}
3254#endif
3255
3256/*********************************************/
3257/*                 SiSSetMode()              */
3258/*********************************************/
3259
3260#ifdef SIS_XORG_XF86
3261/* We need pScrn for setting the pitch correctly */
3262BOOLEAN
3263SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo, BOOLEAN dosetpitch)
3264#else
3265BOOLEAN
3266SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
3267#endif
3268{
3269   SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
3270   unsigned short RealModeNo, ModeIdIndex;
3271   unsigned char  backupreg = 0;
3272#ifdef SIS_LINUX_KERNEL
3273   unsigned short KeepLockReg;
3274
3275   SiS_Pr->UseCustomMode = FALSE;
3276   SiS_Pr->CRT1UsesCustomMode = FALSE;
3277#endif
3278
3279   SiS_Pr->SiS_flag_clearbuffer = 0;
3280
3281   if(SiS_Pr->UseCustomMode) {
3282      ModeNo = 0xfe;
3283   } else {
3284#ifdef SIS_LINUX_KERNEL
3285      if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1;
3286#endif
3287      ModeNo &= 0x7f;
3288   }
3289
3290   /* Don't use FSTN mode for CRT1 */
3291   RealModeNo = ModeNo;
3292   if(ModeNo == 0x5b) ModeNo = 0x56;
3293
3294   SiSInitPtr(SiS_Pr);
3295   SiSRegInit(SiS_Pr, BaseAddr);
3296   SiS_GetSysFlags(SiS_Pr);
3297
3298   SiS_Pr->SiS_VGAINFO = 0x11;
3299#if defined(SIS_XORG_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__))
3300   if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
3301#endif
3302
3303#ifdef SIS_LINUX_KERNEL
3304   KeepLockReg = SiS_GetReg(SiS_Pr->SiS_P3c4,0x05);
3305#endif
3306   SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
3307
3308   SiSInitPCIetc(SiS_Pr);
3309   SiSSetLVDSetc(SiS_Pr);
3310   SiSDetermineROMUsage(SiS_Pr);
3311
3312   SiS_UnLockCRT2(SiS_Pr);
3313
3314   if(!SiS_Pr->UseCustomMode) {
3315      if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
3316   } else {
3317      ModeIdIndex = 0;
3318   }
3319
3320   SiS_GetVBType(SiS_Pr);
3321
3322   /* Init/restore some VB registers */
3323   SiS_InitVB(SiS_Pr);
3324   if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
3325      if(SiS_Pr->ChipType >= SIS_315H) {
3326         SiS_ResetVB(SiS_Pr);
3327	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
3328	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
3329         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
3330      } else {
3331         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
3332      }
3333   }
3334
3335   /* Get VB information (connectors, connected devices) */
3336   SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, (SiS_Pr->UseCustomMode) ? 0 : 1);
3337   SiS_SetYPbPr(SiS_Pr);
3338   SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex);
3339   SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex);
3340   SiS_SetLowModeTest(SiS_Pr, ModeNo);
3341
3342#ifdef SIS_LINUX_KERNEL
3343   /* Check memory size (kernel framebuffer driver only) */
3344   if(!SiS_CheckMemorySize(SiS_Pr, ModeNo, ModeIdIndex)) {
3345      return FALSE;
3346   }
3347#endif
3348
3349   SiS_OpenCRTC(SiS_Pr);
3350
3351   if(SiS_Pr->UseCustomMode) {
3352      SiS_Pr->CRT1UsesCustomMode = TRUE;
3353      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
3354      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
3355   } else {
3356      SiS_Pr->CRT1UsesCustomMode = FALSE;
3357   }
3358
3359   /* Set mode on CRT1 */
3360   if( (SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) ||
3361       (!(SiS_Pr->SiS_VBInfo & SwitchCRT2)) ) {
3362      SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex);
3363   }
3364
3365   /* Set mode on CRT2 */
3366   if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA)) {
3367      if( (SiS_Pr->SiS_VBType & VB_SISVB)    ||
3368	  (SiS_Pr->SiS_IF_DEF_LVDS     == 1) ||
3369	  (SiS_Pr->SiS_IF_DEF_CH70xx   != 0) ||
3370	  (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) {
3371	 SiS_SetCRT2Group(SiS_Pr, RealModeNo);
3372      }
3373   }
3374
3375   SiS_HandleCRT1(SiS_Pr);
3376
3377   SiS_StrangeStuff(SiS_Pr);
3378
3379   SiS_DisplayOn(SiS_Pr);
3380   SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
3381
3382#ifdef SIS315H
3383   if(SiS_Pr->ChipType >= SIS_315H) {
3384      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
3385	 if(!(SiS_IsDualEdge(SiS_Pr))) {
3386	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
3387	 }
3388      }
3389   }
3390#endif
3391
3392   if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
3393      if(SiS_Pr->ChipType >= SIS_315H) {
3394#ifdef SIS315H
3395	 if(!SiS_Pr->SiS_ROMNew) {
3396	    if(SiS_IsVAMode(SiS_Pr)) {
3397	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
3398	    } else {
3399	       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
3400	    }
3401	 }
3402
3403	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
3404
3405	 if((IS_SIS650) && (SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0xfc)) {
3406	    if((ModeNo == 0x03) || (ModeNo == 0x10)) {
3407	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x80);
3408	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x56,0x08);
3409	    }
3410	 }
3411
3412	 if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) {
3413	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
3414	 }
3415#endif
3416      } else if((SiS_Pr->ChipType == SIS_630) ||
3417	        (SiS_Pr->ChipType == SIS_730)) {
3418	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
3419      }
3420   }
3421
3422#ifdef SIS_XORG_XF86
3423   if(pScrn) {
3424      /* SetPitch: Adapt to virtual size & position */
3425      if((ModeNo > 0x13) && (dosetpitch)) {
3426	 SiS_SetPitch(SiS_Pr, pScrn);
3427      }
3428
3429      /* Backup/Set ModeNo in BIOS scratch area */
3430      SiS_GetSetModeID(pScrn, ModeNo);
3431   }
3432#endif
3433
3434   SiS_CloseCRTC(SiS_Pr);
3435
3436   SiS_Handle760(SiS_Pr);
3437
3438#ifdef SIS_LINUX_KERNEL
3439   /* We never lock registers in XF86 */
3440   if(KeepLockReg != 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00);
3441#endif
3442
3443   return TRUE;
3444}
3445
3446/*********************************************/
3447/*       X.org/XFree86: SiSBIOSSetMode()     */
3448/*           for non-Dual-Head mode          */
3449/*********************************************/
3450
3451#ifdef SIS_XORG_XF86
3452BOOLEAN
3453SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
3454               DisplayModePtr mode, BOOLEAN IsCustom)
3455{
3456   SISPtr pSiS = SISPTR(pScrn);
3457   unsigned short ModeNo = 0;
3458
3459   SiS_Pr->UseCustomMode = FALSE;
3460
3461   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
3462
3463      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n",
3464		SiS_Pr->CHDisplay,
3465		(mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 :
3466		   (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 :
3467		      SiS_Pr->CVDisplay)));
3468
3469   } else {
3470
3471      /* Don't need vbflags here; checks done earlier */
3472      ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags);
3473      if(!ModeNo) return FALSE;
3474
3475      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo);
3476
3477   }
3478
3479   return(SiSSetMode(SiS_Pr, pScrn, ModeNo, TRUE));
3480}
3481
3482/*********************************************/
3483/*    X.org/XFree86: SiSBIOSSetModeCRT2()    */
3484/*           for Dual-Head modes             */
3485/*********************************************/
3486
3487BOOLEAN
3488SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
3489               DisplayModePtr mode, BOOLEAN IsCustom)
3490{
3491   SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
3492   SISPtr  pSiS = SISPTR(pScrn);
3493#ifdef SISDUALHEAD
3494   SISEntPtr pSiSEnt = pSiS->entityPrivate;
3495#endif
3496   unsigned short ModeIdIndex;
3497   unsigned short ModeNo = 0;
3498   unsigned char  backupreg = 0;
3499
3500   SiS_Pr->UseCustomMode = FALSE;
3501
3502   /* Remember: Custom modes for CRT2 are ONLY supported
3503    *     -) on the 30x/B/C, and
3504    *     -) if CRT2 is LCD or VGA, or CRT1 is LCDA
3505    */
3506
3507   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
3508
3509	 ModeNo = 0xfe;
3510
3511   } else {
3512
3513	 ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags);
3514	 if(!ModeNo) return FALSE;
3515
3516   }
3517
3518   SiSRegInit(SiS_Pr, BaseAddr);
3519   SiSInitPtr(SiS_Pr);
3520   SiS_GetSysFlags(SiS_Pr);
3521#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__)
3522   SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
3523#else
3524   SiS_Pr->SiS_VGAINFO = 0x11;
3525#endif
3526
3527   SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
3528
3529   SiSInitPCIetc(SiS_Pr);
3530   SiSSetLVDSetc(SiS_Pr);
3531   SiSDetermineROMUsage(SiS_Pr);
3532
3533   /* Save mode info so we can set it from within SetMode for CRT1 */
3534#ifdef SISDUALHEAD
3535   if(pSiS->DualHeadMode) {
3536      pSiSEnt->CRT2ModeNo = ModeNo;
3537      pSiSEnt->CRT2DMode = mode;
3538      pSiSEnt->CRT2IsCustom = IsCustom;
3539      pSiSEnt->CRT2CR30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
3540      pSiSEnt->CRT2CR31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
3541      pSiSEnt->CRT2CR35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
3542      pSiSEnt->CRT2CR38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
3543#if 0
3544      /* We can't set CRT2 mode before CRT1 mode is set - says who...? */
3545      if(pSiSEnt->CRT1ModeNo == -1) {
3546	 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
3547		"Setting CRT2 mode delayed until after setting CRT1 mode\n");
3548	 return TRUE;
3549      }
3550#endif
3551      pSiSEnt->CRT2ModeSet = TRUE;
3552   }
3553#endif
3554
3555   if(SiS_Pr->UseCustomMode) {
3556
3557      unsigned short temptemp = SiS_Pr->CVDisplay;
3558
3559      if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
3560      else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
3561
3562      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
3563	  "Setting custom mode %dx%d on CRT2\n",
3564	  SiS_Pr->CHDisplay, temptemp);
3565
3566   } else {
3567
3568      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
3569	  "Setting standard mode 0x%x on CRT2\n", ModeNo);
3570
3571   }
3572
3573   SiS_UnLockCRT2(SiS_Pr);
3574
3575   if(!SiS_Pr->UseCustomMode) {
3576      if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
3577   } else {
3578      ModeIdIndex = 0;
3579   }
3580
3581   SiS_GetVBType(SiS_Pr);
3582
3583   SiS_InitVB(SiS_Pr);
3584   if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
3585      if(SiS_Pr->ChipType >= SIS_315H) {
3586	 SiS_ResetVB(SiS_Pr);
3587	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
3588	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
3589	 backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
3590      } else {
3591	 backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
3592      }
3593   }
3594
3595   /* Get VB information (connectors, connected devices) */
3596   if(!SiS_Pr->UseCustomMode) {
3597      SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 1);
3598   } else {
3599      /* If this is a custom mode, we don't check the modeflag for CRT2Mode */
3600      SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0);
3601   }
3602   SiS_SetYPbPr(SiS_Pr);
3603   SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex);
3604   SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex);
3605   SiS_SetLowModeTest(SiS_Pr, ModeNo);
3606
3607   SiS_ResetSegmentRegisters(SiS_Pr);
3608
3609   /* Set mode on CRT2 */
3610   if( (SiS_Pr->SiS_VBType & VB_SISVB)    ||
3611       (SiS_Pr->SiS_IF_DEF_LVDS     == 1) ||
3612       (SiS_Pr->SiS_IF_DEF_CH70xx   != 0) ||
3613       (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) {
3614      SiS_SetCRT2Group(SiS_Pr, ModeNo);
3615   }
3616
3617   SiS_StrangeStuff(SiS_Pr);
3618
3619   SiS_DisplayOn(SiS_Pr);
3620   SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
3621
3622   if(SiS_Pr->ChipType >= SIS_315H) {
3623      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
3624	 if(!(SiS_IsDualEdge(SiS_Pr))) {
3625	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
3626	 }
3627      }
3628   }
3629
3630   if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
3631      if(SiS_Pr->ChipType >= SIS_315H) {
3632	 if(!SiS_Pr->SiS_ROMNew) {
3633	    if(SiS_IsVAMode(SiS_Pr)) {
3634	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
3635	    } else {
3636	       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
3637	    }
3638	 }
3639
3640	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
3641
3642	 if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) {
3643	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
3644	 }
3645      } else if((SiS_Pr->ChipType == SIS_630) ||
3646	        (SiS_Pr->ChipType == SIS_730)) {
3647         SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
3648      }
3649   }
3650
3651   /* SetPitch: Adapt to virtual size & position */
3652   SiS_SetPitchCRT2(SiS_Pr, pScrn);
3653
3654   SiS_Handle760(SiS_Pr);
3655
3656   return TRUE;
3657}
3658
3659/*********************************************/
3660/*    X.org/XFree86: SiSBIOSSetModeCRT1()    */
3661/*           for Dual-Head modes             */
3662/*********************************************/
3663
3664BOOLEAN
3665SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
3666                   DisplayModePtr mode, BOOLEAN IsCustom)
3667{
3668   SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
3669   SISPtr  pSiS = SISPTR(pScrn);
3670   unsigned short ModeIdIndex, ModeNo = 0;
3671   unsigned char  backupreg = 0;
3672#ifdef SISDUALHEAD
3673   SISEntPtr pSiSEnt = pSiS->entityPrivate;
3674   unsigned char  backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0;
3675   BOOLEAN backupcustom;
3676#endif
3677
3678   SiS_Pr->UseCustomMode = FALSE;
3679
3680   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
3681
3682	 unsigned short temptemp = SiS_Pr->CVDisplay;
3683
3684	 if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
3685	 else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
3686
3687	 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
3688	 	"Setting custom mode %dx%d on CRT1\n",
3689	 	SiS_Pr->CHDisplay, temptemp);
3690	 ModeNo = 0xfe;
3691
3692   } else {
3693
3694	 ModeNo = SiS_GetModeNumber(pScrn, mode, 0); /* don't give VBFlags */
3695	 if(!ModeNo) return FALSE;
3696
3697	 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
3698	 	"Setting standard mode 0x%x on CRT1\n", ModeNo);
3699   }
3700
3701   SiSInitPtr(SiS_Pr);
3702   SiSRegInit(SiS_Pr, BaseAddr);
3703   SiS_GetSysFlags(SiS_Pr);
3704#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__)
3705   SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
3706#else
3707   SiS_Pr->SiS_VGAINFO = 0x11;
3708#endif
3709
3710   SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
3711
3712   SiSInitPCIetc(SiS_Pr);
3713   SiSSetLVDSetc(SiS_Pr);
3714   SiSDetermineROMUsage(SiS_Pr);
3715
3716   SiS_UnLockCRT2(SiS_Pr);
3717
3718   if(!SiS_Pr->UseCustomMode) {
3719      if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
3720   } else {
3721      ModeIdIndex = 0;
3722   }
3723
3724   /* Determine VBType */
3725   SiS_GetVBType(SiS_Pr);
3726
3727   SiS_InitVB(SiS_Pr);
3728   if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
3729      if(SiS_Pr->ChipType >= SIS_315H) {
3730         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
3731      } else {
3732         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
3733      }
3734   }
3735
3736   /* Get VB information (connectors, connected devices) */
3737   /* (We don't care if the current mode is a CRT2 mode) */
3738   SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0);
3739   SiS_SetYPbPr(SiS_Pr);
3740   SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex);
3741   SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex);
3742   SiS_SetLowModeTest(SiS_Pr, ModeNo);
3743
3744   SiS_OpenCRTC(SiS_Pr);
3745
3746   /* Set mode on CRT1 */
3747   SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex);
3748   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
3749      SiS_SetCRT2Group(SiS_Pr, ModeNo);
3750   }
3751
3752   /* SetPitch: Adapt to virtual size & position */
3753   SiS_SetPitchCRT1(SiS_Pr, pScrn);
3754
3755   SiS_HandleCRT1(SiS_Pr);
3756
3757   SiS_StrangeStuff(SiS_Pr);
3758
3759   SiS_CloseCRTC(SiS_Pr);
3760
3761#ifdef SISDUALHEAD
3762   if(pSiS->DualHeadMode) {
3763      pSiSEnt->CRT1ModeNo = ModeNo;
3764      pSiSEnt->CRT1DMode = mode;
3765   }
3766#endif
3767
3768   if(SiS_Pr->UseCustomMode) {
3769      SiS_Pr->CRT1UsesCustomMode = TRUE;
3770      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
3771      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
3772   } else {
3773      SiS_Pr->CRT1UsesCustomMode = FALSE;
3774   }
3775
3776   /* Reset CRT2 if changing mode on CRT1 */
3777#ifdef SISDUALHEAD
3778   if(pSiS->DualHeadMode) {
3779      if(pSiSEnt->CRT2ModeNo != -1) {
3780	 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
3781				"(Re-)Setting mode for CRT2\n");
3782	 backupcustom = SiS_Pr->UseCustomMode;
3783	 backupcr30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
3784	 backupcr31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
3785	 backupcr35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
3786	 backupcr38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
3787	 if(SiS_Pr->SiS_VBType & VB_SISVB) {
3788	    /* Backup LUT-enable */
3789	    if(pSiSEnt->CRT2ModeSet) {
3790	       backupp40d = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0d) & 0x08;
3791	    }
3792	 }
3793	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
3794	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,pSiSEnt->CRT2CR30);
3795	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,pSiSEnt->CRT2CR31);
3796	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,pSiSEnt->CRT2CR35);
3797	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,pSiSEnt->CRT2CR38);
3798	 }
3799
3800	 SiSBIOSSetModeCRT2(SiS_Pr, pSiSEnt->pScrn_1,
3801			    pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom);
3802
3803	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,backupcr30);
3804	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,backupcr31);
3805	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupcr35);
3806	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupcr38);
3807	 if(SiS_Pr->SiS_VBType & VB_SISVB) {
3808	    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d, ~0x08, backupp40d);
3809	 }
3810	 SiS_Pr->UseCustomMode = backupcustom;
3811      }
3812   }
3813#endif
3814
3815   /* Warning: From here, the custom mode entries in SiS_Pr are
3816    * possibly overwritten
3817    */
3818
3819   SiS_DisplayOn(SiS_Pr);
3820   SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
3821
3822   if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
3823      if(SiS_Pr->ChipType >= SIS_315H) {
3824	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
3825      } else if((SiS_Pr->ChipType == SIS_630) ||
3826                (SiS_Pr->ChipType == SIS_730)) {
3827         SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
3828      }
3829   }
3830
3831   SiS_Handle760(SiS_Pr);
3832
3833   /* Backup/Set ModeNo in BIOS scratch area */
3834   SiS_GetSetModeID(pScrn,ModeNo);
3835
3836   return TRUE;
3837}
3838#endif /* Linux_XF86 */
3839
3840#ifndef GETBITSTR
3841#define BITMASK(h,l)    	(((unsigned)(1U << ((h)-(l)+1))-1)<<(l))
3842#define GENMASK(mask)   	BITMASK(1?mask,0?mask)
3843#define GETBITS(var,mask)   	(((var) & GENMASK(mask)) >> (0?mask))
3844#define GETBITSTR(val,from,to)  ((GETBITS(val,from)) << (0?to))
3845#endif
3846
3847void
3848SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth)
3849{
3850   int x = 1; /* Fix sync */
3851
3852   SiS_Pr->CCRT1CRTC[0]  =  ((SiS_Pr->CHTotal >> 3) - 5) & 0xff;		/* CR0 */
3853   SiS_Pr->CCRT1CRTC[1]  =  (SiS_Pr->CHDisplay >> 3) - 1;			/* CR1 */
3854   SiS_Pr->CCRT1CRTC[2]  =  (SiS_Pr->CHBlankStart >> 3) - 1;			/* CR2 */
3855   SiS_Pr->CCRT1CRTC[3]  =  (((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80;	/* CR3 */
3856   SiS_Pr->CCRT1CRTC[4]  =  (SiS_Pr->CHSyncStart >> 3) + 3;			/* CR4 */
3857   SiS_Pr->CCRT1CRTC[5]  =  ((((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) |	/* CR5 */
3858			    (((SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F);
3859
3860   SiS_Pr->CCRT1CRTC[6]  =  (SiS_Pr->CVTotal       - 2) & 0xFF;			/* CR6 */
3861   SiS_Pr->CCRT1CRTC[7]  =  (((SiS_Pr->CVTotal     - 2) & 0x100) >> 8)		/* CR7 */
3862			  | (((SiS_Pr->CVDisplay   - 1) & 0x100) >> 7)
3863			  | (((SiS_Pr->CVSyncStart - x) & 0x100) >> 6)
3864			  | (((SiS_Pr->CVBlankStart- 1) & 0x100) >> 5)
3865			  | 0x10
3866			  | (((SiS_Pr->CVTotal     - 2) & 0x200) >> 4)
3867			  | (((SiS_Pr->CVDisplay   - 1) & 0x200) >> 3)
3868			  | (((SiS_Pr->CVSyncStart - x) & 0x200) >> 2);
3869
3870   SiS_Pr->CCRT1CRTC[16] = ((((SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5); 	/* CR9 */
3871
3872   if(depth != 8) {
3873      if(SiS_Pr->CHDisplay >= 1600)      SiS_Pr->CCRT1CRTC[16] |= 0x60;		/* SRE */
3874      else if(SiS_Pr->CHDisplay >= 640)  SiS_Pr->CCRT1CRTC[16] |= 0x40;
3875   }
3876
3877   SiS_Pr->CCRT1CRTC[8] =  (SiS_Pr->CVSyncStart  - x) & 0xFF;			/* CR10 */
3878   SiS_Pr->CCRT1CRTC[9] =  ((SiS_Pr->CVSyncEnd   - x) & 0x0F) | 0x80;		/* CR11 */
3879   SiS_Pr->CCRT1CRTC[10] = (SiS_Pr->CVDisplay    - 1) & 0xFF;			/* CR12 */
3880   SiS_Pr->CCRT1CRTC[11] = (SiS_Pr->CVBlankStart - 1) & 0xFF;			/* CR15 */
3881   SiS_Pr->CCRT1CRTC[12] = (SiS_Pr->CVBlankEnd   - 1) & 0xFF;			/* CR16 */
3882
3883   SiS_Pr->CCRT1CRTC[13] =							/* SRA */
3884			GETBITSTR((SiS_Pr->CVTotal     -2), 10:10, 0:0) |
3885			GETBITSTR((SiS_Pr->CVDisplay   -1), 10:10, 1:1) |
3886			GETBITSTR((SiS_Pr->CVBlankStart-1), 10:10, 2:2) |
3887			GETBITSTR((SiS_Pr->CVSyncStart -x), 10:10, 3:3) |
3888			GETBITSTR((SiS_Pr->CVBlankEnd  -1),   8:8, 4:4) |
3889			GETBITSTR((SiS_Pr->CVSyncEnd     ),   4:4, 5:5) ;
3890
3891   SiS_Pr->CCRT1CRTC[14] =							/* SRB */
3892			GETBITSTR((SiS_Pr->CHTotal      >> 3) - 5, 9:8, 1:0) |
3893			GETBITSTR((SiS_Pr->CHDisplay    >> 3) - 1, 9:8, 3:2) |
3894			GETBITSTR((SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) |
3895			GETBITSTR((SiS_Pr->CHSyncStart  >> 3) + 3, 9:8, 7:6) ;
3896
3897
3898   SiS_Pr->CCRT1CRTC[15] =							/* SRC */
3899			GETBITSTR((SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) |
3900			GETBITSTR((SiS_Pr->CHSyncEnd  >> 3) + 3, 5:5, 2:2) ;
3901}
3902
3903void
3904SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
3905		unsigned short ModeIdIndex)
3906{
3907   unsigned short modeflag, tempax, tempbx = 0, remaining = 0;
3908   unsigned short VGAHDE = SiS_Pr->SiS_VGAHDE;
3909   int i, j;
3910
3911   /* 1:1 data: use data set by setcrt1crtc() */
3912   if(SiS_Pr->SiS_LCDInfo & LCDPass11) return;
3913
3914   modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex);
3915
3916   if(modeflag & HalfDCLK) VGAHDE >>= 1;
3917
3918   SiS_Pr->CHDisplay = VGAHDE;
3919   SiS_Pr->CHBlankStart = VGAHDE;
3920
3921   SiS_Pr->CVDisplay = SiS_Pr->SiS_VGAVDE;
3922   SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE;
3923
3924   if(SiS_Pr->ChipType < SIS_315H) {
3925#ifdef SIS300
3926      tempbx = SiS_Pr->SiS_VGAHT;
3927      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
3928         tempbx = SiS_Pr->PanelHT;
3929      }
3930      if(modeflag & HalfDCLK) tempbx >>= 1;
3931      remaining = tempbx % 8;
3932#endif
3933   } else {
3934#ifdef SIS315H
3935      /* OK for LCDA, LVDS */
3936      tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes;
3937      tempax = SiS_Pr->SiS_VGAHDE;  /* not /2 ! */
3938      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
3939         tempax = SiS_Pr->PanelXRes;
3940      }
3941      tempbx += tempax;
3942      if(modeflag & HalfDCLK) tempbx -= VGAHDE;
3943#endif
3944   }
3945   SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx;
3946
3947   if(SiS_Pr->ChipType < SIS_315H) {
3948#ifdef SIS300
3949      if(SiS_Pr->SiS_VGAHDE == SiS_Pr->PanelXRes) {
3950	 SiS_Pr->CHSyncStart = SiS_Pr->SiS_VGAHDE + ((SiS_Pr->PanelHRS + 1) & ~1);
3951	 SiS_Pr->CHSyncEnd = SiS_Pr->CHSyncStart + SiS_Pr->PanelHRE;
3952	 if(modeflag & HalfDCLK) {
3953	    SiS_Pr->CHSyncStart >>= 1;
3954	    SiS_Pr->CHSyncEnd >>= 1;
3955	 }
3956      } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
3957	 tempax = (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) >> 1;
3958	 tempbx = (SiS_Pr->PanelHRS + 1) & ~1;
3959	 if(modeflag & HalfDCLK) {
3960	    tempax >>= 1;
3961	    tempbx >>= 1;
3962	 }
3963	 SiS_Pr->CHSyncStart = (VGAHDE + tempax + tempbx + 7) & ~7;
3964	 tempax = SiS_Pr->PanelHRE + 7;
3965	 if(modeflag & HalfDCLK) tempax >>= 1;
3966	 SiS_Pr->CHSyncEnd = (SiS_Pr->CHSyncStart + tempax) & ~7;
3967      } else {
3968	 SiS_Pr->CHSyncStart = SiS_Pr->SiS_VGAHDE;
3969	 if(modeflag & HalfDCLK) {
3970	    SiS_Pr->CHSyncStart >>= 1;
3971	    tempax = ((SiS_Pr->CHTotal - SiS_Pr->CHSyncStart) / 3) << 1;
3972	    SiS_Pr->CHSyncEnd = SiS_Pr->CHSyncStart + tempax;
3973	 } else {
3974	    SiS_Pr->CHSyncEnd = (SiS_Pr->CHSyncStart + (SiS_Pr->CHTotal / 10) + 7) & ~7;
3975	    SiS_Pr->CHSyncStart += 8;
3976	 }
3977      }
3978#endif
3979   } else {
3980#ifdef SIS315H
3981      tempax = VGAHDE;
3982      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
3983	 tempbx = SiS_Pr->PanelXRes;
3984	 if(modeflag & HalfDCLK) tempbx >>= 1;
3985	 tempax += ((tempbx - tempax) >> 1);
3986      }
3987      tempax += SiS_Pr->PanelHRS;
3988      SiS_Pr->CHSyncStart = tempax;
3989      tempax += SiS_Pr->PanelHRE;
3990      SiS_Pr->CHSyncEnd = tempax;
3991#endif
3992   }
3993
3994   tempbx = SiS_Pr->PanelVT - SiS_Pr->PanelYRes;
3995   tempax = SiS_Pr->SiS_VGAVDE;
3996   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
3997      tempax = SiS_Pr->PanelYRes;
3998   } else if(SiS_Pr->ChipType < SIS_315H) {
3999#ifdef SIS300
4000      /* Stupid hack for 640x400/320x200 */
4001      if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
4002	 if((tempax + tempbx) == 438) tempbx += 16;
4003      } else if((SiS_Pr->SiS_LCDResInfo == Panel_800x600) ||
4004		(SiS_Pr->SiS_LCDResInfo == Panel_1024x600)) {
4005	 tempax = 0;
4006	 tempbx = SiS_Pr->SiS_VGAVT;
4007      }
4008#endif
4009   }
4010   SiS_Pr->CVTotal = SiS_Pr->CVBlankEnd = tempbx + tempax;
4011
4012   tempax = SiS_Pr->SiS_VGAVDE;
4013   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
4014      tempax += (SiS_Pr->PanelYRes - tempax) >> 1;
4015   }
4016   tempax += SiS_Pr->PanelVRS;
4017   SiS_Pr->CVSyncStart = tempax;
4018   tempax += SiS_Pr->PanelVRE;
4019   SiS_Pr->CVSyncEnd = tempax;
4020   if(SiS_Pr->ChipType < SIS_315H) {
4021      SiS_Pr->CVSyncStart--;
4022      SiS_Pr->CVSyncEnd--;
4023   }
4024
4025   SiS_CalcCRRegisters(SiS_Pr, 8);
4026   SiS_Pr->CCRT1CRTC[15] &= ~0xF8;
4027   SiS_Pr->CCRT1CRTC[15] |= (remaining << 4);
4028   SiS_Pr->CCRT1CRTC[16] &= ~0xE0;
4029
4030   SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
4031
4032   for(i = 0, j = 0; i <= 7; i++, j++) {
4033      SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
4034   }
4035   for(j = 0x10; i <= 10; i++, j++) {
4036      SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
4037   }
4038   for(j = 0x15; i <= 12; i++, j++) {
4039      SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
4040   }
4041   for(j = 0x0A; i <= 15; i++, j++) {
4042      SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]);
4043   }
4044
4045   tempax = SiS_Pr->CCRT1CRTC[16] & 0xE0;
4046   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1F,tempax);
4047
4048   tempax = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5;
4049   if(modeflag & DoubleScanMode) tempax |= 0x80;
4050   SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax);
4051
4052#ifdef SIS_XORG_XF86
4053#ifdef TWDEBUG
4054   xf86DrvMsg(0, X_INFO, "%d %d %d %d  %d %d %d %d  (%d %d %d %d)\n",
4055	SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal,
4056	SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal,
4057	SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd);
4058   xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
4059	SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1],
4060	SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3],
4061	SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5],
4062	SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]);
4063   xf86DrvMsg(0, X_INFO, "   0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
4064	SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9],
4065	SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11],
4066	SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13],
4067	SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]);
4068   xf86DrvMsg(0, X_INFO, "   0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]);
4069#endif
4070#endif
4071}
4072
4073void
4074SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
4075			int xres, int yres,
4076#ifdef SIS_XORG_XF86
4077			DisplayModePtr current
4078#endif
4079#ifdef SIS_LINUX_KERNEL
4080			struct fb_var_screeninfo *var, BOOLEAN writeres
4081#endif
4082)
4083{
4084   unsigned short HRE, HBE, HRS, HBS, HDE, HT;
4085   unsigned short VRE, VBE, VRS, VBS, VDE, VT;
4086   unsigned char  sr_data, cr_data, cr_data2;
4087   int            A, B, C, D, E, F, temp;
4088
4089   sr_data = crdata[14];
4090
4091   /* Horizontal total */
4092   HT =  crdata[0] | ((unsigned short)(sr_data & 0x03) << 8);
4093   A = HT + 5;
4094
4095   /* Horizontal display enable end */
4096   HDE = crdata[1] | ((unsigned short)(sr_data & 0x0C) << 6);
4097   E = HDE + 1;
4098
4099   /* Horizontal retrace (=sync) start */
4100   HRS = crdata[4] | ((unsigned short)(sr_data & 0xC0) << 2);
4101   F = HRS - E - 3;
4102
4103   /* Horizontal blank start */
4104   HBS = crdata[2] | ((unsigned short)(sr_data & 0x30) << 4);
4105
4106   sr_data = crdata[15];
4107   cr_data = crdata[5];
4108
4109   /* Horizontal blank end */
4110   HBE = (crdata[3] & 0x1f) |
4111         ((unsigned short)(cr_data & 0x80) >> 2) |
4112         ((unsigned short)(sr_data & 0x03) << 6);
4113
4114   /* Horizontal retrace (=sync) end */
4115   HRE = (cr_data & 0x1f) | ((sr_data & 0x04) << 3);
4116
4117   temp = HBE - ((E - 1) & 255);
4118   B = (temp > 0) ? temp : (temp + 256);
4119
4120   temp = HRE - ((E + F + 3) & 63);
4121   C = (temp > 0) ? temp : (temp + 64);
4122
4123   D = B - F - C;
4124
4125#ifdef SIS_XORG_XF86
4126   current->HDisplay   = (E * 8);
4127   current->HSyncStart = (E * 8) + (F * 8);
4128   current->HSyncEnd   = (E * 8) + (F * 8) + (C * 8);
4129   current->HTotal     = (E * 8) + (F * 8) + (C * 8) + (D * 8);
4130#ifdef TWDEBUG
4131   xf86DrvMsg(0, X_INFO,
4132		"H: A %d B %d C %d D %d E %d F %d  HT %d HDE %d HRS %d HBS %d HBE %d HRE %d\n",
4133		A, B, C, D, E, F, HT, HDE, HRS, HBS, HBE, HRE);
4134#else
4135   (void)VBS;  (void)HBS;  (void)A;
4136#endif
4137#endif
4138#ifdef SIS_LINUX_KERNEL
4139   if(writeres) var->xres = xres = E * 8;
4140   var->left_margin = D * 8;
4141   var->right_margin = F * 8;
4142   var->hsync_len = C * 8;
4143#endif
4144
4145   /* Vertical */
4146   sr_data = crdata[13];
4147   cr_data = crdata[7];
4148
4149   /* Vertical total */
4150   VT  = crdata[6] |
4151	 ((unsigned short)(cr_data & 0x01) << 8) |
4152	 ((unsigned short)(cr_data & 0x20) << 4) |
4153	 ((unsigned short)(sr_data & 0x01) << 10);
4154   A = VT + 2;
4155
4156   /* Vertical display enable end */
4157   VDE = crdata[10] |
4158	 ((unsigned short)(cr_data & 0x02) << 7) |
4159	 ((unsigned short)(cr_data & 0x40) << 3) |
4160	 ((unsigned short)(sr_data & 0x02) << 9);
4161   E = VDE + 1;
4162
4163   /* Vertical retrace (=sync) start */
4164   VRS = crdata[8] |
4165	 ((unsigned short)(cr_data & 0x04) << 6) |
4166	 ((unsigned short)(cr_data & 0x80) << 2) |
4167	 ((unsigned short)(sr_data & 0x08) << 7);
4168   F = VRS + 1 - E;
4169
4170   cr_data2 = (crdata[16] & 0x01) << 5;
4171
4172   /* Vertical blank start */
4173   VBS = crdata[11] |
4174	 ((unsigned short)(cr_data  & 0x08) << 5) |
4175	 ((unsigned short)(cr_data2 & 0x20) << 4) |
4176	 ((unsigned short)(sr_data  & 0x04) << 8);
4177
4178   /* Vertical blank end */
4179   VBE = crdata[12] | ((unsigned short)(sr_data & 0x10) << 4);
4180   temp = VBE - ((E - 1) & 511);
4181   B = (temp > 0) ? temp : (temp + 512);
4182
4183   /* Vertical retrace (=sync) end */
4184   VRE = (crdata[9] & 0x0f) | ((sr_data & 0x20) >> 1);
4185   temp = VRE - ((E + F - 1) & 31);
4186   C = (temp > 0) ? temp : (temp + 32);
4187
4188   D = B - F - C;
4189
4190#ifdef SIS_XORG_XF86
4191   current->VDisplay   = VDE + 1;
4192   current->VSyncStart = VRS + 1;
4193   current->VSyncEnd   = ((VRS & ~0x1f) | VRE) + 1;
4194   if(VRE <= (VRS & 0x1f)) current->VSyncEnd += 32;
4195   current->VTotal     = E + D + C + F;
4196#if 0
4197   current->VDisplay   = E;
4198   current->VSyncStart = E + D;
4199   current->VSyncEnd   = E + D + C;
4200   current->VTotal     = E + D + C + F;
4201#endif
4202#ifdef TWDEBUG
4203   xf86DrvMsg(0, X_INFO,
4204	"V: A %d B %d C %d D %d E %d F %d  VT %d VDE %d VRS %d VBS %d VBE %d VRE %d\n",
4205	A, B, C, D, E, F, VT, VDE, VRS, VBS, VBE, VRE);
4206#endif
4207#endif
4208#ifdef SIS_LINUX_KERNEL
4209   if(writeres) var->yres = yres = E;
4210   var->upper_margin = D;
4211   var->lower_margin = F;
4212   var->vsync_len = C;
4213#endif
4214
4215   if((xres == 320) && ((yres == 200) || (yres == 240))) {
4216	/* Terrible hack, but correct CRTC data for
4217	 * these modes only produces a black screen...
4218	 * (HRE is 0, leading into a too large C and
4219	 * a negative D. The CRT controller does not
4220	 * seem to like correcting HRE to 50)
4221	 */
4222#ifdef SIS_XORG_XF86
4223      current->HDisplay   = 320;
4224      current->HSyncStart = 328;
4225      current->HSyncEnd   = 376;
4226      current->HTotal     = 400;
4227#endif
4228#ifdef SIS_LINUX_KERNEL
4229      var->left_margin = (400 - 376);
4230      var->right_margin = (328 - 320);
4231      var->hsync_len = (376 - 328);
4232#endif
4233
4234   }
4235
4236}
4237
4238
4239
4240
4241