1/*
2 * Mode setup and basic video bridge detection
3 *
4 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
5 *
6 * The SISInit() function for old series (except TV and FIFO calculation)
7 * was previously based on code which was Copyright (C) 1998,1999 by Alan
8 * Hourihane, Wigan, England. However, the code has been rewritten entirely
9 * and is - it its current representation - not covered by this old copyright.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1) Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2) Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3) The name of the author may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
34 *
35 */
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40
41#include "sis.h"
42#define SIS_NEED_inSISREG
43#define SIS_NEED_outSISREG
44#define SIS_NEED_inSISIDXREG
45#define SIS_NEED_outSISIDXREG
46#define SIS_NEED_orSISIDXREG
47#define SIS_NEED_andSISIDXREG
48#include "sis_regs.h"
49#include "sis_dac.h"
50
51static Bool  SISInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
52static Bool  SIS300Init(ScrnInfoPtr pScrn, DisplayModePtr mode);
53static int   SIS6326DoSense(ScrnInfoPtr pScrn, int tempbh, int tempbl, int tempch, int tempcl);
54static void  SISSense6326(ScrnInfoPtr pScrn);
55static void  SiS6326TVDelay(ScrnInfoPtr pScrn, int delay);
56extern void  SISSense30x(ScrnInfoPtr pScrn, Bool quiet);
57extern void  SISSenseChrontel(ScrnInfoPtr pScrn, Bool quiet);
58
59/* Our very own vgaHW functions */
60void SiSVGASave(ScrnInfoPtr pScrn, SISRegPtr save, int flags);
61void SiSVGARestore(ScrnInfoPtr pScrn, SISRegPtr restore, int flags);
62void SiSVGASaveFonts(ScrnInfoPtr pScrn);
63void SiSVGARestoreFonts(ScrnInfoPtr pScrn);
64void SISVGALock(SISPtr pSiS);
65void SiSVGAUnlock(SISPtr pSiS);
66void SiSVGAProtect(ScrnInfoPtr pScrn, Bool on);
67#ifdef SIS_PC_PLATFORM
68Bool SiSVGAMapMem(ScrnInfoPtr pScrn);
69void SiSVGAUnmapMem(ScrnInfoPtr pScrn);
70#endif
71Bool SiSVGASaveScreen(ScreenPtr pScreen, int mode);
72static Bool SiSVGAInit(ScrnInfoPtr pScrn, DisplayModePtr mode, int fixsync);
73
74const CARD8 SiS6326TVRegs1[14] = {
75     0x00,0x01,0x02,0x03,0x04,0x11,0x12,0x13,0x21,0x26,0x27,0x3a,0x3c,0x43
76};
77
78const CARD8 SiS6326TVRegs1_NTSC[6][14] = {
79    {0x81,0x3f,0x49,0x1b,0xa9,0x03,0x00,0x09,0x08,0x7d,0x00,0x88,0x30,0x60},
80    {0x81,0x3f,0x49,0x1d,0xa0,0x03,0x00,0x09,0x08,0x7d,0x00,0x88,0x30,0x60},
81    {0x81,0x45,0x24,0x8e,0x26,0x0b,0x00,0x09,0x02,0xfe,0x00,0x09,0x51,0x60},
82    {0x81,0x45,0x24,0x8e,0x26,0x07,0x00,0x29,0x04,0x30,0x10,0x3b,0x61,0x60},
83    {0x81,0x3f,0x24,0x8e,0x26,0x09,0x00,0x09,0x02,0x30,0x10,0x3b,0x51,0x60},  /* 640x400, 640x480 */
84    {0x83,0x5d,0x21,0xbe,0x75,0x03,0x00,0x09,0x08,0x42,0x10,0x4d,0x61,0x79}   /* 640x480u */
85};
86
87const CARD8 SiS6326TVRegs2_NTSC[6][54] = {
88    {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
89     0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
90     0xFC, 0xDF, 0x94, 0x1F, 0x4A, 0x03, 0x71, 0x07, 0x97, 0x10, 0x40,
91     0x48, 0x00, 0x26, 0xB6, 0x10, 0x5C, 0xEC, 0x21, 0x2E, 0xBE, 0x10,
92     0x64, 0xF4, 0x21, 0x13, 0x75, 0x08, 0x31, 0x6A, 0x01, 0xA0},
93    {0x11, 0x17, 0x03, 0x0A, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
94     0x0D, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
95     0xFF, 0xDF, 0x94, 0x1F, 0x4A, 0x03, 0x71, 0x07, 0x97, 0x10, 0x40,
96     0x48, 0x00, 0x26, 0xB6, 0x10, 0x5C, 0xEC, 0x21, 0x2E, 0xBE, 0x10,
97     0x64, 0xF4, 0x21, 0x13, 0x75, 0x08, 0x31, 0x6A, 0x01, 0xA0},
98    {0x11, 0x17, 0x03, 0x0A, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
99     0x0D, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
100     0xFF, 0xDF, 0x94, 0x3F, 0x8C, 0x06, 0xCE, 0x07, 0x27, 0x30, 0x73,
101     0x7B, 0x00, 0x48, 0x68, 0x30, 0xB2, 0xD2, 0x52, 0x50, 0x70, 0x30,
102     0xBA, 0xDA, 0x52, 0xDC, 0x02, 0xD1, 0x53, 0xF7, 0x02, 0xA0},
103    {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
104     0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
105     0xDC, 0xDF, 0x94, 0x3F, 0x8C, 0x06, 0xCE, 0x07, 0x27, 0x30, 0x73,
106     0x7B, 0x00, 0x48, 0x68, 0x30, 0xB2, 0xD2, 0x52, 0x50, 0x70, 0x30,
107     0xBA, 0xDA, 0x52, 0x00, 0x02, 0xF5, 0x53, 0xF7, 0x02, 0xA0},
108    {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
109     0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
110     0xDC, 0xDF, 0x94, 0x3F, 0x8C, 0x06, 0xCE, 0x07, 0x27, 0x30, 0x73,
111     0x7B, 0x00, 0x48, 0x68, 0x30, 0xB2, 0xD2, 0x52, 0x50, 0x70, 0x30,
112     0xBA, 0xDA, 0x52, 0xDC, 0x02, 0xD1, 0x53, 0xF7, 0x02, 0xA0},
113    {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,  /* 640x480u */
114     0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
115     0xDC, 0xDF, 0x94, 0xAF, 0x95, 0x06, 0xDD, 0x07, 0x5F, 0x30, 0x7E,
116     0x86, 0x00, 0x4C, 0xA4, 0x30, 0xE3, 0x3B, 0x62, 0x54, 0xAC, 0x30,
117     0xEB, 0x43, 0x62, 0x48, 0x34, 0x3D, 0x63, 0x29, 0x03, 0xA0}
118};
119
120const CARD8 SiS6326TVRegs1_PAL[6][14] = {
121    {0x81,0x2d,0xc8,0x07,0xb2,0x0b,0x00,0x09,0x02,0xed,0x00,0xf8,0x30,0x40},
122    {0x80,0x2d,0xa4,0x03,0xd9,0x0b,0x00,0x09,0x02,0xed,0x10,0xf8,0x71,0x40},
123    {0x81,0x2d,0xa4,0x03,0xd9,0x0b,0x00,0x09,0x02,0xed,0x10,0xf8,0x71,0x40},  /* 640x480 */
124    {0x81,0x2d,0xa4,0x03,0xd9,0x0b,0x00,0x09,0x02,0x8f,0x10,0x9a,0x71,0x40},  /* 800x600 */
125    {0x83,0x63,0xa1,0x7a,0xa3,0x0a,0x00,0x09,0x02,0xb5,0x11,0xc0,0x81,0x59},  /* 800x600u */
126    {0x81,0x63,0xa4,0x03,0xd9,0x01,0x00,0x09,0x10,0x9f,0x10,0xaa,0x71,0x59}   /* 720x540  */
127};
128
129const CARD8 SiS6326TVRegs2_PAL[6][54] = {
130    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,
131     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
132     0xE5, 0xDF, 0x94, 0xEF, 0x5A, 0x03, 0x7F, 0x07, 0xFF, 0x10, 0x4E,
133     0x56, 0x00, 0x2B, 0x23, 0x20, 0xB4, 0xAC, 0x31, 0x33, 0x2B, 0x20,
134     0xBC, 0xB4, 0x31, 0x83, 0xE1, 0x78, 0x31, 0xD6, 0x01, 0xA0},
135    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,
136     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
137     0xE5, 0xDF, 0x94, 0xDF, 0xB2, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x90,
138     0x98, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40,
139     0x6A, 0x5A, 0x73, 0x03, 0xC1, 0xF8, 0x63, 0xB6, 0x03, 0xA0},
140    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,  /* 640x480 */
141     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
142     0xE5, 0xDF, 0x94, 0xDF, 0xB2, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x90,
143     0x98, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40,
144     0x6A, 0x5A, 0x73, 0x03, 0xC1, 0xF8, 0x63, 0xB6, 0x03, 0xA0},
145    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,  /* 800x600 */
146     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
147     0xE5, 0xDF, 0x94, 0xDF, 0xB2, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x90,
148     0x98, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40,
149     0x6A, 0x5A, 0x73, 0xA0, 0xC1, 0x95, 0x73, 0xB6, 0x03, 0xA0},
150    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,  /* 800x600u */
151     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
152     0xE5, 0xDF, 0x94, 0x7F, 0xBD, 0x08, 0x0E, 0x07, 0x47, 0x40, 0x9D,
153     0xA5, 0x00, 0x54, 0x94, 0x40, 0xA4, 0xE4, 0x73, 0x5C, 0x9C, 0x40,
154     0xAC, 0xEC, 0x73, 0x0B, 0x0E, 0x00, 0x84, 0x03, 0x04, 0xA0},
155    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,  /* 720x540  */
156     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
157     0xE5, 0xDF, 0x94, 0xDF, 0xB0, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x9D,
158     0xA5, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40,
159     0x6A, 0x5A, 0x73, 0xA0, 0xC1, 0x95, 0x73, 0xB6, 0x03, 0xA0}
160};
161
162const CARD8 SiS6326CR[9][15] = {
163     {0x79,0x63,0x64,0x1d,0x6a,0x93,0x00,0x6f,0xf0,0x58,0x8a,0x57,0x57,0x70,0x20},  /* PAL 800x600   */
164     {0x79,0x4f,0x50,0x95,0x60,0x93,0x00,0x6f,0xba,0x14,0x86,0xdf,0xe0,0x30,0x00},  /* PAL 640x480   */
165     {0x5f,0x4f,0x50,0x82,0x53,0x9f,0x00,0x0b,0x3e,0xe9,0x8b,0xdf,0xe7,0x04,0x00},  /* NTSC 640x480  */
166     {0x5f,0x4f,0x50,0x82,0x53,0x9f,0x00,0x0b,0x3e,0xcb,0x8d,0x8f,0x96,0xe9,0x00},  /* NTSC 640x400  */
167     {0x83,0x63,0x64,0x1f,0x6d,0x9b,0x00,0x6f,0xf0,0x48,0x0a,0x23,0x57,0x70,0x20},  /* PAL 800x600u  */
168     {0x79,0x59,0x5b,0x1d,0x66,0x93,0x00,0x6f,0xf0,0x42,0x04,0x1b,0x40,0x70,0x20},  /* PAL 720x540   */
169     {0x66,0x4f,0x51,0x0a,0x57,0x89,0x00,0x0b,0x3e,0xd9,0x0b,0xb6,0xe7,0x04,0x00},  /* NTSC 640x480u */
170     {0xce,0x9f,0x9f,0x92,0xa4,0x16,0x00,0x28,0x5a,0x00,0x04,0xff,0xff,0x29,0x39},  /* 1280x1024-75  */
171     {0x09,0xc7,0xc7,0x0d,0xd2,0x0a,0x01,0xe0,0x10,0xb0,0x04,0xaf,0xaf,0xe1,0x1f}   /* 1600x1200-60  */
172};
173
174/* Initialize a display mode on 5597/5598, 6326 and 530/620 */
175static Bool
176SISInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
177{
178    SISPtr       pSiS = SISPTR(pScrn);
179    SISRegPtr    pReg = &pSiS->ModeReg;
180    UChar        temp;
181    int          mclk = pSiS->MemClock;
182    int          clock = mode->Clock;
183    int          width = mode->HDisplay;
184    int          height = mode->VDisplay;
185    int          rate = (int)SiSCalcVRate(mode);
186    int          buswidth = pSiS->BusWidth;
187    unsigned int vclk[5];
188    UShort       CRT_CPUthresholdLow, CRT_CPUthresholdHigh, CRT_ENGthreshold;
189    double       a, b, c;
190    int          d, factor, offset, fixsync = 1;
191    int          num, denum, div, sbit, scale;
192    Bool	 sis6326tvmode, sis6326himode;
193
194    /* Save the registers for further processing */
195    (*pSiS->SiSSave)(pScrn, pReg);
196
197    /* Initialise the standard VGA registers */
198    if(!pSiS->UseVESA) {
199       if(!SiSVGAInit(pScrn, mode, fixsync)) {
200          xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SISInit: SiSVGAInit() failed\n");
201          return FALSE;
202       }
203    }
204
205    /* Determine if chosen mode is suitable for TV on the 6326
206     * and if the mode is one of our special hi-res modes.
207     */
208    sis6326tvmode = FALSE;
209    sis6326himode = FALSE;
210    if(pSiS->Chipset == PCI_CHIP_SIS6326) {
211       if(pSiS->SiS6326Flags & SIS6326_HASTV) {
212	  if((pSiS->SiS6326Flags & SIS6326_TVDETECTED) &&
213	     ((strcmp(mode->name, "PAL800x600") == 0)   ||	/* Special TV modes */
214	      (strcmp(mode->name, "PAL800x600U") == 0)  ||
215	      (strcmp(mode->name, "PAL720x540") == 0)   ||
216	      (strcmp(mode->name, "PAL640x480") == 0)   ||
217	      (strcmp(mode->name, "NTSC640x480") == 0)  ||
218	      (strcmp(mode->name, "NTSC640x480U") == 0) ||
219	      (strcmp(mode->name, "NTSC640x400") == 0))) {
220	     sis6326tvmode = TRUE;
221	  } else {
222	     pReg->sis6326tv[0x00] &= 0xfb;
223	  }
224       }
225       if((strcmp(mode->name, "SIS1280x1024-75") == 0) ||	/* Special high-res modes */
226	  (strcmp(mode->name, "SIS1600x1200-60") == 0)) {
227	  sis6326himode = TRUE;
228       }
229    }
230
231#ifdef UNLOCK_ALWAYS
232    outSISIDXREG(SISSR, 0x05, 0x86);
233#endif
234
235    if(!pSiS->UseVESA) {
236       pReg->sisRegs3C4[0x06] &= 0x01;
237    }
238
239    /* set interlace */
240    if(!(mode->Flags & V_INTERLACE)) {
241       offset = pSiS->CurrentLayout.displayWidth >> 3;
242    } else {
243       offset = pSiS->CurrentLayout.displayWidth >> 2;
244       if(!pSiS->UseVESA) {
245	  pReg->sisRegs3C4[0x06] |= 0x20;
246       }
247    }
248
249    /* Enable Linear and Enhanced Gfx Mode */
250    if(!pSiS->UseVESA) {
251       pReg->sisRegs3C4[0x06] |= 0x82;
252    }
253
254    /* Enable MMIO at PCI Register 14H (D[6:5]: 11) */
255    if(pSiS->oldChipset >= OC_SIS5597) {
256       pReg->sisRegs3C4[0x0B] |= 0x60;
257    } else {
258       pReg->sisRegs3C4[0x0B] |= 0x20;
259       pReg->sisRegs3C4[0x0B] &= ~0x40;
260    }
261
262    if(!pSiS->UseVESA) {
263
264       /* Enable 32bit mem access (D7), read-ahead cache (D5) */
265       pReg->sisRegs3C4[0x0C] |= 0x80;
266       if(pSiS->oldChipset > OC_SIS6225) {
267	  pReg->sisRegs3C4[0x0C] |= 0x20;
268       }
269
270       /* Some speed-up stuff */
271       switch(pSiS->Chipset) {
272       case PCI_CHIP_SIS5597:
273	  /* enable host bus */
274	  if(!pSiS->HostBus) {
275	     pReg->sisRegs3C4[0x34] &= ~0x08;
276	  } else {
277	    pReg->sisRegs3C4[0x34] |= 0x08;
278	  }
279	  /* fall through */
280       case PCI_CHIP_SIS6326:
281       case PCI_CHIP_SIS530:
282	  /* Enable "dual segment register mode" (D2) and "i/o gating while
283	   * write buffer is not empty" (D3)
284	   */
285	  pReg->sisRegs3C4[0x0B] |= 0x0C;
286       }
287
288       /* set colordepth */
289       if(pSiS->Chipset == PCI_CHIP_SIS530) {
290	  pReg->sisRegs3C4[0x09] &= 0x7F;
291       }
292       switch(pSiS->CurrentLayout.bitsPerPixel) {
293	  case 8:
294	     break;
295	  case 16:
296	     offset <<= 1;
297	     if(pSiS->CurrentLayout.depth == 15)
298		pReg->sisRegs3C4[0x06] |= 0x04;
299	     else
300		pReg->sisRegs3C4[0x06] |= 0x08;
301	     break;
302	  case 24:
303	     offset += (offset << 1);
304	     pReg->sisRegs3C4[0x06] |= 0x10;
305	     pReg->sisRegs3C4[0x0B] |= 0x90;
306	     break;
307	  case 32:
308	     if(pSiS->Chipset == PCI_CHIP_SIS530) {
309		offset <<= 2;
310		if(pSiS->oldChipset != OC_SIS620) {
311		   pReg->sisRegs3C4[0x06] |= 0x10;
312		}
313		pReg->sisRegs3C4[0x0B] |= 0x90;
314		pReg->sisRegs3C4[0x09] |= 0x80;
315	     } else return FALSE;
316	     break;
317       }
318    }
319
320    /* save screen pitch for acceleration functions */
321    pSiS->scrnOffset = pSiS->CurrentLayout.displayWidth *
322			((pSiS->CurrentLayout.bitsPerPixel + 7) / 8);
323
324    /* Set accelerator dest color depth to 0 - not supported on 530/620 */
325    pSiS->DstColor = 0;
326
327    if(!pSiS->UseVESA) {
328
329       /* set linear framebuffer addresses */
330       switch(pScrn->videoRam) {
331	  case 512:  temp = 0x00;  break;
332	  case 1024: temp = 0x20;  break;
333	  case 2048: temp = 0x40;  break;
334	  case 4096: temp = 0x60;  break;
335	  case 8192: temp = 0x80;  break;
336	  default:   temp = 0x20;
337       }
338       pReg->sisRegs3C4[0x20] = (pSiS->FbAddress & 0x07F80000) >> 19;
339       pReg->sisRegs3C4[0x21] = ((pSiS->FbAddress & 0xF8000000) >> 27) | temp;
340
341       /* Set screen offset */
342       pReg->sisRegs3D4[0x13] = offset & 0xFF;
343
344       /* Set CR registers for our built-in TV and hi-res modes */
345       if((sis6326tvmode) || (sis6326himode)) {
346
347	  int index,i;
348
349	  /* We need our very private data for hi-res and TV modes */
350	  if(sis6326himode) {
351	     if(strcmp(mode->name, "SIS1280x1024-75") == 0)  index = 7;
352	     else index = 8;
353	  } else {
354	     if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
355		switch(width) {
356		case 800:
357		   if((strcmp(mode->name, "PAL800x600U") == 0))
358		      index = 4;
359		   else
360		      index = 0;
361		   break;
362		case 720:
363		   index = 5;
364		   break;
365		case 640:
366		default:
367		   index = 1;
368		}
369	     } else {
370		switch(height) {
371		case 400:
372		   index = 3;
373		   break;
374		case 480:
375		default:
376		   if((strcmp(mode->name, "NTSC640x480U") == 0))
377		      index = 6;
378		   else
379		      index = 2;
380		}
381	     }
382	  }
383	  for(i=0; i<=5; i++) {
384	     pReg->sisRegs3D4[i] = SiS6326CR[index][i];
385	  }
386	  pReg->sisRegs3C4[0x12] = SiS6326CR[index][6];
387	  pReg->sisRegs3D4[6] = SiS6326CR[index][7];
388	  pReg->sisRegs3D4[7] = SiS6326CR[index][8];
389	  pReg->sisRegs3D4[0x10] = SiS6326CR[index][9];
390	  pReg->sisRegs3D4[0x11] = SiS6326CR[index][10];
391	  pReg->sisRegs3D4[0x12] = SiS6326CR[index][11];
392	  pReg->sisRegs3D4[0x15] = SiS6326CR[index][12];
393	  pReg->sisRegs3D4[0x16] = SiS6326CR[index][13];
394	  pReg->sisRegs3D4[9] &= ~0x20;
395	  pReg->sisRegs3D4[9] |= (SiS6326CR[index][14] & 0x20);
396	  pReg->sisRegs3C4[0x0A] = ((offset & 0xF00) >> 4) | (SiS6326CR[index][14] & 0x0f);
397
398       } else {
399
400	  /* Set extended vertical overflow register */
401	  pReg->sisRegs3C4[0x0A] = (
402	      ((offset                                & 0xF00) >>  4) |
403	      (((mode->CrtcVTotal - 2)                & 0x400) >> 10) |
404	      (((mode->CrtcVDisplay - 1)              & 0x400) >>  9) |
405	      (((mode->CrtcVBlankStart - 1)           & 0x400) >>  8) |
406	      (((mode->CrtcVSyncStart - fixsync)      & 0x400) >>  7));
407
408	  /* Set extended horizontal overflow register */
409	  pReg->sisRegs3C4[0x12] &= 0xE0;
410	  pReg->sisRegs3C4[0x12] |= (
411	      ((((mode->CrtcHTotal >> 3) - 5)          & 0x100) >> 8) |
412	      ((((mode->CrtcHDisplay >> 3) - 1)        & 0x100) >> 7) |
413	      ((((mode->CrtcHBlankStart >> 3) - 1)     & 0x100) >> 6) |
414	      ((((mode->CrtcHSyncStart >> 3) - fixsync)& 0x100) >> 5) |
415	      ((((mode->CrtcHBlankEnd >> 3) - 1)       & 0x40)  >> 2));
416       }
417
418       /* enable (or disable) line compare */
419       if(mode->CrtcVDisplay >= 1024)
420	  pReg->sisRegs3C4[0x38] |= 0x04;
421       else
422	  pReg->sisRegs3C4[0x38] &= 0xFB;
423
424       /* Enable (or disable) high speed DCLK (some 6326 and 530/620 only) */
425       if( ( (pSiS->Chipset == PCI_CHIP_SIS6326) &&
426	     ( (pSiS->ChipRev == 0xd0) || (pSiS->ChipRev == 0xd1) ||
427	       (pSiS->ChipRev == 0xd2) || (pSiS->ChipRev == 0x92) ||
428	       (pSiS->Flags & A6326REVAB) ) ) ||
429	   (pSiS->oldChipset > OC_SIS6326) ) {
430	 if( (pSiS->CurrentLayout.bitsPerPixel == 24) ||
431	     (pSiS->CurrentLayout.bitsPerPixel == 32) ||
432	     (mode->CrtcHDisplay >= 1280) )
433	    pReg->sisRegs3C4[0x3E] |= 0x01;
434	 else
435	    pReg->sisRegs3C4[0x3E] &= 0xFE;
436       }
437
438       /* We use the internal VCLK */
439       pReg->sisRegs3C4[0x38] &= 0xFC;
440
441       /* Programmable Clock */
442       pReg->sisRegs3C2 = inSISREG(SISMISCR) | 0x0C;
443
444#if 0
445       if(pSiS->oldChipset <= OC_SIS86202) {
446	  /* TODO: Handle SR07 for clock selection */
447	  /* 86C201 does not even have a programmable clock... */
448	  /* pReg->sisRegs3C4[0x07] &= 0x??; */
449       }
450#endif
451
452       /* Set VCLK */
453       if((sis6326tvmode) || (sis6326himode)) {
454
455	  /* For our built-in modes, the calculation is not suitable */
456	  if(sis6326himode) {
457	     if((strcmp(mode->name, "SIS1280x1024-75") == 0)) {
458		pReg->sisRegs3C4[0x2A] = 0x5d;	/* 1280x1024-75 */
459		pReg->sisRegs3C4[0x2B] = 0xa4;
460             } else {
461		pReg->sisRegs3C4[0x2A] = 0x59;	/* 1600x1200-60 */
462		pReg->sisRegs3C4[0x2B] = 0xa3;
463	     }
464	     pReg->sisRegs3C4[0x13] &= ~0x40;
465	  } else {
466             if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
467		/* PAL: 31.500 Mhz */
468		if((strcmp(mode->name, "PAL800x600U") == 0)) {
469		   pReg->sisRegs3C4[0x2A] = 0x46;
470		   pReg->sisRegs3C4[0x2B] = 0x49;
471		} else {
472		   pReg->sisRegs3C4[0x2A] = 0xab;
473		   pReg->sisRegs3C4[0x2B] = 0xe9;
474		}
475		pReg->sisRegs3C4[0x13] &= ~0x40;
476	     } else {
477		/* NTSC: 27.000 Mhz */
478		if((strcmp(mode->name, "NTSC640x480U") == 0)) {
479		   pReg->sisRegs3C4[0x2A] = 0x5a;
480		   pReg->sisRegs3C4[0x2B] = 0x65;
481		} else {
482		   pReg->sisRegs3C4[0x2A] = 0x29;
483		   pReg->sisRegs3C4[0x2B] = 0xe2;
484		}
485		pReg->sisRegs3C4[0x13] |= 0x40;
486	     }
487	  }
488
489       } else if(SiS_compute_vclk(clock, &num, &denum, &div, &sbit, &scale)) {
490
491	  pReg->sisRegs3C4[0x2A] = (num - 1) & 0x7f ;
492	  pReg->sisRegs3C4[0x2A] |= (div == 2) ? 0x80 : 0;
493	  pReg->sisRegs3C4[0x2B] = ((denum - 1) & 0x1f);
494	  pReg->sisRegs3C4[0x2B] |= (((scale -1) & 3) << 5);
495
496	  /* When setting VCLK, we should set SR13 first */
497	  if(sbit)
498	     pReg->sisRegs3C4[0x13] |= 0x40;
499	  else
500	     pReg->sisRegs3C4[0x13] &= 0xBF;
501
502#ifdef TWDEBUG
503	  xf86DrvMsg(0, X_INFO, "2a: %x 2b: %x 13: %x clock %d\n",
504		pReg->sisRegs3C4[0x2A], pReg->sisRegs3C4[0x2B], pReg->sisRegs3C4[0x13], clock);
505#endif
506
507       } else {
508
509	  /* if SiS_compute_vclk cannot handle the requested clock, try sisCalcClock */
510	  SiSCalcClock(pScrn, clock, 2, vclk);
511
512#define Midx    0
513#define Nidx    1
514#define VLDidx  2
515#define Pidx    3
516#define PSNidx  4
517
518	  pReg->sisRegs3C4[0x2A] = (vclk[Midx] - 1) & 0x7f;
519	  pReg->sisRegs3C4[0x2A] |= ((vclk[VLDidx] == 2) ? 1 : 0) << 7;
520
521	  /* D[4:0]: denumerator */
522	  pReg->sisRegs3C4[0x2B] = (vclk[Nidx] - 1) & 0x1f;
523
524	  if(vclk[Pidx] <= 4){
525	     /* postscale 1,2,3,4 */
526	     pReg->sisRegs3C4[0x2B] |= (vclk[Pidx] - 1) << 5;
527	     pReg->sisRegs3C4[0x13] &= 0xBF;
528	  } else {
529	     /* postscale 6,8 */
530	     pReg->sisRegs3C4[0x2B] |= ((vclk[Pidx] / 2) - 1) << 5;
531	     pReg->sisRegs3C4[0x13] |= 0x40;
532	  }
533	  pReg->sisRegs3C4[0x2B] |= 0x80 ;   /* gain for high frequency */
534
535       }
536
537       /* High speed DAC */
538       if(clock > 135000)
539	  pReg->sisRegs3C4[0x07] |= 0x02;
540
541       if(pSiS->oldChipset > OC_SIS6225) {
542	  /* 1 or 2 cycle DRAM (set by option FastVram) */
543	  if(pSiS->newFastVram == -1) {
544	     if(pSiS->oldChipset == OC_SIS620) {
545		/* Use different default on the 620 */
546		pReg->sisRegs3C4[0x34] |= 0x40;
547		pReg->sisRegs3C4[0x34] &= ~0x80;
548	     } else {
549		pReg->sisRegs3C4[0x34] |= 0x80;
550		pReg->sisRegs3C4[0x34] &= ~0x40;
551	     }
552	  } else if(pSiS->newFastVram == 1)
553	     pReg->sisRegs3C4[0x34] |= 0xC0;
554	  else
555	     pReg->sisRegs3C4[0x34] &= ~0xC0;
556
557	  if(pSiS->oldChipset == OC_SIS620) {
558	     /* Enable SGRAM burst timing (= bit clear) on the 620 */
559	     if(pSiS->Flags & SYNCDRAM) {
560		pReg->sisRegs3C4[0x35] &= ~0x20;
561	     } else {
562		pReg->sisRegs3C4[0x35] |= 0x20;
563	     }
564	  }
565       }
566
567    } /* VESA */
568
569    /* Logical line length */
570    pSiS->ValidWidth = TRUE;
571    pReg->sisRegs3C4[0x27] &= 0xCF;
572    if(pSiS->CurrentLayout.bitsPerPixel == 24) {
573       /* "Invalid logical width" */
574       pReg->sisRegs3C4[0x27] |= 0x30;
575       pSiS->ValidWidth = FALSE;
576    } else {
577       switch(pScrn->virtualX * (pSiS->CurrentLayout.bitsPerPixel >> 3)) {
578	 case 1024:
579		pReg->sisRegs3C4[0x27] |= 0x00;
580		break;
581	 case 2048:
582		pReg->sisRegs3C4[0x27] |= 0x10;
583		break;
584	 case 4096:
585		pReg->sisRegs3C4[0x27] |= 0x20;
586		break;
587	 default:
588		/* Invalid logical width */
589		pReg->sisRegs3C4[0x27] |= 0x30;
590		pSiS->ValidWidth = FALSE;
591		break;
592       }
593    }
594
595    /* Acceleration stuff */
596    if(!pSiS->NoAccel) {
597       pReg->sisRegs3C4[0x27] |= 0x40;   /* Enable engine programming registers */
598       if( (pSiS->TurboQueue) &&	 /* Handle TurboQueue */
599	   (pSiS->oldChipset > OC_SIS6225) &&
600	   ( (pSiS->Chipset != PCI_CHIP_SIS530) ||
601	     (pSiS->CurrentLayout.bitsPerPixel != 24) ) ) {
602	  pReg->sisRegs3C4[0x27] |= 0x80;        /* Enable TQ */
603	  if((pSiS->Chipset == PCI_CHIP_SIS530) ||
604	     ((pSiS->Chipset == PCI_CHIP_SIS6326 &&
605	      (pSiS->ChipRev == 0xd0 || pSiS->ChipRev == 0xd1 ||
606	       pSiS->ChipRev == 0xd2 || pSiS->ChipRev == 0x92 ||
607	       pSiS->ChipRev == 0x0a || pSiS->ChipRev == 0x1a ||
608	       pSiS->ChipRev == 0x2a || pSiS->ChipRev == 0x0b ||
609	       pSiS->ChipRev == 0x1b || pSiS->ChipRev == 0x2b) ) ) ) {
610	     /* pReg->sisRegs3C4[0x3D] |= 0x80;  */     /* Queue is 62K (530/620 specs) */
611	     pReg->sisRegs3C4[0x3D] &= 0x7F;         /* Queue is 30K (530/620 specs) */
612	  }
613	  /* Locate the TQ at the beginning of the last 64K block of
614	   * video RAM. The address is to be specified in 32K steps.
615	   */
616	  pReg->sisRegs3C4[0x2C] = (pScrn->videoRam - 64) / 32;
617	  if(pSiS->Chipset != PCI_CHIP_SIS530) {	/* 530/620: Reserved (don't touch) */
618	     pReg->sisRegs3C4[0x3C] &= 0xFC; 		/* 6326: Queue is all for 2D */
619	  }						/* 5597: Must be 0           */
620       } else {
621	  pReg->sisRegs3C4[0x27] &= 0x7F;
622       }
623    }
624
625
626    if(!pSiS->UseVESA) {
627
628       /* No idea what this does. The Windows driver does it, so we do it as well */
629       if(pSiS->Chipset == PCI_CHIP_SIS6326) {
630	  if((pSiS->ChipRev == 0xd0) || (pSiS->ChipRev == 0xd1) ||
631	     (pSiS->ChipRev == 0xd2) || (pSiS->ChipRev == 0x92) ||
632	     (pSiS->Flags & A6326REVAB)) {
633	     if((pSiS->Flags & (SYNCDRAM | RAMFLAG)) == (SYNCDRAM | RAMFLAG)) {
634	        if(!(pReg->sisRegs3C4[0x0E] & 0x03)) {
635	           pReg->sisRegs3C4[0x3E] |= 0x02;
636	        }
637	     }
638	  }
639       }
640
641       /* Set memclock */
642#if 0
643       /* We don't need to do this; the SetMClk option was not used since 4.0. */
644       if((pSiS->Chipset == PCI_CHIP_SIS5597) || (pSiS->Chipset == PCI_CHIP_SIS6326)) {
645          if(pSiS->MemClock > 66000) {
646             SiSCalcClock(pScrn, pSiS->MemClock, 1, vclk);
647
648             pReg->sisRegs3C4[0x28] = (vclk[Midx] - 1) & 0x7f ;
649             pReg->sisRegs3C4[0x28] |= ((vclk[VLDidx] == 2 ) ? 1 : 0 ) << 7 ;
650             pReg->sisRegs3C4[0x29] = (vclk[Nidx] -1) & 0x1f ;   /* bits [4:0] contain denumerator -MC */
651             if(vclk[Pidx] <= 4) {
652                pReg->sisRegs3C4[0x29] |= (vclk[Pidx] - 1) << 5 ; /* postscale 1,2,3,4 */
653                pReg->sisRegs3C4[0x13] &= 0x7F;
654             } else {
655                pReg->sisRegs3C4[0x29] |= ((vclk[Pidx] / 2) - 1) << 5 ;  /* postscale 6,8 */
656                pReg->sisRegs3C4[0x13] |= 0x80;
657             }
658             /* Check programmed memory clock. Enable only to check the above code */
659/*
660             mclk = 14318 * ((pReg->sisRegs3C4[0x28] & 0x7f) + 1);
661             mclk /= ((pReg->sisRegs3C4[0x29] & 0x0f) + 1);
662             if(!(pReg->sisRegs3C4[0x13] & 0x80)) {
663                mclk /= (((pReg->sisRegs3C4[0x29] & 0x60) >> 5) + 1);
664             } else {
665                if((pReg->sisRegs3C4[0x29] & 0x60) == 0x40) mclk /= 6;
666                if((pReg->sisRegs3C4[0x29] & 0x60) == 0x60) mclk /= 8;
667             }
668             xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,2,
669                 "Setting memory clock to %.3f MHz\n",
670                 mclk/1000.0);
671*/
672          }
673       }
674#endif
675
676       /* Set threshold values */
677       /*
678        * CPU/CRT Threshold:                     FIFO
679        *                           MCLK     ___________      VCLK
680        * cpu/engine <---o       o--------->|___________| -----------> CRT
681        *                ^       ^            ^       ^
682        *                 \     /             |       |
683        *                  \   /              |< gap >|
684        *                   \ /               |       |
685        *           selector switch   Thrsh. low     high
686        *
687        * CRT consumes the data in the FIFO during scanline display. When the
688        * amount of data in the FIFO reaches the Threshold low value, the selector
689        * switch will switch to the right, and the FIFO will be refilled with data.
690        * When the amount of data in the FIFO reaches the Threshold high value, the
691        * selector switch will switch to the left and allows the CPU and the chip
692        * engines to access the video RAM.
693        *
694        * The Threshold low values should be increased at higher bpps, simply because
695        * there is more data needed for the CRT. When Threshold low and high are very
696        * close to each other, the selector switch will be activated more often, which
697        * decreases performance.
698        *
699        */
700       switch(pSiS->Chipset) {
701       case PCI_CHIP_SIS5597:  factor = 65; break;
702       case PCI_CHIP_SIS6326:  factor = 30; break;
703       case PCI_CHIP_SIS530:   factor = (pSiS->Flags & UMA) ? 60 : 30; break;
704       default:                factor = (pScrn->videoRam > 1024) ? 24 : 12;
705       }
706       a = width * height * rate * 1.40 * factor * ((pSiS->CurrentLayout.bitsPerPixel + 1) / 8);
707       b = (mclk / 1000) * 999488.0 * (buswidth / 8);
708       c = ((a / b) + 1.0) / 2;
709       d = (int)c + 2;
710
711       CRT_CPUthresholdLow = d;
712       if((pSiS->Flags & (RAMFLAG | SYNCDRAM)) == (RAMFLAG | SYNCDRAM)) {
713          CRT_CPUthresholdLow += 2;
714       }
715       CRT_CPUthresholdHigh = CRT_CPUthresholdLow + 3;
716
717       CRT_ENGthreshold = 0x0F;
718
719#if 0  /* See comment in sis_dac.c on why this is commented */
720       if(pSiS->Chipset == PCI_CHIP_SIS530) {
721	  if((pSiS->oldChipset == OC_SIS530A) &&
722	     (pSiS->Flags & UMA) &&
723	     (mclk == 100000) &&
724	     (pSiS->Flags & ESS137xPRESENT)) {
725	       if(!(pSiS->Flags & SECRETFLAG)) index = 0;
726	       if((temp = SiS_CalcSpecial530Threshold(pSiS, mode, index)) {
727		   CRT_CPUthresholdLow = temp;
728		   break;
729	       }
730	  }
731       }
732#endif
733
734       switch(pSiS->Chipset) {
735       case PCI_CHIP_SIS530:
736	  if(CRT_CPUthresholdLow > 0x1f)  CRT_CPUthresholdLow = 0x1f;
737	  CRT_CPUthresholdHigh = 0x1f;
738	  break;
739       case PCI_CHIP_SIS5597:
740       case PCI_CHIP_SIS6326:
741       default:
742	  if(CRT_CPUthresholdLow > 0x0f)  CRT_CPUthresholdLow  = 0x0f;
743	  if(CRT_CPUthresholdHigh > 0x0f) CRT_CPUthresholdHigh = 0x0f;
744       }
745
746       pReg->sisRegs3C4[0x08] = ((CRT_CPUthresholdLow & 0x0F) << 4) |
747				(CRT_ENGthreshold & 0x0F);
748
749       pReg->sisRegs3C4[0x09] &= 0xF0;
750       pReg->sisRegs3C4[0x09] |= (CRT_CPUthresholdHigh & 0x0F);
751
752       pReg->sisRegs3C4[0x3F] &= 0xEB;
753       pReg->sisRegs3C4[0x3F] |= ((CRT_CPUthresholdHigh & 0x10) |
754				  ((CRT_CPUthresholdLow & 0x10) >> 2));
755
756       if(pSiS->oldChipset >= OC_SIS530A) {
757	  pReg->sisRegs3C4[0x3F] &= 0xDF;
758	  pReg->sisRegs3C4[0x3F] |= 0x58;
759       }
760
761       /* Set SiS6326 TV registers */
762       if((pSiS->Chipset == PCI_CHIP_SIS6326) && (sis6326tvmode)) {
763	  UChar tmp;
764	  int index=0, i, j, k;
765	  int fsc;
766
767	  if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
768	     pReg->sisRegs3C4[0x0D] |= 0x04;
769	     switch(width) {
770	     case 800:
771	        if((strcmp(mode->name, "PAL800x600U") == 0))  index = 4;
772	        else	        			      index = 3;
773	        break;
774	     case 720: index = 5;  break;
775	     case 640:
776	     default:  index = 2;
777	     }
778	     for(i=0; i<14; i++) {
779	        pReg->sis6326tv[SiS6326TVRegs1[i]] = SiS6326TVRegs1_PAL[index][i];
780	     }
781	     fsc = (SiS6326TVRegs1_PAL[index][2] << 16) |
782		   (SiS6326TVRegs1_PAL[index][3] << 8)  |
783		   (SiS6326TVRegs1_PAL[index][4]);
784	  } else {
785	     pReg->sisRegs3C4[0x0D] &= ~0x04;
786	     if((strcmp(mode->name, "NTSC640x480U") == 0))  index = 5;
787	     else 					    index = 4;
788	     for(i=0; i<14; i++) {
789	        pReg->sis6326tv[SiS6326TVRegs1[i]] = SiS6326TVRegs1_NTSC[index][i];
790	     }
791	     fsc = (SiS6326TVRegs1_NTSC[index][2] << 16) |
792	           (SiS6326TVRegs1_NTSC[index][3] << 8)  |
793	           (SiS6326TVRegs1_NTSC[index][4]);
794	  }
795	  if(pSiS->sis6326fscadjust) {
796	     fsc += pSiS->sis6326fscadjust;
797	     pReg->sis6326tv[2] = (fsc >> 16) & 0xff;
798	     pReg->sis6326tv[3] = (fsc >> 8) & 0xff;
799	     pReg->sis6326tv[4] = fsc & 0xff;
800	  }
801	  tmp = pReg->sis6326tv[0x43];
802	  if(pSiS->SiS6326Flags & SIS6326_TVCVBS) tmp |= 0x10;
803	  tmp |= 0x08;
804	  pReg->sis6326tv[0x43] = tmp;
805	  j = 0; k = 0;
806	  for(i=0; i<=0x44; i++) {
807	     if(SiS6326TVRegs1[j] == i) {
808		j++;
809		continue;
810	     }
811	     if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
812		tmp = SiS6326TVRegs2_PAL[index][k];
813	     } else {
814		tmp = SiS6326TVRegs2_NTSC[index][k];
815	     }
816	     pReg->sis6326tv[i] = tmp;
817	     k++;
818	  }
819	  pReg->sis6326tv[0x43] |= 0x08;
820	  if((pSiS->ChipRev == 0xc1) || (pSiS->ChipRev == 0xc2)) {
821	     pReg->sis6326tv[0x43] &= ~0x08;
822	  }
823
824	  tmp = pReg->sis6326tv[0];
825	  tmp |= 0x18;
826	  if(pSiS->SiS6326Flags & SIS6326_TVCVBS)   tmp &= ~0x10;
827	  if(pSiS->SiS6326Flags & SIS6326_TVSVIDEO) tmp &= ~0x08;
828	  tmp |= 0x04;
829	  pReg->sis6326tv[0] = tmp;
830       }
831
832    } /* VESA */
833
834    return TRUE;
835}
836
837/* Init a mode for SiS 300, 315, 330, 340 series
838 * This function is now only used for setting up some
839 * variables (eg. scrnOffset).
840 */
841Bool
842SIS300Init(ScrnInfoPtr pScrn, DisplayModePtr mode)
843{
844    SISPtr    pSiS = SISPTR(pScrn);
845    SISRegPtr pReg = &pSiS->ModeReg;
846    UShort    temp;
847    DisplayModePtr realmode = mode;
848
849    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SIS300Init()\n"));
850
851    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
852	"virtualX = %d depth = %d Logical width = %d\n",
853	pScrn->virtualX, pSiS->CurrentLayout.bitsPerPixel,
854	pScrn->virtualX * pSiS->CurrentLayout.bitsPerPixel/8);
855
856#ifdef SISMERGED
857    if(pSiS->MergedFB) {
858       realmode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
859    }
860#endif
861
862    /* Copy current register settings to structure */
863    (*pSiS->SiSSave)(pScrn, pReg);
864
865    /* Calculate Offset/Display Pitch */
866    pSiS->scrnOffset = pSiS->CurrentLayout.displayWidth *
867                          ((pSiS->CurrentLayout.bitsPerPixel + 7) / 8);
868
869    pSiS->scrnPitch = pSiS->scrnPitch2 = pSiS->scrnOffset;
870    if(!(pSiS->VBFlags & CRT1_LCDA)) {
871       if(realmode->Flags & V_INTERLACE) pSiS->scrnPitch <<= 1;
872    }
873    /* CRT2 mode can never be interlaced */
874
875#ifdef UNLOCK_ALWAYS
876    outSISIDXREG(SISSR, 0x05, 0x86);
877#endif
878
879    switch(pSiS->CurrentLayout.bitsPerPixel) {
880	case 8:
881	    pSiS->DstColor = 0x0000;
882	    pSiS->SiS310_AccelDepth = 0x00000000;
883	    break;
884	case 16:
885	    if(pSiS->CurrentLayout.depth == 15)
886	        pSiS->DstColor = (short) 0x4000;
887	    else
888	        pSiS->DstColor = (short) 0x8000;
889	    pSiS->SiS310_AccelDepth = 0x00010000;
890	    break;
891	case 32:
892	    pSiS->DstColor = (short) 0xC000;
893	    pSiS->SiS310_AccelDepth = 0x00020000;
894	    break;
895    }
896
897    /* Enable PCI LINEAR ADDRESSING (0x80), MMIO (0x01), PCI_IO (0x20) */
898    pReg->sisRegs3C4[0x20] = 0xA1;
899
900    /* Now initialize TurboQueue. TB is always located at the very top of
901     * the videoRAM (notably NOT the x framebuffer memory, which can/should
902     * be limited by MaxXFbMem when using DRI). Also, enable the accelerators.
903     */
904    if(!pSiS->NoAccel) {
905	pReg->sisRegs3C4[0x1E] |= 0x42;  /* Enable 2D accelerator */
906	pReg->sisRegs3C4[0x1E] |= 0x18;  /* Enable 3D accelerator */
907	switch(pSiS->VGAEngine) {
908	case SIS_300_VGA:
909	  if(pSiS->TurboQueue) {    		/* set Turbo Queue as 512k */
910	    temp = ((pScrn->videoRam/64)-8);    /* 8=512k, 4=256k, 2=128k, 1=64k */
911	    pReg->sisRegs3C4[0x26] = temp & 0xFF;
912	    pReg->sisRegs3C4[0x27] =
913		(pReg->sisRegs3C4[0x27] & 0xfc) | (((temp >> 8) & 3) | 0xF0);
914	  }	/* line above new for saving D2&3 of status register */
915	  break;
916	case SIS_315_VGA:
917#ifndef SISVRAMQ
918	  /* See comments in sis_driver.c */
919	  pReg->sisRegs3C4[0x27] = 0x1F;
920	  pReg->sisRegs3C4[0x26] = 0x22;
921	  pReg->sisMMIO85C0 = (pScrn->videoRam - 512) * 1024;
922#endif
923	  break;
924	}
925    }
926
927    return TRUE;
928}
929
930static void
931SiS6326TVDelay(ScrnInfoPtr pScrn, int delay)
932{
933    SISPtr  pSiS = SISPTR(pScrn);
934    int i;
935    UChar temp;
936
937    for(i=0; i<delay; i++) {
938       inSISIDXREG(SISSR, 0x05, temp);
939    }
940    (void)temp;
941}
942
943static int
944SIS6326DoSense(ScrnInfoPtr pScrn, int tempbh, int tempbl, int tempch, int tempcl)
945{
946    UChar temp;
947
948    SiS6326SetTVReg(pScrn, 0x42, tempbl);
949    temp = SiS6326GetTVReg(pScrn, 0x43);
950    temp &= 0xfc;
951    temp |= tempbh;
952    SiS6326SetTVReg(pScrn, 0x43, temp);
953    SiS6326TVDelay(pScrn, 0x1000);
954    temp = SiS6326GetTVReg(pScrn, 0x43);
955    temp |= 0x04;
956    SiS6326SetTVReg(pScrn, 0x43, temp);
957    SiS6326TVDelay(pScrn, 0x8000);
958    temp = SiS6326GetTVReg(pScrn, 0x44);
959    if(!(tempch & temp)) tempcl = 0;
960    return tempcl;
961}
962
963static void
964SISSense6326(ScrnInfoPtr pScrn)
965{
966    SISPtr pSiS = SISPTR(pScrn);
967    UChar  temp;
968    int    result;
969
970    pSiS->SiS6326Flags &= (SIS6326_HASTV | SIS6326_TVPAL);
971    temp = SiS6326GetTVReg(pScrn, 0x43);
972    temp &= 0xfb;
973    SiS6326SetTVReg(pScrn, 0x43, temp);
974    result = SIS6326DoSense(pScrn, 0x01, 0xb0, 0x06, SIS6326_TVSVIDEO);  /* 0x02 */
975    pSiS->SiS6326Flags |= result;
976    result = SIS6326DoSense(pScrn, 0x01, 0xa0, 0x01, SIS6326_TVCVBS);    /* 0x04 */
977    pSiS->SiS6326Flags |= result;
978    temp = SiS6326GetTVReg(pScrn, 0x43);
979    temp &= 0xfb;
980    SiS6326SetTVReg(pScrn, 0x43, temp);
981    if(pSiS->SiS6326Flags & (SIS6326_TVSVIDEO | SIS6326_TVCVBS)) {
982       pSiS->SiS6326Flags |= SIS6326_TVDETECTED;
983       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
984	    "SiS6326: Detected TV connected to %s output\n",
985		(((pSiS->SiS6326Flags & (SIS6326_TVSVIDEO | SIS6326_TVCVBS)) ==
986		   (SIS6326_TVSVIDEO | SIS6326_TVCVBS)) ?
987			"both SVIDEO and COMPOSITE" :
988			   ((pSiS->SiS6326Flags & SIS6326_TVSVIDEO) ?
989				"SVIDEO" : "COMPOSITE")));
990    } else {
991       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
992	    "SiS6326: No TV detected\n");
993    }
994}
995
996static Bool
997SISIsUMC(SISPtr pSiS)
998{
999    UShort p4_0f, p4_25, p4_27, temp;
1000
1001    inSISIDXREG(SISPART4, 0x0f, p4_0f);
1002    inSISIDXREG(SISPART4, 0x25, p4_25);
1003    inSISIDXREG(SISPART4, 0x27, p4_27);
1004    andSISIDXREG(SISPART4, 0x0f, 0x7f);
1005    orSISIDXREG(SISPART4, 0x25, 0x08);
1006    andSISIDXREG(SISPART4, 0x27, 0xfd);
1007    inSISIDXREG(SISPART4, 0x26, temp);
1008    outSISIDXREG(SISPART4, 0x27, p4_27);
1009    outSISIDXREG(SISPART4, 0x25, p4_25);
1010    outSISIDXREG(SISPART4, 0x0f, p4_0f);
1011    return((temp & 0x08) ? TRUE : FALSE);
1012}
1013
1014/* Detect video bridge and set VBFlags accordingly */
1015void SISVGAPreInit(ScrnInfoPtr pScrn)
1016{
1017    SISPtr pSiS = SISPTR(pScrn);
1018    int    temp,temp1,temp2,sistypeidx;
1019    int    upperlimitlvds, lowerlimitlvds;
1020    int    upperlimitch, lowerlimitch;
1021    int    chronteltype, chrontelidreg, upperlimitvb;
1022    static const char *detectvb = "Detected SiS%s video bridge (%s, ID %d; Rev 0x%x)\n";
1023#if 0
1024    UChar sr17=0;
1025#endif
1026    static const char *ChrontelTypeStr[] = {
1027	"7004",
1028	"7005",
1029	"7007",
1030	"7006",
1031	"7008",
1032	"7013",
1033	"7019",
1034	"7020",
1035	"(unknown)"
1036    };
1037    static const char *SiSVBTypeStr[] = {
1038	"301",		/* 0 */
1039	"301B",		/* 1 */
1040	"301B-DH",	/* 2 */
1041	"301LV",	/* 3 */
1042	"302LV",	/* 4 */
1043	"301C",		/* 5 */
1044	"302ELV",	/* 6 */
1045	"302B"		/* 7 */
1046    };
1047
1048    switch(pSiS->Chipset) {
1049       case PCI_CHIP_SIS300:
1050       case PCI_CHIP_SIS540:
1051       case PCI_CHIP_SIS630:
1052       case PCI_CHIP_SIS550:
1053       case PCI_CHIP_SIS315:
1054       case PCI_CHIP_SIS315H:
1055       case PCI_CHIP_SIS315PRO:
1056       case PCI_CHIP_SIS650:
1057       case PCI_CHIP_SIS330:
1058       case PCI_CHIP_SIS660:
1059       case PCI_CHIP_SIS340:
1060       case PCI_CHIP_XGIXG20:
1061       case PCI_CHIP_XGIXG40:
1062          pSiS->ModeInit = SIS300Init;
1063          break;
1064       default:
1065          pSiS->ModeInit = SISInit;
1066    }
1067
1068    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
1069       UChar sr0d;
1070       inSISIDXREG(SISSR, 0x0d, sr0d);
1071       if(sr0d & 0x04) {
1072	  pSiS->SiS6326Flags |= SIS6326_TVPAL;
1073       }
1074       SISSense6326(pScrn);
1075    }
1076
1077    pSiS->VBFlags = pSiS->VBFlags2 = 0; /* reset VBFlags */
1078    pSiS->SiS_Pr->SiS_UseLCDA = FALSE;
1079    pSiS->SiS_Pr->Backup = FALSE;
1080
1081    /* Videobridges only available for 300/315/330/340 series */
1082    if((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA))
1083       return;
1084
1085    /* No video bridge ever on XGI Z7 (XG20) */
1086    if(pSiS->ChipType == XGI_20)
1087       return;
1088
1089    inSISIDXREG(SISPART4, 0x00, temp);
1090    temp &= 0x0F;
1091    if(temp == 1) {
1092
1093        inSISIDXREG(SISPART4, 0x01, temp1);
1094	temp1 &= 0xff;
1095
1096	if(temp1 >= 0xC0) {
1097	   if(SISIsUMC(pSiS)) pSiS->VBFlags2 |= VB2_SISUMC;
1098	}
1099
1100        if(temp1 >= 0xE0) {
1101		inSISIDXREG(SISPART4, 0x39, temp2);
1102		if(temp2 == 0xff) {
1103		   pSiS->VBFlags2 |= VB2_302LV;
1104		   sistypeidx = 4;
1105		} else {
1106		   pSiS->VBFlags2 |= VB2_301C;	/* VB_302ELV; */
1107		   sistypeidx = 5; 		/* 6; */
1108		}
1109	} else if(temp1 >= 0xD0) {
1110		pSiS->VBFlags2 |= VB2_301LV;
1111		sistypeidx = 3;
1112	} else if(temp1 >= 0xC0) {
1113		pSiS->VBFlags2 |= VB2_301C;
1114		sistypeidx = 5;
1115	} else if(temp1 >= 0xB0) {
1116		pSiS->VBFlags2 |= VB2_301B;
1117		sistypeidx = 1;
1118		inSISIDXREG(SISPART4, 0x23, temp2);
1119		if(!(temp2 & 0x02)) {
1120		   pSiS->VBFlags2 |= VB2_30xBDH;
1121		   sistypeidx = 2;
1122		}
1123	} else {
1124		pSiS->VBFlags2 |= VB2_301;
1125		sistypeidx = 0;
1126	}
1127
1128	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, detectvb, SiSVBTypeStr[sistypeidx],
1129				(pSiS->VBFlags2 & VB2_SISUMC) ? "UMC-0" : "Charter/UMC-1", 1, temp1);
1130
1131	SISSense30x(pScrn, FALSE);
1132
1133    } else if(temp == 2) {
1134
1135	inSISIDXREG(SISPART4, 0x01, temp1);
1136	temp1 &= 0xff;
1137
1138	if(temp1 >= 0xC0) {
1139	   if(SISIsUMC(pSiS)) pSiS->VBFlags2 |= VB2_SISUMC;
1140	}
1141
1142	if(temp1 >= 0xE0) {
1143		pSiS->VBFlags2 |= VB2_302LV;
1144		sistypeidx = 4;
1145	} else if(temp1 >= 0xD0) {
1146		pSiS->VBFlags2 |= VB2_301LV;
1147		sistypeidx = 3;
1148	} else {
1149		pSiS->VBFlags2 |= VB2_302B;
1150		sistypeidx = 7;
1151	}
1152
1153	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, detectvb, SiSVBTypeStr[sistypeidx],
1154				(pSiS->VBFlags2 & VB2_SISUMC) ? "UMC-0" : "Charter/UMC-1", 2, temp1);
1155
1156	SISSense30x(pScrn, FALSE);
1157
1158    } else if (temp == 3) {
1159
1160	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, detectvb, "303", "unsupported, unknown", temp, 0);
1161
1162    } else {
1163
1164	if(pSiS->NewCRLayout) {
1165	   inSISIDXREG(SISCR, 0x38, temp);
1166	   temp = (temp >> 5) & 0x07;
1167	} else {
1168	   inSISIDXREG(SISCR, 0x37, temp);
1169	   temp = (temp >> 1) & 0x07;
1170	}
1171	if(pSiS->VGAEngine == SIS_300_VGA) {
1172	   lowerlimitlvds = 2; upperlimitlvds = 4;
1173	   lowerlimitch   = 4; upperlimitch   = 5;
1174	   chronteltype = 1;   chrontelidreg  = 0x25;
1175	   upperlimitvb = upperlimitlvds;
1176	} else {
1177	   lowerlimitlvds = 2; upperlimitlvds = 3;
1178	   lowerlimitch   = 3; upperlimitch   = 3;
1179	   chronteltype = 2;   chrontelidreg  = 0x4b;
1180	   upperlimitvb = upperlimitlvds;
1181	   if(pSiS->NewCRLayout) {
1182	      upperlimitvb = 4;
1183	   }
1184	}
1185
1186	if((temp >= lowerlimitlvds) && (temp <= upperlimitlvds)) {
1187	   pSiS->VBFlags2 |= VB2_LVDS;
1188	   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1189	          "Detected LVDS transmitter (External chip ID %d)\n", temp);
1190	}
1191	if((temp >= lowerlimitch) && (temp <= upperlimitch))  {
1192	   /* Set global for init301.c */
1193	   pSiS->SiS_Pr->SiS_IF_DEF_CH70xx = chronteltype;
1194
1195	   if(chronteltype == 1) {
1196	      /* Set general purpose IO for Chrontel communication */
1197	      SiS_SetChrontelGPIO(pSiS->SiS_Pr, 0x9c);
1198	   }
1199
1200	   /* Read Chrontel version number */
1201	   temp1 = SiS_GetCH70xx(pSiS->SiS_Pr, chrontelidreg);
1202	   if(chronteltype == 1) {
1203	      /* See Chrontel TB31 for explanation */
1204	      temp2 = SiS_GetCH700x(pSiS->SiS_Pr, 0x0e);
1205	      if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
1206		 SiS_SetCH700x(pSiS->SiS_Pr, 0x0e, 0x0b);
1207		 SiS_DDC2Delay(pSiS->SiS_Pr, 300);
1208	      }
1209	      temp2 = SiS_GetCH70xx(pSiS->SiS_Pr, chrontelidreg);
1210	      if(temp2 != temp1) temp1 = temp2;
1211	   }
1212	   if(temp1 == 0xFFFF) {	/* 0xFFFF = error reading DDC port */
1213	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1214			"Detected Chrontel 70xx, but encountered error reading I2C port\n");
1215	      andSISIDXREG(SISCR, 0x32, ~0x07);
1216	      pSiS->postVBCR32 &= ~0x07;
1217	   } else if((temp1 >= 0x19) && (temp1 <= 200)) {
1218	      /* We only support device ids 0x19-200; other values may indicate DDC problems */
1219	      pSiS->VBFlags2 |= VB2_CHRONTEL;
1220	      switch (temp1) {
1221		case 0x32: temp2 = 0; pSiS->ChrontelType = CHRONTEL_700x; break;
1222		case 0x3A: temp2 = 1; pSiS->ChrontelType = CHRONTEL_700x; break;
1223		case 0x50: temp2 = 2; pSiS->ChrontelType = CHRONTEL_700x; break;
1224		case 0x2A: temp2 = 3; pSiS->ChrontelType = CHRONTEL_700x; break;
1225		case 0x40: temp2 = 4; pSiS->ChrontelType = CHRONTEL_700x; break;
1226		case 0x22: temp2 = 5; pSiS->ChrontelType = CHRONTEL_700x; break;
1227	        case 0x19: temp2 = 6; pSiS->ChrontelType = CHRONTEL_701x; break;
1228	        case 0x20: temp2 = 7; pSiS->ChrontelType = CHRONTEL_701x; break;  /* ID for 7020? */
1229		default:   temp2 = 8; pSiS->ChrontelType = CHRONTEL_701x; break;
1230	      }
1231	      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1232			"Detected Chrontel %s TV encoder (ID 0x%02x; chip ID %d)\n",
1233					ChrontelTypeStr[temp2], temp1, temp);
1234
1235	      /* Sense connected TV's */
1236	      SISSenseChrontel(pScrn, FALSE);
1237
1238	   } else if(temp1 == 0) {
1239	      /* This indicates a communication problem, but it only occures if there
1240	       * is no TV attached. So we don't use TV in this case.
1241	       */
1242	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1243			"Detected Chrontel TV encoder in promiscuous state (DDC/I2C mix-up)\n");
1244	      andSISIDXREG(SISCR, 0x32, ~0x07);
1245	      pSiS->postVBCR32 &= ~0x07;
1246	   } else {
1247	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1248			"Chrontel: Unsupported device id (%d) detected\n",temp1);
1249	      andSISIDXREG(SISCR, 0x32, ~0x07);
1250	      pSiS->postVBCR32 &= ~0x07;
1251	   }
1252	   if(chronteltype == 1) {
1253	      /* Set general purpose IO for Chrontel communication */
1254	      SiS_SetChrontelGPIO(pSiS->SiS_Pr, 0x00);
1255	   }
1256	}
1257	if((pSiS->NewCRLayout) && (temp == 4)) {
1258	   pSiS->VBFlags2 |= VB2_CONEXANT;
1259	   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1260	               "Detected Conexant video bridge - UNSUPPORTED\n");
1261	}
1262	if((pSiS->VGAEngine == SIS_300_VGA) && (temp == 3)) {
1263	    pSiS->VBFlags2 |= VB2_TRUMPION;
1264	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1265	               "Detected Trumpion Zurac (I/II/III) LVDS scaler\n");
1266	}
1267	if(temp > upperlimitvb) {
1268	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1269	               "Detected unknown bridge type (%d)\n", temp);
1270	}
1271    }
1272
1273   /* Old BIOSes store the detected CRT2 type in SR17, 16 and 13
1274    * instead of CR32. However, since our detection routines
1275    * store their results to CR32, we now copy the
1276    * remaining bits (for LCD and VGA) to CR32 for unified usage.
1277    * SR17[0] CRT1     [1] LCD       [2] TV    [3] VGA2
1278    *     [4] AVIDEO   [5] SVIDEO
1279    * SR13[0] SCART    [1] HiVision
1280    * SR16[5] PAL/NTSC [6] LCD-SCALE [7] OVERSCAN
1281    */
1282
1283#if 0
1284    inSISIDXREG(SISSR, 0x17, sr17);
1285    if( (pSiS->VGAEngine == SIS_300_VGA) &&
1286        (pSiS->Chipset != PCI_CHIP_SIS300) &&
1287        (sr17 & 0x0F) ) {
1288
1289	UChar cr32;
1290	inSISIDXREG(SISCR, 0x32, cr32);
1291
1292	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1293		"Converting SR17 (%02x) to CR32 (%02x)\n", sr17, cr32);
1294
1295	 if(sr17 & 0x01) {  	/* CRT1 */
1296		orSISIDXREG(SISCR, 0x32, 0x20);
1297		pSiS->postVBCR32 |= 0x20;
1298	 } else {
1299		andSISIDXREG(SISCR, 0x32, ~0x20);
1300		pSiS->postVBCR32 &= ~0x20;
1301	 }
1302
1303	 if(sr17 & 0x02) {	/* LCD */
1304		orSISIDXREG(SISCR, 0x32, 0x08);
1305		pSiS->postVBCR32 |= 0x08;
1306	 } else	{
1307		andSISIDXREG(SISCR, 0x32, ~0x08);
1308		pSiS->postVBCR32 &= ~0x08;
1309	 }
1310
1311	 /* No Hivision, no DVI here */
1312	 andSISIDXREG(SISCR,0x32,~0xc0);
1313	 pSiS->postVBCR32 &= ~0xc0;
1314    }
1315#endif
1316
1317    /* Try to find out if the bridge uses LCDA for low resolution and
1318     * text modes. If sisfb saved this for us, use it. Otherwise,
1319     * check if we are running on a low mode on LCD and read the
1320     * relevant registers ourselves.
1321     */
1322    if(pSiS->VGAEngine == SIS_315_VGA) {
1323
1324       if(pSiS->VBFlags2 & VB2_SISLCDABRIDGE) {
1325          if(pSiS->sisfblcda != 0xff) {
1326	     if((pSiS->sisfblcda & 0x03) == 0x03) {
1327		pSiS->SiS_Pr->SiS_UseLCDA = TRUE;
1328		pSiS->ChipFlags |= SiSCF_UseLCDA;
1329	     }
1330	  } else {
1331             inSISIDXREG(SISCR,0x34,temp);
1332	     if(temp <= 0x13) {
1333		inSISIDXREG(SISCR,0x38,temp);
1334		if((temp & 0x03) == 0x03) {
1335		   pSiS->SiS_Pr->SiS_UseLCDA = TRUE;
1336		   pSiS->ChipFlags |= SiSCF_UseLCDA;
1337		   pSiS->SiS_Pr->Backup = TRUE;
1338		} else {
1339		   orSISIDXREG(SISPART1,0x2f,0x01);  /* Unlock CRT2 */
1340		   inSISIDXREG(SISPART1,0x13,temp);
1341		   if(temp & 0x04) {
1342		      pSiS->SiS_Pr->SiS_UseLCDA = TRUE;
1343		      pSiS->ChipFlags |= SiSCF_UseLCDA;
1344		      pSiS->SiS_Pr->Backup = TRUE;
1345		   }
1346		}
1347	     }
1348	  }
1349	  if(pSiS->ChipFlags & SiSCF_UseLCDA) {
1350	     xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 3,
1351		"BIOS uses LCDA for low resolution and text modes\n");
1352	     if(pSiS->SiS_Pr->Backup == TRUE) {
1353		inSISIDXREG(SISCR,0x34,pSiS->SiS_Pr->Backup_Mode);
1354		inSISIDXREG(SISPART1,0x14,pSiS->SiS_Pr->Backup_14);
1355		inSISIDXREG(SISPART1,0x15,pSiS->SiS_Pr->Backup_15);
1356		inSISIDXREG(SISPART1,0x16,pSiS->SiS_Pr->Backup_16);
1357		inSISIDXREG(SISPART1,0x17,pSiS->SiS_Pr->Backup_17);
1358		inSISIDXREG(SISPART1,0x18,pSiS->SiS_Pr->Backup_18);
1359		inSISIDXREG(SISPART1,0x19,pSiS->SiS_Pr->Backup_19);
1360		inSISIDXREG(SISPART1,0x1a,pSiS->SiS_Pr->Backup_1a);
1361		inSISIDXREG(SISPART1,0x1b,pSiS->SiS_Pr->Backup_1b);
1362		inSISIDXREG(SISPART1,0x1c,pSiS->SiS_Pr->Backup_1c);
1363		inSISIDXREG(SISPART1,0x1d,pSiS->SiS_Pr->Backup_1d);
1364	     }
1365	  }
1366       }
1367    }
1368}
1369
1370static void
1371SiS_WriteAttr(SISPtr pSiS, int index, int value)
1372{
1373    (void)inSISREG(SISINPSTAT);
1374    index |= 0x20;
1375    outSISREG(SISAR, index);
1376    outSISREG(SISAR, value);
1377}
1378
1379static int
1380SiS_ReadAttr(SISPtr pSiS, int index)
1381{
1382    (void)inSISREG(SISINPSTAT);
1383    index |= 0x20;
1384    outSISREG(SISAR, index);
1385    return(inSISREG(SISARR));
1386}
1387
1388static void
1389SiS_EnablePalette(SISPtr pSiS)
1390{
1391    (void)inSISREG(SISINPSTAT);
1392    outSISREG(SISAR, 0x00);
1393    pSiS->VGAPaletteEnabled = TRUE;
1394}
1395
1396static void
1397SiS_DisablePalette(SISPtr pSiS)
1398{
1399    (void)inSISREG(SISINPSTAT);
1400    outSISREG(SISAR, 0x20);
1401    pSiS->VGAPaletteEnabled = FALSE;
1402}
1403
1404void
1405SISVGALock(SISPtr pSiS)
1406{
1407    orSISIDXREG(SISCR, 0x11, 0x80);  	/* Protect CRTC[0-7] */
1408}
1409
1410void
1411SiSVGAUnlock(SISPtr pSiS)
1412{
1413    andSISIDXREG(SISCR, 0x11, 0x7f);	/* Unprotect CRTC[0-7] */
1414}
1415
1416#define SIS_FONTS_SIZE (8 * 8192)
1417
1418void
1419SiSVGASaveFonts(ScrnInfoPtr pScrn)
1420{
1421#ifdef SIS_PC_PLATFORM
1422    SISPtr pSiS = SISPTR(pScrn);
1423    pointer vgaMemBase = pSiS->VGAMemBase;
1424    UChar miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn;
1425
1426    if((pSiS->fonts) || (vgaMemBase == NULL)) return;
1427
1428    /* If in graphics mode, don't save anything */
1429    attr10 = SiS_ReadAttr(pSiS, 0x10);
1430    if(attr10 & 0x01) return;
1431
1432    if(!(pSiS->fonts = malloc(SIS_FONTS_SIZE * 2))) {
1433       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1434		"Could not save console fonts, mem allocation failed\n");
1435       return;
1436    }
1437
1438    /* save the registers that are needed here */
1439    miscOut = inSISREG(SISMISCR);
1440    inSISIDXREG(SISGR, 0x04, gr4);
1441    inSISIDXREG(SISGR, 0x05, gr5);
1442    inSISIDXREG(SISGR, 0x06, gr6);
1443    inSISIDXREG(SISSR, 0x02, seq2);
1444    inSISIDXREG(SISSR, 0x04, seq4);
1445
1446    /* Force into color mode */
1447    outSISREG(SISMISCW, miscOut | 0x01);
1448
1449    inSISIDXREG(SISSR, 0x01, scrn);
1450    outSISIDXREG(SISSR, 0x00, 0x01);
1451    outSISIDXREG(SISSR, 0x01, scrn | 0x20);
1452    outSISIDXREG(SISSR, 0x00, 0x03);
1453
1454    SiS_WriteAttr(pSiS, 0x10, 0x01);  /* graphics mode */
1455
1456    /*font1 */
1457    outSISIDXREG(SISSR, 0x02, 0x04);  /* write to plane 2 */
1458    outSISIDXREG(SISSR, 0x04, 0x06);  /* enable plane graphics */
1459    outSISIDXREG(SISGR, 0x04, 0x02);  /* read plane 2 */
1460    outSISIDXREG(SISGR, 0x05, 0x00);  /* write mode 0, read mode 0 */
1461    outSISIDXREG(SISGR, 0x06, 0x05);  /* set graphics */
1462    slowbcopy_frombus(vgaMemBase, pSiS->fonts, SIS_FONTS_SIZE);
1463
1464    /* font2 */
1465    outSISIDXREG(SISSR, 0x02, 0x08);  /* write to plane 3 */
1466    outSISIDXREG(SISSR, 0x04, 0x06);  /* enable plane graphics */
1467    outSISIDXREG(SISGR, 0x04, 0x03);  /* read plane 3 */
1468    outSISIDXREG(SISGR, 0x05, 0x00);  /* write mode 0, read mode 0 */
1469    outSISIDXREG(SISGR, 0x06, 0x05);  /* set graphics */
1470    slowbcopy_frombus(vgaMemBase, pSiS->fonts + SIS_FONTS_SIZE, SIS_FONTS_SIZE);
1471
1472    inSISIDXREG(SISSR, 0x01, scrn);
1473    outSISIDXREG(SISSR, 0x00, 0x01);
1474    outSISIDXREG(SISSR, 0x01, scrn & ~0x20);
1475    outSISIDXREG(SISSR, 0x00, 0x03);
1476
1477    /* Restore clobbered registers */
1478    SiS_WriteAttr(pSiS, 0x10, attr10);
1479    outSISIDXREG(SISSR, 0x02, seq2);
1480    outSISIDXREG(SISSR, 0x04, seq4);
1481    outSISIDXREG(SISGR, 0x04, gr4);
1482    outSISIDXREG(SISGR, 0x05, gr5);
1483    outSISIDXREG(SISGR, 0x06, gr6);
1484    outSISREG(SISMISCW, miscOut);
1485#endif
1486}
1487
1488static void
1489SiSVGASaveMode(ScrnInfoPtr pScrn, SISRegPtr save)
1490{
1491    SISPtr pSiS = SISPTR(pScrn);
1492    int i;
1493
1494    save->sisRegMiscOut = inSISREG(SISMISCR);
1495
1496    for(i = 0; i < 25; i++) {
1497       inSISIDXREG(SISCR, i, save->sisRegs3D4[i]);
1498    }
1499
1500    SiS_EnablePalette(pSiS);
1501    for(i = 0; i < 21; i++) {
1502       save->sisRegsATTR[i] = SiS_ReadAttr(pSiS, i);
1503    }
1504    SiS_DisablePalette(pSiS);
1505
1506    for(i = 0; i < 9; i++) {
1507       inSISIDXREG(SISGR, i, save->sisRegsGR[i]);
1508    }
1509
1510    for(i = 1; i < 5; i++) {
1511       inSISIDXREG(SISSR, i, save->sisRegs3C4[i]);
1512    }
1513}
1514
1515static void
1516SiSVGASaveColormap(ScrnInfoPtr pScrn, SISRegPtr save)
1517{
1518    SISPtr pSiS = SISPTR(pScrn);
1519    int i;
1520
1521    if(pSiS->VGACMapSaved) return;
1522
1523    outSISREG(SISPEL, 0xff);
1524
1525    outSISREG(SISCOLIDXR, 0x00);
1526    for(i = 0; i < 768; i++) {
1527       save->sisDAC[i] = inSISREG(SISCOLDATA);
1528       (void)inSISREG(SISINPSTAT);
1529       (void)inSISREG(SISINPSTAT);
1530    }
1531
1532    SiS_DisablePalette(pSiS);
1533    pSiS->VGACMapSaved = TRUE;
1534}
1535
1536void
1537SiSVGASave(ScrnInfoPtr pScrn, SISRegPtr save, int flags)
1538{
1539    if(save == NULL) return;
1540
1541    if(flags & SISVGA_SR_CMAP)  SiSVGASaveColormap(pScrn, save);
1542    if(flags & SISVGA_SR_MODE)  SiSVGASaveMode(pScrn, save);
1543    if(flags & SISVGA_SR_FONTS) SiSVGASaveFonts(pScrn);
1544}
1545
1546void
1547SiSVGARestoreFonts(ScrnInfoPtr pScrn)
1548{
1549#ifdef SIS_PC_PLATFORM
1550    SISPtr pSiS = SISPTR(pScrn);
1551    pointer vgaMemBase = pSiS->VGAMemBase;
1552    UChar miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn;
1553
1554    if((!pSiS->fonts) || (vgaMemBase == NULL)) return;
1555
1556    /* save the registers that are needed here */
1557    miscOut = inSISREG(SISMISCR);
1558    attr10 = SiS_ReadAttr(pSiS, 0x10);
1559    inSISIDXREG(SISGR, 0x01, gr1);
1560    inSISIDXREG(SISGR, 0x03, gr3);
1561    inSISIDXREG(SISGR, 0x04, gr4);
1562    inSISIDXREG(SISGR, 0x05, gr5);
1563    inSISIDXREG(SISGR, 0x06, gr6);
1564    inSISIDXREG(SISGR, 0x08, gr8);
1565    inSISIDXREG(SISSR, 0x02, seq2);
1566    inSISIDXREG(SISSR, 0x04, seq4);
1567
1568    /* Force into color mode */
1569    outSISREG(SISMISCW, miscOut | 0x01);
1570    inSISIDXREG(SISSR, 0x01, scrn);
1571    outSISIDXREG(SISSR, 0x00, 0x01);
1572    outSISIDXREG(SISSR, 0x01, scrn | 0x20);
1573    outSISIDXREG(SISSR, 0x00, 0x03);
1574
1575    SiS_WriteAttr(pSiS, 0x10, 0x01);	  /* graphics mode */
1576    if(pScrn->depth == 4) {
1577       outSISIDXREG(SISGR, 0x03, 0x00);  /* don't rotate, write unmodified */
1578       outSISIDXREG(SISGR, 0x08, 0xFF);  /* write all bits in a byte */
1579       outSISIDXREG(SISGR, 0x01, 0x00);  /* all planes come from CPU */
1580    }
1581
1582    outSISIDXREG(SISSR, 0x02, 0x04); /* write to plane 2 */
1583    outSISIDXREG(SISSR, 0x04, 0x06); /* enable plane graphics */
1584    outSISIDXREG(SISGR, 0x04, 0x02); /* read plane 2 */
1585    outSISIDXREG(SISGR, 0x05, 0x00); /* write mode 0, read mode 0 */
1586    outSISIDXREG(SISGR, 0x06, 0x05); /* set graphics */
1587    slowbcopy_tobus(pSiS->fonts, vgaMemBase, SIS_FONTS_SIZE);
1588
1589    outSISIDXREG(SISSR, 0x02, 0x08); /* write to plane 3 */
1590    outSISIDXREG(SISSR, 0x04, 0x06); /* enable plane graphics */
1591    outSISIDXREG(SISGR, 0x04, 0x03); /* read plane 3 */
1592    outSISIDXREG(SISGR, 0x05, 0x00); /* write mode 0, read mode 0 */
1593    outSISIDXREG(SISGR, 0x06, 0x05); /* set graphics */
1594    slowbcopy_tobus(pSiS->fonts + SIS_FONTS_SIZE, vgaMemBase, SIS_FONTS_SIZE);
1595
1596    inSISIDXREG(SISSR, 0x01, scrn);
1597    outSISIDXREG(SISSR, 0x00, 0x01);
1598    outSISIDXREG(SISSR, 0x01, scrn & ~0x20);
1599    outSISIDXREG(SISSR, 0x00, 0x03);
1600
1601    /* restore the registers that were changed */
1602    outSISREG(SISMISCW, miscOut);
1603    SiS_WriteAttr(pSiS, 0x10, attr10);
1604    outSISIDXREG(SISGR, 0x01, gr1);
1605    outSISIDXREG(SISGR, 0x03, gr3);
1606    outSISIDXREG(SISGR, 0x04, gr4);
1607    outSISIDXREG(SISGR, 0x05, gr5);
1608    outSISIDXREG(SISGR, 0x06, gr6);
1609    outSISIDXREG(SISGR, 0x08, gr8);
1610    outSISIDXREG(SISSR, 0x02, seq2);
1611    outSISIDXREG(SISSR, 0x04, seq4);
1612#endif
1613}
1614
1615static void
1616SiSVGARestoreMode(ScrnInfoPtr pScrn, SISRegPtr restore)
1617{
1618    SISPtr pSiS = SISPTR(pScrn);
1619    int i;
1620
1621    outSISREG(SISMISCW, restore->sisRegMiscOut);
1622
1623    for(i = 1; i < 5; i++) {
1624       outSISIDXREG(SISSR, i, restore->sisRegs3C4[i]);
1625    }
1626
1627    outSISIDXREG(SISCR, 17, restore->sisRegs3D4[17] & ~0x80);
1628
1629    for(i = 0; i < 25; i++) {
1630       outSISIDXREG(SISCR, i, restore->sisRegs3D4[i]);
1631    }
1632
1633    for(i = 0; i < 9; i++) {
1634       outSISIDXREG(SISGR, i, restore->sisRegsGR[i]);
1635    }
1636
1637    SiS_EnablePalette(pSiS);
1638    for(i = 0; i < 21; i++) {
1639       SiS_WriteAttr(pSiS, i, restore->sisRegsATTR[i]);
1640    }
1641    SiS_DisablePalette(pSiS);
1642}
1643
1644
1645static void
1646SiSVGARestoreColormap(ScrnInfoPtr pScrn, SISRegPtr restore)
1647{
1648    SISPtr pSiS = SISPTR(pScrn);
1649    int i;
1650
1651    if(!pSiS->VGACMapSaved) return;
1652
1653    outSISREG(SISPEL, 0xff);
1654
1655    outSISREG(SISCOLIDX, 0x00);
1656    for(i = 0; i < 768; i++) {
1657       outSISREG(SISCOLDATA, restore->sisDAC[i]);
1658       (void)inSISREG(SISINPSTAT);
1659       (void)inSISREG(SISINPSTAT);
1660    }
1661
1662    SiS_DisablePalette(pSiS);
1663}
1664
1665void
1666SiSVGARestore(ScrnInfoPtr pScrn, SISRegPtr restore, int flags)
1667{
1668    if(restore == NULL) return;
1669
1670    if(flags & SISVGA_SR_MODE)  SiSVGARestoreMode(pScrn, restore);
1671    if(flags & SISVGA_SR_FONTS) SiSVGARestoreFonts(pScrn);
1672    if(flags & SISVGA_SR_CMAP)  SiSVGARestoreColormap(pScrn, restore);
1673}
1674
1675static void
1676SiS_SeqReset(SISPtr pSiS, Bool start)
1677{
1678    if(start) {
1679       outSISIDXREG(SISSR, 0x00, 0x01);	/* Synchronous Reset */
1680    } else {
1681       outSISIDXREG(SISSR, 0x00, 0x03);	/* End Reset */
1682    }
1683}
1684
1685void
1686SiSVGAProtect(ScrnInfoPtr pScrn, Bool on)
1687{
1688    SISPtr pSiS = SISPTR(pScrn);
1689    UChar  tmp;
1690
1691    if(!pScrn->vtSema) return;
1692
1693    if(on) {
1694       inSISIDXREG(SISSR, 0x01, tmp);
1695       SiS_SeqReset(pSiS, TRUE);		/* start synchronous reset */
1696       outSISIDXREG(SISSR, 0x01, tmp | 0x20);	/* disable display */
1697       SiS_EnablePalette(pSiS);
1698    } else {
1699       andSISIDXREG(SISSR, 0x01, ~0x20);	/* enable display */
1700       SiS_SeqReset(pSiS, FALSE);		/* clear synchronous reset */
1701       SiS_DisablePalette(pSiS);
1702    }
1703}
1704
1705#ifdef SIS_PC_PLATFORM
1706Bool
1707SiSVGAMapMem(ScrnInfoPtr pScrn)
1708{
1709    SISPtr pSiS = SISPTR(pScrn);
1710
1711    /* Map only once */
1712    if(pSiS->VGAMemBase) return TRUE;
1713
1714    if(pSiS->VGAMapSize == 0) pSiS->VGAMapSize = (64 * 1024);
1715    if(pSiS->VGAMapPhys == 0) pSiS->VGAMapPhys = 0xA0000;
1716
1717#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
1718#if XSERVER_LIBPCIACCESS
1719    (void) pci_device_map_legacy(pSiS->PciInfo, pSiS->VGAMapPhys, pSiS->VGAMapSize,
1720                                 PCI_DEV_MAP_FLAG_WRITABLE, &pSiS->VGAMemBase);
1721#else
1722    pSiS->VGAMemBase = xf86MapDomainMemory(pScrn->scrnIndex, VIDMEM_MMIO_32BIT,
1723			pSiS->PciTag, pSiS->VGAMapPhys, pSiS->VGAMapSize);
1724#endif
1725#else
1726    pSiS->VGAMemBase = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO_32BIT,
1727			pSiS->VGAMapPhys, pSiS->VGAMapSize);
1728#endif
1729
1730    return(pSiS->VGAMemBase != NULL);
1731}
1732
1733void
1734SiSVGAUnmapMem(ScrnInfoPtr pScrn)
1735{
1736    SISPtr pSiS = SISPTR(pScrn);
1737
1738    if(pSiS->VGAMemBase == NULL) return;
1739
1740#if XSERVER_LIBPCIACCESS
1741    (void) pci_device_unmap_legacy(pSiS->PciInfo, pSiS->VGAMemBase, pSiS->VGAMapSize);
1742#else
1743    xf86UnMapVidMem(pScrn->scrnIndex, pSiS->VGAMemBase, pSiS->VGAMapSize);
1744#endif
1745
1746    pSiS->VGAMemBase = NULL;
1747}
1748#endif
1749
1750#if 0
1751static CARD32
1752SiS_HBlankKGA(DisplayModePtr mode, SISRegPtr regp, int nBits, unsigned int Flags)
1753{
1754    int    nExtBits = (nBits < 6) ? 0 : nBits - 6;
1755    CARD32 ExtBits;
1756    CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 6;
1757
1758    regp->sisRegs3D4[3] = (regp->sisRegs3D4[3] & ~0x1F) |
1759                          (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F);
1760    regp->sisRegs3D4[5] = (regp->sisRegs3D4[5] & ~0x80) |
1761                          ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2);
1762    ExtBits             = ((mode->CrtcHBlankEnd >> 3) - 1) & ExtBitMask;
1763
1764    if( (Flags & SISKGA_FIX_OVERSCAN) &&
1765        ((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3))) {
1766       int i = (regp->sisRegs3D4[3] & 0x1F)        |
1767	       ((regp->sisRegs3D4[5] & 0x80) >> 2) |
1768	       ExtBits;
1769       if(Flags & SISKGA_ENABLE_ON_ZERO) {
1770	  if( (i-- > (((mode->CrtcHBlankStart >> 3) - 1) & (0x3F | ExtBitMask))) &&
1771	      (mode->CrtcHBlankEnd == mode->CrtcHTotal) ) {
1772	     i = 0;
1773	  }
1774       } else if (Flags & SISKGA_BE_TOT_DEC) i--;
1775       regp->sisRegs3D4[3] = (regp->sisRegs3D4[3] & ~0x1F) | (i & 0x1F);
1776       regp->sisRegs3D4[5] = (regp->sisRegs3D4[5] & ~0x80) | ((i << 2) & 0x80);
1777       ExtBits = i & ExtBitMask;
1778    }
1779    return ExtBits >> 6;
1780}
1781#endif
1782
1783static CARD32
1784SiS_VBlankKGA(DisplayModePtr mode, SISRegPtr regp, int nBits, unsigned int Flags)
1785{
1786    CARD32 nExtBits   = (nBits < 8) ? 0 : (nBits - 8);
1787    CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 8;
1788    CARD32 ExtBits    = (mode->CrtcVBlankEnd - 1) & ExtBitMask;
1789    CARD32 BitMask    = (nBits < 7) ? 0 : ((1 << nExtBits) - 1);
1790    int VBlankStart   = (mode->CrtcVBlankStart - 1) & 0xFF;
1791    regp->sisRegs3D4[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
1792
1793    if((Flags & SISKGA_FIX_OVERSCAN) && (mode->CrtcVBlankEnd == mode->CrtcVTotal)) {
1794       int i = regp->sisRegs3D4[22] | ExtBits;
1795       if(Flags & SISKGA_ENABLE_ON_ZERO) {
1796	  if( ((BitMask && ((i & BitMask) > (VBlankStart & BitMask))) ||
1797	       ((i > VBlankStart)  &&  		            /* 8-bit case */
1798	        ((i & 0x7F) > (VBlankStart & 0x7F)))) &&    /* 7-bit case */
1799	      (!(regp->sisRegs3D4[9] & 0x9F)) ) {	    /* 1 scanline/row */
1800	     i = 0;
1801	  } else {
1802	     i--;
1803	  }
1804       } else if(Flags & SISKGA_BE_TOT_DEC) i--;
1805
1806       regp->sisRegs3D4[22] = i & 0xFF;
1807       ExtBits = i & 0xFF00;
1808    }
1809    return (ExtBits >> 8);
1810}
1811
1812Bool
1813SiSVGAInit(ScrnInfoPtr pScrn, DisplayModePtr mode, int fixsync)
1814{
1815    SISPtr pSiS = SISPTR(pScrn);
1816    SISRegPtr regp = &pSiS->ModeReg;
1817    int depth = pScrn->depth;
1818    unsigned int i;
1819
1820    /* Sync */
1821    if((mode->Flags & (V_PHSYNC | V_NHSYNC)) && (mode->Flags & (V_PVSYNC | V_NVSYNC))) {
1822        regp->sisRegMiscOut = 0x23;
1823        if(mode->Flags & V_NHSYNC) regp->sisRegMiscOut |= 0x40;
1824        if(mode->Flags & V_NVSYNC) regp->sisRegMiscOut |= 0x80;
1825    } else {
1826        int VDisplay = mode->VDisplay;
1827
1828        if(mode->Flags & V_DBLSCAN) VDisplay *= 2;
1829        if(mode->VScan > 1)         VDisplay *= mode->VScan;
1830
1831        if(VDisplay < 400)        regp->sisRegMiscOut = 0xA3;	/* +hsync -vsync */
1832        else if (VDisplay < 480)  regp->sisRegMiscOut = 0x63;	/* -hsync +vsync */
1833        else if (VDisplay < 768)  regp->sisRegMiscOut = 0xE3;	/* -hsync -vsync */
1834        else                      regp->sisRegMiscOut = 0x23;	/* +hsync +vsync */
1835    }
1836
1837    regp->sisRegMiscOut |= (mode->ClockIndex & 0x03) << 2;
1838
1839    /* Seq */
1840    if(depth == 4) regp->sisRegs3C4[0] = 0x02;
1841    else	   regp->sisRegs3C4[0] = 0x00;
1842
1843    if(mode->Flags & V_CLKDIV2) regp->sisRegs3C4[1] = 0x09;
1844    else                        regp->sisRegs3C4[1] = 0x01;
1845
1846    regp->sisRegs3C4[2] = 0x0F;
1847
1848    regp->sisRegs3C4[3] = 0x00;
1849
1850    if(depth < 8)  regp->sisRegs3C4[4] = 0x06;
1851    else           regp->sisRegs3C4[4] = 0x0E;
1852
1853    /* CRTC */
1854    regp->sisRegs3D4[0]  = (mode->CrtcHTotal >> 3) - 5;
1855    regp->sisRegs3D4[1]  = (mode->CrtcHDisplay >> 3) - 1;
1856    regp->sisRegs3D4[2]  = (mode->CrtcHBlankStart >> 3) - 1;
1857    regp->sisRegs3D4[3]  = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80;
1858    i = (((mode->CrtcHSkew << 2) + 0x10) & ~0x1F);
1859    if(i < 0x80)  regp->sisRegs3D4[3] |= i;
1860    regp->sisRegs3D4[4]  = (mode->CrtcHSyncStart >> 3) - fixsync;
1861    regp->sisRegs3D4[5]  = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) |
1862			   (((mode->CrtcHSyncEnd >> 3) - fixsync) & 0x1F);
1863    regp->sisRegs3D4[6]  = (mode->CrtcVTotal - 2) & 0xFF;
1864    regp->sisRegs3D4[7]  = (((mode->CrtcVTotal - 2) & 0x100) >> 8)           |
1865			   (((mode->CrtcVDisplay - 1) & 0x100) >> 7)         |
1866			   (((mode->CrtcVSyncStart - fixsync) & 0x100) >> 6) |
1867			   (((mode->CrtcVBlankStart - 1) & 0x100) >> 5)      |
1868			   0x10                                              |
1869			   (((mode->CrtcVTotal - 2) & 0x200)   >> 4)         |
1870			   (((mode->CrtcVDisplay - 1) & 0x200) >> 3)         |
1871			   (((mode->CrtcVSyncStart - fixsync) & 0x200) >> 2);
1872    regp->sisRegs3D4[8]  = 0x00;
1873    regp->sisRegs3D4[9]  = (((mode->CrtcVBlankStart - 1) & 0x200) >> 4) | 0x40;
1874    if(mode->Flags & V_DBLSCAN) regp->sisRegs3D4[9] |= 0x80;
1875    if(mode->VScan >= 32)     regp->sisRegs3D4[9] |= 0x1F;
1876    else if (mode->VScan > 1) regp->sisRegs3D4[9] |= mode->VScan - 1;
1877    regp->sisRegs3D4[10] = 0x00;
1878    regp->sisRegs3D4[11] = 0x00;
1879    regp->sisRegs3D4[12] = 0x00;
1880    regp->sisRegs3D4[13] = 0x00;
1881    regp->sisRegs3D4[14] = 0x00;
1882    regp->sisRegs3D4[15] = 0x00;
1883    regp->sisRegs3D4[16] = (mode->CrtcVSyncStart - fixsync) & 0xFF;
1884    regp->sisRegs3D4[17] = ((mode->CrtcVSyncEnd - fixsync) & 0x0F) | 0x20;
1885    regp->sisRegs3D4[18] = (mode->CrtcVDisplay - 1) & 0xFF;
1886    regp->sisRegs3D4[19] = pScrn->displayWidth >> 4;
1887    regp->sisRegs3D4[20] = 0x00;
1888    regp->sisRegs3D4[21] = (mode->CrtcVBlankStart - 1) & 0xFF;
1889    regp->sisRegs3D4[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
1890    if(depth < 8) regp->sisRegs3D4[23] = 0xE3;
1891    else	  regp->sisRegs3D4[23] = 0xC3;
1892    regp->sisRegs3D4[24] = 0xFF;
1893
1894#if 0
1895    SiS_HBlankKGA(mode, regp, 0, SISKGA_FIX_OVERSCAN | SISKGA_ENABLE_ON_ZERO);
1896#endif
1897    SiS_VBlankKGA(mode, regp, 0, SISKGA_FIX_OVERSCAN | SISKGA_ENABLE_ON_ZERO);
1898
1899    /* GR */
1900    regp->sisRegsGR[0] = 0x00;
1901    regp->sisRegsGR[1] = 0x00;
1902    regp->sisRegsGR[2] = 0x00;
1903    regp->sisRegsGR[3] = 0x00;
1904    regp->sisRegsGR[4] = 0x00;
1905    if(depth == 4) regp->sisRegsGR[5] = 0x02;
1906    else           regp->sisRegsGR[5] = 0x40;
1907    regp->sisRegsGR[6] = 0x05;   /* only map 64k VGA memory !!!! */
1908    regp->sisRegsGR[7] = 0x0F;
1909    regp->sisRegsGR[8] = 0xFF;
1910
1911    /* Attr */
1912    for(i = 0; i <= 15; i++) {	/* standard colormap translation */
1913       regp->sisRegsATTR[i] = i;
1914    }
1915    if(depth == 4) regp->sisRegsATTR[16] = 0x81;
1916    else           regp->sisRegsATTR[16] = 0x41;
1917    if(depth >= 4) regp->sisRegsATTR[17] = 0xFF;
1918    else           regp->sisRegsATTR[17] = 0x01;
1919    regp->sisRegsATTR[18] = 0x0F;
1920    regp->sisRegsATTR[19] = 0x00;
1921    regp->sisRegsATTR[20] = 0x00;
1922
1923    return TRUE;
1924}
1925
1926static void
1927SISVGABlankScreen(ScrnInfoPtr pScrn, Bool on)
1928{
1929    SISPtr pSiS = SISPTR(pScrn);
1930    UChar  tmp, orig;
1931
1932    inSISIDXREG(SISSR, 0x01, tmp);
1933    orig = tmp;
1934    if(on) tmp &= ~0x20;
1935    else   tmp |= 0x20;
1936    /* Only update the hardware if the state changes because the reset will
1937     * disrupt the output requiring the screen to resync.
1938     */
1939    if(orig == tmp)
1940        return;
1941    SiS_SeqReset(pSiS, TRUE);
1942    outSISIDXREG(SISSR, 0x01, tmp);
1943    SiS_SeqReset(pSiS, FALSE);
1944}
1945
1946Bool
1947SiSVGASaveScreen(ScreenPtr pScreen, int mode)
1948{
1949    ScrnInfoPtr pScrn = NULL;
1950    Bool on = xf86IsUnblank(mode);
1951
1952    if(pScreen == NULL) return FALSE;
1953
1954    pScrn = xf86ScreenToScrn(pScreen);
1955
1956    if(pScrn->vtSema) {
1957       SISVGABlankScreen(pScrn, on);
1958    }
1959    return TRUE;
1960}
1961
1962#undef SIS_FONTS_SIZE
1963
1964
1965