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