sis_vga.c revision 72b676d7
172b676d7Smrg/* $XFree86$ */
272b676d7Smrg/* $XdotOrg$ */
372b676d7Smrg/*
472b676d7Smrg * Mode setup and basic video bridge detection
572b676d7Smrg *
672b676d7Smrg * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
772b676d7Smrg *
872b676d7Smrg * The SISInit() function for old series (except TV and FIFO calculation)
972b676d7Smrg * was previously based on code which was Copyright (C) 1998,1999 by Alan
1072b676d7Smrg * Hourihane, Wigan, England. However, the code has been rewritten entirely
1172b676d7Smrg * and is - it its current representation - not covered by this old copyright.
1272b676d7Smrg *
1372b676d7Smrg * Redistribution and use in source and binary forms, with or without
1472b676d7Smrg * modification, are permitted provided that the following conditions
1572b676d7Smrg * are met:
1672b676d7Smrg * 1) Redistributions of source code must retain the above copyright
1772b676d7Smrg *    notice, this list of conditions and the following disclaimer.
1872b676d7Smrg * 2) Redistributions in binary form must reproduce the above copyright
1972b676d7Smrg *    notice, this list of conditions and the following disclaimer in the
2072b676d7Smrg *    documentation and/or other materials provided with the distribution.
2172b676d7Smrg * 3) The name of the author may not be used to endorse or promote products
2272b676d7Smrg *    derived from this software without specific prior written permission.
2372b676d7Smrg *
2472b676d7Smrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2572b676d7Smrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2672b676d7Smrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2772b676d7Smrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2872b676d7Smrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2972b676d7Smrg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3072b676d7Smrg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3172b676d7Smrg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3272b676d7Smrg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3372b676d7Smrg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3472b676d7Smrg *
3572b676d7Smrg * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
3672b676d7Smrg *
3772b676d7Smrg */
3872b676d7Smrg
3972b676d7Smrg#ifdef HAVE_CONFIG_H
4072b676d7Smrg#include "config.h"
4172b676d7Smrg#endif
4272b676d7Smrg
4372b676d7Smrg#include "sis.h"
4472b676d7Smrg#define SIS_NEED_inSISREG
4572b676d7Smrg#define SIS_NEED_outSISREG
4672b676d7Smrg#define SIS_NEED_inSISIDXREG
4772b676d7Smrg#define SIS_NEED_outSISIDXREG
4872b676d7Smrg#define SIS_NEED_orSISIDXREG
4972b676d7Smrg#define SIS_NEED_andSISIDXREG
5072b676d7Smrg#include "sis_regs.h"
5172b676d7Smrg#include "sis_dac.h"
5272b676d7Smrg
5372b676d7Smrgstatic Bool  SISInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
5472b676d7Smrgstatic Bool  SIS300Init(ScrnInfoPtr pScrn, DisplayModePtr mode);
5572b676d7Smrgstatic int   SIS6326DoSense(ScrnInfoPtr pScrn, int tempbh, int tempbl, int tempch, int tempcl);
5672b676d7Smrgstatic void  SISSense6326(ScrnInfoPtr pScrn);
5772b676d7Smrgstatic void  SiS6326TVDelay(ScrnInfoPtr pScrn, int delay);
5872b676d7Smrgextern void  SISSense30x(ScrnInfoPtr pScrn, Bool quiet);
5972b676d7Smrgextern void  SISSenseChrontel(ScrnInfoPtr pScrn, Bool quiet);
6072b676d7Smrg
6172b676d7Smrg/* Our very own vgaHW functions */
6272b676d7Smrgvoid SiSVGASave(ScrnInfoPtr pScrn, SISRegPtr save, int flags);
6372b676d7Smrgvoid SiSVGARestore(ScrnInfoPtr pScrn, SISRegPtr restore, int flags);
6472b676d7Smrgvoid SiSVGASaveFonts(ScrnInfoPtr pScrn);
6572b676d7Smrgvoid SiSVGARestoreFonts(ScrnInfoPtr pScrn);
6672b676d7Smrgvoid SISVGALock(SISPtr pSiS);
6772b676d7Smrgvoid SiSVGAUnlock(SISPtr pSiS);
6872b676d7Smrgvoid SiSVGAProtect(ScrnInfoPtr pScrn, Bool on);
6972b676d7Smrg#ifdef SIS_PC_PLATFORM
7072b676d7SmrgBool SiSVGAMapMem(ScrnInfoPtr pScrn);
7172b676d7Smrgvoid SiSVGAUnmapMem(ScrnInfoPtr pScrn);
7272b676d7Smrg#endif
7372b676d7SmrgBool SiSVGASaveScreen(ScreenPtr pScreen, int mode);
7472b676d7Smrgstatic Bool SiSVGAInit(ScrnInfoPtr pScrn, DisplayModePtr mode, int fixsync);
7572b676d7Smrg
7672b676d7Smrgconst CARD8 SiS6326TVRegs1[14] = {
7772b676d7Smrg     0x00,0x01,0x02,0x03,0x04,0x11,0x12,0x13,0x21,0x26,0x27,0x3a,0x3c,0x43
7872b676d7Smrg};
7972b676d7Smrg
8072b676d7Smrgconst CARD8 SiS6326TVRegs1_NTSC[6][14] = {
8172b676d7Smrg    {0x81,0x3f,0x49,0x1b,0xa9,0x03,0x00,0x09,0x08,0x7d,0x00,0x88,0x30,0x60},
8272b676d7Smrg    {0x81,0x3f,0x49,0x1d,0xa0,0x03,0x00,0x09,0x08,0x7d,0x00,0x88,0x30,0x60},
8372b676d7Smrg    {0x81,0x45,0x24,0x8e,0x26,0x0b,0x00,0x09,0x02,0xfe,0x00,0x09,0x51,0x60},
8472b676d7Smrg    {0x81,0x45,0x24,0x8e,0x26,0x07,0x00,0x29,0x04,0x30,0x10,0x3b,0x61,0x60},
8572b676d7Smrg    {0x81,0x3f,0x24,0x8e,0x26,0x09,0x00,0x09,0x02,0x30,0x10,0x3b,0x51,0x60},  /* 640x400, 640x480 */
8672b676d7Smrg    {0x83,0x5d,0x21,0xbe,0x75,0x03,0x00,0x09,0x08,0x42,0x10,0x4d,0x61,0x79}   /* 640x480u */
8772b676d7Smrg};
8872b676d7Smrg
8972b676d7Smrgconst CARD8 SiS6326TVRegs2_NTSC[6][54] = {
9072b676d7Smrg    {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
9172b676d7Smrg     0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
9272b676d7Smrg     0xFC, 0xDF, 0x94, 0x1F, 0x4A, 0x03, 0x71, 0x07, 0x97, 0x10, 0x40,
9372b676d7Smrg     0x48, 0x00, 0x26, 0xB6, 0x10, 0x5C, 0xEC, 0x21, 0x2E, 0xBE, 0x10,
9472b676d7Smrg     0x64, 0xF4, 0x21, 0x13, 0x75, 0x08, 0x31, 0x6A, 0x01, 0xA0},
9572b676d7Smrg    {0x11, 0x17, 0x03, 0x0A, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
9672b676d7Smrg     0x0D, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
9772b676d7Smrg     0xFF, 0xDF, 0x94, 0x1F, 0x4A, 0x03, 0x71, 0x07, 0x97, 0x10, 0x40,
9872b676d7Smrg     0x48, 0x00, 0x26, 0xB6, 0x10, 0x5C, 0xEC, 0x21, 0x2E, 0xBE, 0x10,
9972b676d7Smrg     0x64, 0xF4, 0x21, 0x13, 0x75, 0x08, 0x31, 0x6A, 0x01, 0xA0},
10072b676d7Smrg    {0x11, 0x17, 0x03, 0x0A, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
10172b676d7Smrg     0x0D, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
10272b676d7Smrg     0xFF, 0xDF, 0x94, 0x3F, 0x8C, 0x06, 0xCE, 0x07, 0x27, 0x30, 0x73,
10372b676d7Smrg     0x7B, 0x00, 0x48, 0x68, 0x30, 0xB2, 0xD2, 0x52, 0x50, 0x70, 0x30,
10472b676d7Smrg     0xBA, 0xDA, 0x52, 0xDC, 0x02, 0xD1, 0x53, 0xF7, 0x02, 0xA0},
10572b676d7Smrg    {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
10672b676d7Smrg     0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
10772b676d7Smrg     0xDC, 0xDF, 0x94, 0x3F, 0x8C, 0x06, 0xCE, 0x07, 0x27, 0x30, 0x73,
10872b676d7Smrg     0x7B, 0x00, 0x48, 0x68, 0x30, 0xB2, 0xD2, 0x52, 0x50, 0x70, 0x30,
10972b676d7Smrg     0xBA, 0xDA, 0x52, 0x00, 0x02, 0xF5, 0x53, 0xF7, 0x02, 0xA0},
11072b676d7Smrg    {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,
11172b676d7Smrg     0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
11272b676d7Smrg     0xDC, 0xDF, 0x94, 0x3F, 0x8C, 0x06, 0xCE, 0x07, 0x27, 0x30, 0x73,
11372b676d7Smrg     0x7B, 0x00, 0x48, 0x68, 0x30, 0xB2, 0xD2, 0x52, 0x50, 0x70, 0x30,
11472b676d7Smrg     0xBA, 0xDA, 0x52, 0xDC, 0x02, 0xD1, 0x53, 0xF7, 0x02, 0xA0},
11572b676d7Smrg    {0x11, 0x17, 0x03, 0x09, 0x94, 0x02, 0x05, 0x06, 0x09, 0x50, 0x0C,  /* 640x480u */
11672b676d7Smrg     0x0C, 0x06, 0x0D, 0x04, 0x0A, 0x94, 0x06, 0x0D, 0x04, 0x0A, 0x94,
11772b676d7Smrg     0xDC, 0xDF, 0x94, 0xAF, 0x95, 0x06, 0xDD, 0x07, 0x5F, 0x30, 0x7E,
11872b676d7Smrg     0x86, 0x00, 0x4C, 0xA4, 0x30, 0xE3, 0x3B, 0x62, 0x54, 0xAC, 0x30,
11972b676d7Smrg     0xEB, 0x43, 0x62, 0x48, 0x34, 0x3D, 0x63, 0x29, 0x03, 0xA0}
12072b676d7Smrg};
12172b676d7Smrg
12272b676d7Smrgconst CARD8 SiS6326TVRegs1_PAL[6][14] = {
12372b676d7Smrg    {0x81,0x2d,0xc8,0x07,0xb2,0x0b,0x00,0x09,0x02,0xed,0x00,0xf8,0x30,0x40},
12472b676d7Smrg    {0x80,0x2d,0xa4,0x03,0xd9,0x0b,0x00,0x09,0x02,0xed,0x10,0xf8,0x71,0x40},
12572b676d7Smrg    {0x81,0x2d,0xa4,0x03,0xd9,0x0b,0x00,0x09,0x02,0xed,0x10,0xf8,0x71,0x40},  /* 640x480 */
12672b676d7Smrg    {0x81,0x2d,0xa4,0x03,0xd9,0x0b,0x00,0x09,0x02,0x8f,0x10,0x9a,0x71,0x40},  /* 800x600 */
12772b676d7Smrg    {0x83,0x63,0xa1,0x7a,0xa3,0x0a,0x00,0x09,0x02,0xb5,0x11,0xc0,0x81,0x59},  /* 800x600u */
12872b676d7Smrg    {0x81,0x63,0xa4,0x03,0xd9,0x01,0x00,0x09,0x10,0x9f,0x10,0xaa,0x71,0x59}   /* 720x540  */
12972b676d7Smrg};
13072b676d7Smrg
13172b676d7Smrgconst CARD8 SiS6326TVRegs2_PAL[6][54] = {
13272b676d7Smrg    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,
13372b676d7Smrg     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
13472b676d7Smrg     0xE5, 0xDF, 0x94, 0xEF, 0x5A, 0x03, 0x7F, 0x07, 0xFF, 0x10, 0x4E,
13572b676d7Smrg     0x56, 0x00, 0x2B, 0x23, 0x20, 0xB4, 0xAC, 0x31, 0x33, 0x2B, 0x20,
13672b676d7Smrg     0xBC, 0xB4, 0x31, 0x83, 0xE1, 0x78, 0x31, 0xD6, 0x01, 0xA0},
13772b676d7Smrg    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,
13872b676d7Smrg     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
13972b676d7Smrg     0xE5, 0xDF, 0x94, 0xDF, 0xB2, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x90,
14072b676d7Smrg     0x98, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40,
14172b676d7Smrg     0x6A, 0x5A, 0x73, 0x03, 0xC1, 0xF8, 0x63, 0xB6, 0x03, 0xA0},
14272b676d7Smrg    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,  /* 640x480 */
14372b676d7Smrg     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
14472b676d7Smrg     0xE5, 0xDF, 0x94, 0xDF, 0xB2, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x90,
14572b676d7Smrg     0x98, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40,
14672b676d7Smrg     0x6A, 0x5A, 0x73, 0x03, 0xC1, 0xF8, 0x63, 0xB6, 0x03, 0xA0},
14772b676d7Smrg    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,  /* 800x600 */
14872b676d7Smrg     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
14972b676d7Smrg     0xE5, 0xDF, 0x94, 0xDF, 0xB2, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x90,
15072b676d7Smrg     0x98, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40,
15172b676d7Smrg     0x6A, 0x5A, 0x73, 0xA0, 0xC1, 0x95, 0x73, 0xB6, 0x03, 0xA0},
15272b676d7Smrg    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,  /* 800x600u */
15372b676d7Smrg     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
15472b676d7Smrg     0xE5, 0xDF, 0x94, 0x7F, 0xBD, 0x08, 0x0E, 0x07, 0x47, 0x40, 0x9D,
15572b676d7Smrg     0xA5, 0x00, 0x54, 0x94, 0x40, 0xA4, 0xE4, 0x73, 0x5C, 0x9C, 0x40,
15672b676d7Smrg     0xAC, 0xEC, 0x73, 0x0B, 0x0E, 0x00, 0x84, 0x03, 0x04, 0xA0},
15772b676d7Smrg    {0x15, 0x4E, 0x35, 0x6E, 0x94, 0x02, 0x04, 0x38, 0x3A, 0x50, 0x3D,  /* 720x540  */
15872b676d7Smrg     0x70, 0x06, 0x3E, 0x35, 0x6D, 0x94, 0x05, 0x3F, 0x36, 0x6E, 0x94,
15972b676d7Smrg     0xE5, 0xDF, 0x94, 0xDF, 0xB0, 0x07, 0xFB, 0x07, 0xF7, 0x30, 0x9D,
16072b676d7Smrg     0xA5, 0x00, 0x4F, 0x3F, 0x40, 0x62, 0x52, 0x73, 0x57, 0x47, 0x40,
16172b676d7Smrg     0x6A, 0x5A, 0x73, 0xA0, 0xC1, 0x95, 0x73, 0xB6, 0x03, 0xA0}
16272b676d7Smrg};
16372b676d7Smrg
16472b676d7Smrgconst CARD8 SiS6326CR[9][15] = {
16572b676d7Smrg     {0x79,0x63,0x64,0x1d,0x6a,0x93,0x00,0x6f,0xf0,0x58,0x8a,0x57,0x57,0x70,0x20},  /* PAL 800x600   */
16672b676d7Smrg     {0x79,0x4f,0x50,0x95,0x60,0x93,0x00,0x6f,0xba,0x14,0x86,0xdf,0xe0,0x30,0x00},  /* PAL 640x480   */
16772b676d7Smrg     {0x5f,0x4f,0x50,0x82,0x53,0x9f,0x00,0x0b,0x3e,0xe9,0x8b,0xdf,0xe7,0x04,0x00},  /* NTSC 640x480  */
16872b676d7Smrg     {0x5f,0x4f,0x50,0x82,0x53,0x9f,0x00,0x0b,0x3e,0xcb,0x8d,0x8f,0x96,0xe9,0x00},  /* NTSC 640x400  */
16972b676d7Smrg     {0x83,0x63,0x64,0x1f,0x6d,0x9b,0x00,0x6f,0xf0,0x48,0x0a,0x23,0x57,0x70,0x20},  /* PAL 800x600u  */
17072b676d7Smrg     {0x79,0x59,0x5b,0x1d,0x66,0x93,0x00,0x6f,0xf0,0x42,0x04,0x1b,0x40,0x70,0x20},  /* PAL 720x540   */
17172b676d7Smrg     {0x66,0x4f,0x51,0x0a,0x57,0x89,0x00,0x0b,0x3e,0xd9,0x0b,0xb6,0xe7,0x04,0x00},  /* NTSC 640x480u */
17272b676d7Smrg     {0xce,0x9f,0x9f,0x92,0xa4,0x16,0x00,0x28,0x5a,0x00,0x04,0xff,0xff,0x29,0x39},  /* 1280x1024-75  */
17372b676d7Smrg     {0x09,0xc7,0xc7,0x0d,0xd2,0x0a,0x01,0xe0,0x10,0xb0,0x04,0xaf,0xaf,0xe1,0x1f}   /* 1600x1200-60  */
17472b676d7Smrg};
17572b676d7Smrg
17672b676d7Smrg/* Initialize a display mode on 5597/5598, 6326 and 530/620 */
17772b676d7Smrgstatic Bool
17872b676d7SmrgSISInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
17972b676d7Smrg{
18072b676d7Smrg    SISPtr       pSiS = SISPTR(pScrn);
18172b676d7Smrg    SISRegPtr    pReg = &pSiS->ModeReg;
18272b676d7Smrg    UChar        temp;
18372b676d7Smrg    int          mclk = pSiS->MemClock;
18472b676d7Smrg    int          clock = mode->Clock;
18572b676d7Smrg    int          width = mode->HDisplay;
18672b676d7Smrg    int          height = mode->VDisplay;
18772b676d7Smrg    int          rate = (int)SiSCalcVRate(mode);
18872b676d7Smrg    int          buswidth = pSiS->BusWidth;
18972b676d7Smrg    unsigned int vclk[5];
19072b676d7Smrg    UShort       CRT_CPUthresholdLow, CRT_CPUthresholdHigh, CRT_ENGthreshold;
19172b676d7Smrg    double       a, b, c;
19272b676d7Smrg    int          d, factor, offset, fixsync = 1;
19372b676d7Smrg    int          num, denum, div, sbit, scale;
19472b676d7Smrg    Bool	 sis6326tvmode, sis6326himode;
19572b676d7Smrg
19672b676d7Smrg    /* Save the registers for further processing */
19772b676d7Smrg    (*pSiS->SiSSave)(pScrn, pReg);
19872b676d7Smrg
19972b676d7Smrg    /* Initialise the standard VGA registers */
20072b676d7Smrg    if(!pSiS->UseVESA) {
20172b676d7Smrg       if(!SiSVGAInit(pScrn, mode, fixsync)) {
20272b676d7Smrg          xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "SISInit: SiSVGAInit() failed\n");
20372b676d7Smrg          return FALSE;
20472b676d7Smrg       }
20572b676d7Smrg    }
20672b676d7Smrg
20772b676d7Smrg    /* Determine if chosen mode is suitable for TV on the 6326
20872b676d7Smrg     * and if the mode is one of our special hi-res modes.
20972b676d7Smrg     */
21072b676d7Smrg    sis6326tvmode = FALSE;
21172b676d7Smrg    sis6326himode = FALSE;
21272b676d7Smrg    if(pSiS->Chipset == PCI_CHIP_SIS6326) {
21372b676d7Smrg       if(pSiS->SiS6326Flags & SIS6326_HASTV) {
21472b676d7Smrg	  if((pSiS->SiS6326Flags & SIS6326_TVDETECTED) &&
21572b676d7Smrg	     ((strcmp(mode->name, "PAL800x600") == 0)   ||	/* Special TV modes */
21672b676d7Smrg	      (strcmp(mode->name, "PAL800x600U") == 0)  ||
21772b676d7Smrg	      (strcmp(mode->name, "PAL720x540") == 0)   ||
21872b676d7Smrg	      (strcmp(mode->name, "PAL640x480") == 0)   ||
21972b676d7Smrg	      (strcmp(mode->name, "NTSC640x480") == 0)  ||
22072b676d7Smrg	      (strcmp(mode->name, "NTSC640x480U") == 0) ||
22172b676d7Smrg	      (strcmp(mode->name, "NTSC640x400") == 0))) {
22272b676d7Smrg	     sis6326tvmode = TRUE;
22372b676d7Smrg	  } else {
22472b676d7Smrg	     pReg->sis6326tv[0x00] &= 0xfb;
22572b676d7Smrg	  }
22672b676d7Smrg       }
22772b676d7Smrg       if((strcmp(mode->name, "SIS1280x1024-75") == 0) ||	/* Special high-res modes */
22872b676d7Smrg	  (strcmp(mode->name, "SIS1600x1200-60") == 0)) {
22972b676d7Smrg	  sis6326himode = TRUE;
23072b676d7Smrg       }
23172b676d7Smrg    }
23272b676d7Smrg
23372b676d7Smrg#ifdef UNLOCK_ALWAYS
23472b676d7Smrg    outSISIDXREG(SISSR, 0x05, 0x86);
23572b676d7Smrg#endif
23672b676d7Smrg
23772b676d7Smrg    if(!pSiS->UseVESA) {
23872b676d7Smrg       pReg->sisRegs3C4[0x06] &= 0x01;
23972b676d7Smrg    }
24072b676d7Smrg
24172b676d7Smrg    /* set interlace */
24272b676d7Smrg    if(!(mode->Flags & V_INTERLACE)) {
24372b676d7Smrg       offset = pSiS->CurrentLayout.displayWidth >> 3;
24472b676d7Smrg    } else {
24572b676d7Smrg       offset = pSiS->CurrentLayout.displayWidth >> 2;
24672b676d7Smrg       if(!pSiS->UseVESA) {
24772b676d7Smrg	  pReg->sisRegs3C4[0x06] |= 0x20;
24872b676d7Smrg       }
24972b676d7Smrg    }
25072b676d7Smrg
25172b676d7Smrg    /* Enable Linear and Enhanced Gfx Mode */
25272b676d7Smrg    if(!pSiS->UseVESA) {
25372b676d7Smrg       pReg->sisRegs3C4[0x06] |= 0x82;
25472b676d7Smrg    }
25572b676d7Smrg
25672b676d7Smrg    /* Enable MMIO at PCI Register 14H (D[6:5]: 11) */
25772b676d7Smrg    if(pSiS->oldChipset >= OC_SIS5597) {
25872b676d7Smrg       pReg->sisRegs3C4[0x0B] |= 0x60;
25972b676d7Smrg    } else {
26072b676d7Smrg       pReg->sisRegs3C4[0x0B] |= 0x20;
26172b676d7Smrg       pReg->sisRegs3C4[0x0B] &= ~0x40;
26272b676d7Smrg    }
26372b676d7Smrg
26472b676d7Smrg    if(!pSiS->UseVESA) {
26572b676d7Smrg
26672b676d7Smrg       /* Enable 32bit mem access (D7), read-ahead cache (D5) */
26772b676d7Smrg       pReg->sisRegs3C4[0x0C] |= 0x80;
26872b676d7Smrg       if(pSiS->oldChipset > OC_SIS6225) {
26972b676d7Smrg	  pReg->sisRegs3C4[0x0C] |= 0x20;
27072b676d7Smrg       }
27172b676d7Smrg
27272b676d7Smrg       /* Some speed-up stuff */
27372b676d7Smrg       switch(pSiS->Chipset) {
27472b676d7Smrg       case PCI_CHIP_SIS5597:
27572b676d7Smrg	  /* enable host bus */
27672b676d7Smrg	  if(!pSiS->HostBus) {
27772b676d7Smrg	     pReg->sisRegs3C4[0x34] &= ~0x08;
27872b676d7Smrg	  } else {
27972b676d7Smrg	    pReg->sisRegs3C4[0x34] |= 0x08;
28072b676d7Smrg	  }
28172b676d7Smrg	  /* fall through */
28272b676d7Smrg       case PCI_CHIP_SIS6326:
28372b676d7Smrg       case PCI_CHIP_SIS530:
28472b676d7Smrg	  /* Enable "dual segment register mode" (D2) and "i/o gating while
28572b676d7Smrg	   * write buffer is not empty" (D3)
28672b676d7Smrg	   */
28772b676d7Smrg	  pReg->sisRegs3C4[0x0B] |= 0x0C;
28872b676d7Smrg       }
28972b676d7Smrg
29072b676d7Smrg       /* set colordepth */
29172b676d7Smrg       if(pSiS->Chipset == PCI_CHIP_SIS530) {
29272b676d7Smrg	  pReg->sisRegs3C4[0x09] &= 0x7F;
29372b676d7Smrg       }
29472b676d7Smrg       switch(pSiS->CurrentLayout.bitsPerPixel) {
29572b676d7Smrg	  case 8:
29672b676d7Smrg	     break;
29772b676d7Smrg	  case 16:
29872b676d7Smrg	     offset <<= 1;
29972b676d7Smrg	     if(pSiS->CurrentLayout.depth == 15)
30072b676d7Smrg		pReg->sisRegs3C4[0x06] |= 0x04;
30172b676d7Smrg	     else
30272b676d7Smrg		pReg->sisRegs3C4[0x06] |= 0x08;
30372b676d7Smrg	     break;
30472b676d7Smrg	  case 24:
30572b676d7Smrg	     offset += (offset << 1);
30672b676d7Smrg	     pReg->sisRegs3C4[0x06] |= 0x10;
30772b676d7Smrg	     pReg->sisRegs3C4[0x0B] |= 0x90;
30872b676d7Smrg	     break;
30972b676d7Smrg	  case 32:
31072b676d7Smrg	     if(pSiS->Chipset == PCI_CHIP_SIS530) {
31172b676d7Smrg		offset <<= 2;
31272b676d7Smrg		if(pSiS->oldChipset != OC_SIS620) {
31372b676d7Smrg		   pReg->sisRegs3C4[0x06] |= 0x10;
31472b676d7Smrg		}
31572b676d7Smrg		pReg->sisRegs3C4[0x0B] |= 0x90;
31672b676d7Smrg		pReg->sisRegs3C4[0x09] |= 0x80;
31772b676d7Smrg	     } else return FALSE;
31872b676d7Smrg	     break;
31972b676d7Smrg       }
32072b676d7Smrg    }
32172b676d7Smrg
32272b676d7Smrg    /* save screen pitch for acceleration functions */
32372b676d7Smrg    pSiS->scrnOffset = pSiS->CurrentLayout.displayWidth *
32472b676d7Smrg			((pSiS->CurrentLayout.bitsPerPixel + 7) / 8);
32572b676d7Smrg
32672b676d7Smrg    /* Set accelerator dest color depth to 0 - not supported on 530/620 */
32772b676d7Smrg    pSiS->DstColor = 0;
32872b676d7Smrg
32972b676d7Smrg    if(!pSiS->UseVESA) {
33072b676d7Smrg
33172b676d7Smrg       /* set linear framebuffer addresses */
33272b676d7Smrg       switch(pScrn->videoRam) {
33372b676d7Smrg	  case 512:  temp = 0x00;  break;
33472b676d7Smrg	  case 1024: temp = 0x20;  break;
33572b676d7Smrg	  case 2048: temp = 0x40;  break;
33672b676d7Smrg	  case 4096: temp = 0x60;  break;
33772b676d7Smrg	  case 8192: temp = 0x80;  break;
33872b676d7Smrg	  default:   temp = 0x20;
33972b676d7Smrg       }
34072b676d7Smrg       pReg->sisRegs3C4[0x20] = (pSiS->FbAddress & 0x07F80000) >> 19;
34172b676d7Smrg       pReg->sisRegs3C4[0x21] = ((pSiS->FbAddress & 0xF8000000) >> 27) | temp;
34272b676d7Smrg
34372b676d7Smrg       /* Set screen offset */
34472b676d7Smrg       pReg->sisRegs3D4[0x13] = offset & 0xFF;
34572b676d7Smrg
34672b676d7Smrg       /* Set CR registers for our built-in TV and hi-res modes */
34772b676d7Smrg       if((sis6326tvmode) || (sis6326himode)) {
34872b676d7Smrg
34972b676d7Smrg	  int index,i;
35072b676d7Smrg
35172b676d7Smrg	  /* We need our very private data for hi-res and TV modes */
35272b676d7Smrg	  if(sis6326himode) {
35372b676d7Smrg	     if(strcmp(mode->name, "SIS1280x1024-75") == 0)  index = 7;
35472b676d7Smrg	     else index = 8;
35572b676d7Smrg	  } else {
35672b676d7Smrg	     if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
35772b676d7Smrg		switch(width) {
35872b676d7Smrg		case 800:
35972b676d7Smrg		   if((strcmp(mode->name, "PAL800x600U") == 0))
36072b676d7Smrg		      index = 4;
36172b676d7Smrg		   else
36272b676d7Smrg		      index = 0;
36372b676d7Smrg		   break;
36472b676d7Smrg		case 720:
36572b676d7Smrg		   index = 5;
36672b676d7Smrg		   break;
36772b676d7Smrg		case 640:
36872b676d7Smrg		default:
36972b676d7Smrg		   index = 1;
37072b676d7Smrg		}
37172b676d7Smrg	     } else {
37272b676d7Smrg		switch(height) {
37372b676d7Smrg		case 400:
37472b676d7Smrg		   index = 3;
37572b676d7Smrg		   break;
37672b676d7Smrg		case 480:
37772b676d7Smrg		default:
37872b676d7Smrg		   if((strcmp(mode->name, "NTSC640x480U") == 0))
37972b676d7Smrg		      index = 6;
38072b676d7Smrg		   else
38172b676d7Smrg		      index = 2;
38272b676d7Smrg		}
38372b676d7Smrg	     }
38472b676d7Smrg	  }
38572b676d7Smrg	  for(i=0; i<=5; i++) {
38672b676d7Smrg	     pReg->sisRegs3D4[i] = SiS6326CR[index][i];
38772b676d7Smrg	  }
38872b676d7Smrg	  pReg->sisRegs3C4[0x12] = SiS6326CR[index][6];
38972b676d7Smrg	  pReg->sisRegs3D4[6] = SiS6326CR[index][7];
39072b676d7Smrg	  pReg->sisRegs3D4[7] = SiS6326CR[index][8];
39172b676d7Smrg	  pReg->sisRegs3D4[0x10] = SiS6326CR[index][9];
39272b676d7Smrg	  pReg->sisRegs3D4[0x11] = SiS6326CR[index][10];
39372b676d7Smrg	  pReg->sisRegs3D4[0x12] = SiS6326CR[index][11];
39472b676d7Smrg	  pReg->sisRegs3D4[0x15] = SiS6326CR[index][12];
39572b676d7Smrg	  pReg->sisRegs3D4[0x16] = SiS6326CR[index][13];
39672b676d7Smrg	  pReg->sisRegs3D4[9] &= ~0x20;
39772b676d7Smrg	  pReg->sisRegs3D4[9] |= (SiS6326CR[index][14] & 0x20);
39872b676d7Smrg	  pReg->sisRegs3C4[0x0A] = ((offset & 0xF00) >> 4) | (SiS6326CR[index][14] & 0x0f);
39972b676d7Smrg
40072b676d7Smrg       } else {
40172b676d7Smrg
40272b676d7Smrg	  /* Set extended vertical overflow register */
40372b676d7Smrg	  pReg->sisRegs3C4[0x0A] = (
40472b676d7Smrg	      ((offset                                & 0xF00) >>  4) |
40572b676d7Smrg	      (((mode->CrtcVTotal - 2)                & 0x400) >> 10) |
40672b676d7Smrg	      (((mode->CrtcVDisplay - 1)              & 0x400) >>  9) |
40772b676d7Smrg	      (((mode->CrtcVBlankStart - 1)           & 0x400) >>  8) |
40872b676d7Smrg	      (((mode->CrtcVSyncStart - fixsync)      & 0x400) >>  7));
40972b676d7Smrg
41072b676d7Smrg	  /* Set extended horizontal overflow register */
41172b676d7Smrg	  pReg->sisRegs3C4[0x12] &= 0xE0;
41272b676d7Smrg	  pReg->sisRegs3C4[0x12] |= (
41372b676d7Smrg	      ((((mode->CrtcHTotal >> 3) - 5)          & 0x100) >> 8) |
41472b676d7Smrg	      ((((mode->CrtcHDisplay >> 3) - 1)        & 0x100) >> 7) |
41572b676d7Smrg	      ((((mode->CrtcHBlankStart >> 3) - 1)     & 0x100) >> 6) |
41672b676d7Smrg	      ((((mode->CrtcHSyncStart >> 3) - fixsync)& 0x100) >> 5) |
41772b676d7Smrg	      ((((mode->CrtcHBlankEnd >> 3) - 1)       & 0x40)  >> 2));
41872b676d7Smrg       }
41972b676d7Smrg
42072b676d7Smrg       /* enable (or disable) line compare */
42172b676d7Smrg       if(mode->CrtcVDisplay >= 1024)
42272b676d7Smrg	  pReg->sisRegs3C4[0x38] |= 0x04;
42372b676d7Smrg       else
42472b676d7Smrg	  pReg->sisRegs3C4[0x38] &= 0xFB;
42572b676d7Smrg
42672b676d7Smrg       /* Enable (or disable) high speed DCLK (some 6326 and 530/620 only) */
42772b676d7Smrg       if( ( (pSiS->Chipset == PCI_CHIP_SIS6326) &&
42872b676d7Smrg	     ( (pSiS->ChipRev == 0xd0) || (pSiS->ChipRev == 0xd1) ||
42972b676d7Smrg	       (pSiS->ChipRev == 0xd2) || (pSiS->ChipRev == 0x92) ||
43072b676d7Smrg	       (pSiS->Flags & A6326REVAB) ) ) ||
43172b676d7Smrg	   (pSiS->oldChipset > OC_SIS6326) ) {
43272b676d7Smrg	 if( (pSiS->CurrentLayout.bitsPerPixel == 24) ||
43372b676d7Smrg	     (pSiS->CurrentLayout.bitsPerPixel == 32) ||
43472b676d7Smrg	     (mode->CrtcHDisplay >= 1280) )
43572b676d7Smrg	    pReg->sisRegs3C4[0x3E] |= 0x01;
43672b676d7Smrg	 else
43772b676d7Smrg	    pReg->sisRegs3C4[0x3E] &= 0xFE;
43872b676d7Smrg       }
43972b676d7Smrg
44072b676d7Smrg       /* We use the internal VCLK */
44172b676d7Smrg       pReg->sisRegs3C4[0x38] &= 0xFC;
44272b676d7Smrg
44372b676d7Smrg       /* Programmable Clock */
44472b676d7Smrg       pReg->sisRegs3C2 = inSISREG(SISMISCR) | 0x0C;
44572b676d7Smrg
44672b676d7Smrg#if 0
44772b676d7Smrg       if(pSiS->oldChipset <= OC_SIS86202) {
44872b676d7Smrg	  /* TODO: Handle SR07 for clock selection */
44972b676d7Smrg	  /* 86C201 does not even have a programmable clock... */
45072b676d7Smrg	  /* pReg->sisRegs3C4[0x07] &= 0x??; */
45172b676d7Smrg       }
45272b676d7Smrg#endif
45372b676d7Smrg
45472b676d7Smrg       /* Set VCLK */
45572b676d7Smrg       if((sis6326tvmode) || (sis6326himode)) {
45672b676d7Smrg
45772b676d7Smrg	  /* For our built-in modes, the calculation is not suitable */
45872b676d7Smrg	  if(sis6326himode) {
45972b676d7Smrg	     if((strcmp(mode->name, "SIS1280x1024-75") == 0)) {
46072b676d7Smrg		pReg->sisRegs3C4[0x2A] = 0x5d;	/* 1280x1024-75 */
46172b676d7Smrg		pReg->sisRegs3C4[0x2B] = 0xa4;
46272b676d7Smrg             } else {
46372b676d7Smrg		pReg->sisRegs3C4[0x2A] = 0x59;	/* 1600x1200-60 */
46472b676d7Smrg		pReg->sisRegs3C4[0x2B] = 0xa3;
46572b676d7Smrg	     }
46672b676d7Smrg	     pReg->sisRegs3C4[0x13] &= ~0x40;
46772b676d7Smrg	  } else {
46872b676d7Smrg             if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
46972b676d7Smrg		/* PAL: 31.500 Mhz */
47072b676d7Smrg		if((strcmp(mode->name, "PAL800x600U") == 0)) {
47172b676d7Smrg		   pReg->sisRegs3C4[0x2A] = 0x46;
47272b676d7Smrg		   pReg->sisRegs3C4[0x2B] = 0x49;
47372b676d7Smrg		} else {
47472b676d7Smrg		   pReg->sisRegs3C4[0x2A] = 0xab;
47572b676d7Smrg		   pReg->sisRegs3C4[0x2B] = 0xe9;
47672b676d7Smrg		}
47772b676d7Smrg		pReg->sisRegs3C4[0x13] &= ~0x40;
47872b676d7Smrg	     } else {
47972b676d7Smrg		/* NTSC: 27.000 Mhz */
48072b676d7Smrg		if((strcmp(mode->name, "NTSC640x480U") == 0)) {
48172b676d7Smrg		   pReg->sisRegs3C4[0x2A] = 0x5a;
48272b676d7Smrg		   pReg->sisRegs3C4[0x2B] = 0x65;
48372b676d7Smrg		} else {
48472b676d7Smrg		   pReg->sisRegs3C4[0x2A] = 0x29;
48572b676d7Smrg		   pReg->sisRegs3C4[0x2B] = 0xe2;
48672b676d7Smrg		}
48772b676d7Smrg		pReg->sisRegs3C4[0x13] |= 0x40;
48872b676d7Smrg	     }
48972b676d7Smrg	  }
49072b676d7Smrg
49172b676d7Smrg       } else if(SiS_compute_vclk(clock, &num, &denum, &div, &sbit, &scale)) {
49272b676d7Smrg
49372b676d7Smrg	  pReg->sisRegs3C4[0x2A] = (num - 1) & 0x7f ;
49472b676d7Smrg	  pReg->sisRegs3C4[0x2A] |= (div == 2) ? 0x80 : 0;
49572b676d7Smrg	  pReg->sisRegs3C4[0x2B] = ((denum - 1) & 0x1f);
49672b676d7Smrg	  pReg->sisRegs3C4[0x2B] |= (((scale -1) & 3) << 5);
49772b676d7Smrg
49872b676d7Smrg	  /* When setting VCLK, we should set SR13 first */
49972b676d7Smrg	  if(sbit)
50072b676d7Smrg	     pReg->sisRegs3C4[0x13] |= 0x40;
50172b676d7Smrg	  else
50272b676d7Smrg	     pReg->sisRegs3C4[0x13] &= 0xBF;
50372b676d7Smrg
50472b676d7Smrg#ifdef TWDEBUG
50572b676d7Smrg	  xf86DrvMsg(0, X_INFO, "2a: %x 2b: %x 13: %x clock %d\n",
50672b676d7Smrg		pReg->sisRegs3C4[0x2A], pReg->sisRegs3C4[0x2B], pReg->sisRegs3C4[0x13], clock);
50772b676d7Smrg#endif
50872b676d7Smrg
50972b676d7Smrg       } else {
51072b676d7Smrg
51172b676d7Smrg	  /* if SiS_compute_vclk cannot handle the requested clock, try sisCalcClock */
51272b676d7Smrg	  SiSCalcClock(pScrn, clock, 2, vclk);
51372b676d7Smrg
51472b676d7Smrg#define Midx    0
51572b676d7Smrg#define Nidx    1
51672b676d7Smrg#define VLDidx  2
51772b676d7Smrg#define Pidx    3
51872b676d7Smrg#define PSNidx  4
51972b676d7Smrg
52072b676d7Smrg	  pReg->sisRegs3C4[0x2A] = (vclk[Midx] - 1) & 0x7f;
52172b676d7Smrg	  pReg->sisRegs3C4[0x2A] |= ((vclk[VLDidx] == 2) ? 1 : 0) << 7;
52272b676d7Smrg
52372b676d7Smrg	  /* D[4:0]: denumerator */
52472b676d7Smrg	  pReg->sisRegs3C4[0x2B] = (vclk[Nidx] - 1) & 0x1f;
52572b676d7Smrg
52672b676d7Smrg	  if(vclk[Pidx] <= 4){
52772b676d7Smrg	     /* postscale 1,2,3,4 */
52872b676d7Smrg	     pReg->sisRegs3C4[0x2B] |= (vclk[Pidx] - 1) << 5;
52972b676d7Smrg	     pReg->sisRegs3C4[0x13] &= 0xBF;
53072b676d7Smrg	  } else {
53172b676d7Smrg	     /* postscale 6,8 */
53272b676d7Smrg	     pReg->sisRegs3C4[0x2B] |= ((vclk[Pidx] / 2) - 1) << 5;
53372b676d7Smrg	     pReg->sisRegs3C4[0x13] |= 0x40;
53472b676d7Smrg	  }
53572b676d7Smrg	  pReg->sisRegs3C4[0x2B] |= 0x80 ;   /* gain for high frequency */
53672b676d7Smrg
53772b676d7Smrg       }
53872b676d7Smrg
53972b676d7Smrg       /* High speed DAC */
54072b676d7Smrg       if(clock > 135000)
54172b676d7Smrg	  pReg->sisRegs3C4[0x07] |= 0x02;
54272b676d7Smrg
54372b676d7Smrg       if(pSiS->oldChipset > OC_SIS6225) {
54472b676d7Smrg	  /* 1 or 2 cycle DRAM (set by option FastVram) */
54572b676d7Smrg	  if(pSiS->newFastVram == -1) {
54672b676d7Smrg	     if(pSiS->oldChipset == OC_SIS620) {
54772b676d7Smrg		/* Use different default on the 620 */
54872b676d7Smrg		pReg->sisRegs3C4[0x34] |= 0x40;
54972b676d7Smrg		pReg->sisRegs3C4[0x34] &= ~0x80;
55072b676d7Smrg	     } else {
55172b676d7Smrg		pReg->sisRegs3C4[0x34] |= 0x80;
55272b676d7Smrg		pReg->sisRegs3C4[0x34] &= ~0x40;
55372b676d7Smrg	     }
55472b676d7Smrg	  } else if(pSiS->newFastVram == 1)
55572b676d7Smrg	     pReg->sisRegs3C4[0x34] |= 0xC0;
55672b676d7Smrg	  else
55772b676d7Smrg	     pReg->sisRegs3C4[0x34] &= ~0xC0;
55872b676d7Smrg
55972b676d7Smrg	  if(pSiS->oldChipset == OC_SIS620) {
56072b676d7Smrg	     /* Enable SGRAM burst timing (= bit clear) on the 620 */
56172b676d7Smrg	     if(pSiS->Flags & SYNCDRAM) {
56272b676d7Smrg		pReg->sisRegs3C4[0x35] &= ~0x20;
56372b676d7Smrg	     } else {
56472b676d7Smrg		pReg->sisRegs3C4[0x35] |= 0x20;
56572b676d7Smrg	     }
56672b676d7Smrg	  }
56772b676d7Smrg       }
56872b676d7Smrg
56972b676d7Smrg    } /* VESA */
57072b676d7Smrg
57172b676d7Smrg    /* Logical line length */
57272b676d7Smrg    pSiS->ValidWidth = TRUE;
57372b676d7Smrg    pReg->sisRegs3C4[0x27] &= 0xCF;
57472b676d7Smrg    if(pSiS->CurrentLayout.bitsPerPixel == 24) {
57572b676d7Smrg       /* "Invalid logical width" */
57672b676d7Smrg       pReg->sisRegs3C4[0x27] |= 0x30;
57772b676d7Smrg       pSiS->ValidWidth = FALSE;
57872b676d7Smrg    } else {
57972b676d7Smrg       switch(pScrn->virtualX * (pSiS->CurrentLayout.bitsPerPixel >> 3)) {
58072b676d7Smrg	 case 1024:
58172b676d7Smrg		pReg->sisRegs3C4[0x27] |= 0x00;
58272b676d7Smrg		break;
58372b676d7Smrg	 case 2048:
58472b676d7Smrg		pReg->sisRegs3C4[0x27] |= 0x10;
58572b676d7Smrg		break;
58672b676d7Smrg	 case 4096:
58772b676d7Smrg		pReg->sisRegs3C4[0x27] |= 0x20;
58872b676d7Smrg		break;
58972b676d7Smrg	 default:
59072b676d7Smrg		/* Invalid logical width */
59172b676d7Smrg		pReg->sisRegs3C4[0x27] |= 0x30;
59272b676d7Smrg		pSiS->ValidWidth = FALSE;
59372b676d7Smrg		break;
59472b676d7Smrg       }
59572b676d7Smrg    }
59672b676d7Smrg
59772b676d7Smrg    /* Acceleration stuff */
59872b676d7Smrg    if(!pSiS->NoAccel) {
59972b676d7Smrg       pReg->sisRegs3C4[0x27] |= 0x40;   /* Enable engine programming registers */
60072b676d7Smrg       if( (pSiS->TurboQueue) &&	 /* Handle TurboQueue */
60172b676d7Smrg	   (pSiS->oldChipset > OC_SIS6225) &&
60272b676d7Smrg	   ( (pSiS->Chipset != PCI_CHIP_SIS530) ||
60372b676d7Smrg	     (pSiS->CurrentLayout.bitsPerPixel != 24) ) ) {
60472b676d7Smrg	  pReg->sisRegs3C4[0x27] |= 0x80;        /* Enable TQ */
60572b676d7Smrg	  if((pSiS->Chipset == PCI_CHIP_SIS530) ||
60672b676d7Smrg	     ((pSiS->Chipset == PCI_CHIP_SIS6326 &&
60772b676d7Smrg	      (pSiS->ChipRev == 0xd0 || pSiS->ChipRev == 0xd1 ||
60872b676d7Smrg	       pSiS->ChipRev == 0xd2 || pSiS->ChipRev == 0x92 ||
60972b676d7Smrg	       pSiS->ChipRev == 0x0a || pSiS->ChipRev == 0x1a ||
61072b676d7Smrg	       pSiS->ChipRev == 0x2a || pSiS->ChipRev == 0x0b ||
61172b676d7Smrg	       pSiS->ChipRev == 0x1b || pSiS->ChipRev == 0x2b) ) ) ) {
61272b676d7Smrg	     /* pReg->sisRegs3C4[0x3D] |= 0x80;  */     /* Queue is 62K (530/620 specs) */
61372b676d7Smrg	     pReg->sisRegs3C4[0x3D] &= 0x7F;         /* Queue is 30K (530/620 specs) */
61472b676d7Smrg	  }
61572b676d7Smrg	  /* Locate the TQ at the beginning of the last 64K block of
61672b676d7Smrg	   * video RAM. The address is to be specified in 32K steps.
61772b676d7Smrg	   */
61872b676d7Smrg	  pReg->sisRegs3C4[0x2C] = (pScrn->videoRam - 64) / 32;
61972b676d7Smrg	  if(pSiS->Chipset != PCI_CHIP_SIS530) {	/* 530/620: Reserved (don't touch) */
62072b676d7Smrg	     pReg->sisRegs3C4[0x3C] &= 0xFC; 		/* 6326: Queue is all for 2D */
62172b676d7Smrg	  }						/* 5597: Must be 0           */
62272b676d7Smrg       } else {
62372b676d7Smrg	  pReg->sisRegs3C4[0x27] &= 0x7F;
62472b676d7Smrg       }
62572b676d7Smrg    }
62672b676d7Smrg
62772b676d7Smrg
62872b676d7Smrg    if(!pSiS->UseVESA) {
62972b676d7Smrg
63072b676d7Smrg       /* No idea what this does. The Windows driver does it, so we do it as well */
63172b676d7Smrg       if(pSiS->Chipset == PCI_CHIP_SIS6326) {
63272b676d7Smrg	  if((pSiS->ChipRev == 0xd0) || (pSiS->ChipRev == 0xd1) ||
63372b676d7Smrg	     (pSiS->ChipRev == 0xd2) || (pSiS->ChipRev == 0x92) ||
63472b676d7Smrg	     (pSiS->Flags & A6326REVAB)) {
63572b676d7Smrg	     if((pSiS->Flags & (SYNCDRAM | RAMFLAG)) == (SYNCDRAM | RAMFLAG)) {
63672b676d7Smrg	        if(!(pReg->sisRegs3C4[0x0E] & 0x03)) {
63772b676d7Smrg	           pReg->sisRegs3C4[0x3E] |= 0x02;
63872b676d7Smrg	        }
63972b676d7Smrg	     }
64072b676d7Smrg	  }
64172b676d7Smrg       }
64272b676d7Smrg
64372b676d7Smrg       /* Set memclock */
64472b676d7Smrg#if 0
64572b676d7Smrg       /* We don't need to do this; the SetMClk option was not used since 4.0. */
64672b676d7Smrg       if((pSiS->Chipset == PCI_CHIP_SIS5597) || (pSiS->Chipset == PCI_CHIP_SIS6326)) {
64772b676d7Smrg          if(pSiS->MemClock > 66000) {
64872b676d7Smrg             SiSCalcClock(pScrn, pSiS->MemClock, 1, vclk);
64972b676d7Smrg
65072b676d7Smrg             pReg->sisRegs3C4[0x28] = (vclk[Midx] - 1) & 0x7f ;
65172b676d7Smrg             pReg->sisRegs3C4[0x28] |= ((vclk[VLDidx] == 2 ) ? 1 : 0 ) << 7 ;
65272b676d7Smrg             pReg->sisRegs3C4[0x29] = (vclk[Nidx] -1) & 0x1f ;   /* bits [4:0] contain denumerator -MC */
65372b676d7Smrg             if(vclk[Pidx] <= 4) {
65472b676d7Smrg                pReg->sisRegs3C4[0x29] |= (vclk[Pidx] - 1) << 5 ; /* postscale 1,2,3,4 */
65572b676d7Smrg                pReg->sisRegs3C4[0x13] &= 0x7F;
65672b676d7Smrg             } else {
65772b676d7Smrg                pReg->sisRegs3C4[0x29] |= ((vclk[Pidx] / 2) - 1) << 5 ;  /* postscale 6,8 */
65872b676d7Smrg                pReg->sisRegs3C4[0x13] |= 0x80;
65972b676d7Smrg             }
66072b676d7Smrg             /* Check programmed memory clock. Enable only to check the above code */
66172b676d7Smrg/*
66272b676d7Smrg             mclk = 14318 * ((pReg->sisRegs3C4[0x28] & 0x7f) + 1);
66372b676d7Smrg             mclk /= ((pReg->sisRegs3C4[0x29] & 0x0f) + 1);
66472b676d7Smrg             if(!(pReg->sisRegs3C4[0x13] & 0x80)) {
66572b676d7Smrg                mclk /= (((pReg->sisRegs3C4[0x29] & 0x60) >> 5) + 1);
66672b676d7Smrg             } else {
66772b676d7Smrg                if((pReg->sisRegs3C4[0x29] & 0x60) == 0x40) mclk /= 6;
66872b676d7Smrg                if((pReg->sisRegs3C4[0x29] & 0x60) == 0x60) mclk /= 8;
66972b676d7Smrg             }
67072b676d7Smrg             xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO,2,
67172b676d7Smrg                 "Setting memory clock to %.3f MHz\n",
67272b676d7Smrg                 mclk/1000.0);
67372b676d7Smrg*/
67472b676d7Smrg          }
67572b676d7Smrg       }
67672b676d7Smrg#endif
67772b676d7Smrg
67872b676d7Smrg       /* Set threshold values */
67972b676d7Smrg       /*
68072b676d7Smrg        * CPU/CRT Threshold:                     FIFO
68172b676d7Smrg        *                           MCLK     ___________      VCLK
68272b676d7Smrg        * cpu/engine <---o       o--------->|___________| -----------> CRT
68372b676d7Smrg        *                ^       ^            ^       ^
68472b676d7Smrg        *                 \     /             |       |
68572b676d7Smrg        *                  \   /              |< gap >|
68672b676d7Smrg        *                   \ /               |       |
68772b676d7Smrg        *           selector switch   Thrsh. low     high
68872b676d7Smrg        *
68972b676d7Smrg        * CRT consumes the data in the FIFO during scanline display. When the
69072b676d7Smrg        * amount of data in the FIFO reaches the Threshold low value, the selector
69172b676d7Smrg        * switch will switch to the right, and the FIFO will be refilled with data.
69272b676d7Smrg        * When the amount of data in the FIFO reaches the Threshold high value, the
69372b676d7Smrg        * selector switch will switch to the left and allows the CPU and the chip
69472b676d7Smrg        * engines to access the video RAM.
69572b676d7Smrg        *
69672b676d7Smrg        * The Threshold low values should be increased at higher bpps, simply because
69772b676d7Smrg        * there is more data needed for the CRT. When Threshold low and high are very
69872b676d7Smrg        * close to each other, the selector switch will be activated more often, which
69972b676d7Smrg        * decreases performance.
70072b676d7Smrg        *
70172b676d7Smrg        */
70272b676d7Smrg       switch(pSiS->Chipset) {
70372b676d7Smrg       case PCI_CHIP_SIS5597:  factor = 65; break;
70472b676d7Smrg       case PCI_CHIP_SIS6326:  factor = 30; break;
70572b676d7Smrg       case PCI_CHIP_SIS530:   factor = (pSiS->Flags & UMA) ? 60 : 30; break;
70672b676d7Smrg       default:                factor = (pScrn->videoRam > 1024) ? 24 : 12;
70772b676d7Smrg       }
70872b676d7Smrg       a = width * height * rate * 1.40 * factor * ((pSiS->CurrentLayout.bitsPerPixel + 1) / 8);
70972b676d7Smrg       b = (mclk / 1000) * 999488.0 * (buswidth / 8);
71072b676d7Smrg       c = ((a / b) + 1.0) / 2;
71172b676d7Smrg       d = (int)c + 2;
71272b676d7Smrg
71372b676d7Smrg       CRT_CPUthresholdLow = d;
71472b676d7Smrg       if((pSiS->Flags & (RAMFLAG | SYNCDRAM)) == (RAMFLAG | SYNCDRAM)) {
71572b676d7Smrg          CRT_CPUthresholdLow += 2;
71672b676d7Smrg       }
71772b676d7Smrg       CRT_CPUthresholdHigh = CRT_CPUthresholdLow + 3;
71872b676d7Smrg
71972b676d7Smrg       CRT_ENGthreshold = 0x0F;
72072b676d7Smrg
72172b676d7Smrg#if 0  /* See comment in sis_dac.c on why this is commented */
72272b676d7Smrg       if(pSiS->Chipset == PCI_CHIP_SIS530) {
72372b676d7Smrg	  if((pSiS->oldChipset == OC_SIS530A) &&
72472b676d7Smrg	     (pSiS->Flags & UMA) &&
72572b676d7Smrg	     (mclk == 100000) &&
72672b676d7Smrg	     (pSiS->Flags & ESS137xPRESENT)) {
72772b676d7Smrg	       if(!(pSiS->Flags & SECRETFLAG)) index = 0;
72872b676d7Smrg	       if((temp = SiS_CalcSpecial530Threshold(pSiS, mode, index)) {
72972b676d7Smrg		   CRT_CPUthresholdLow = temp;
73072b676d7Smrg		   break;
73172b676d7Smrg	       }
73272b676d7Smrg	  }
73372b676d7Smrg       }
73472b676d7Smrg#endif
73572b676d7Smrg
73672b676d7Smrg       switch(pSiS->Chipset) {
73772b676d7Smrg       case PCI_CHIP_SIS530:
73872b676d7Smrg	  if(CRT_CPUthresholdLow > 0x1f)  CRT_CPUthresholdLow = 0x1f;
73972b676d7Smrg	  CRT_CPUthresholdHigh = 0x1f;
74072b676d7Smrg	  break;
74172b676d7Smrg       case PCI_CHIP_SIS5597:
74272b676d7Smrg       case PCI_CHIP_SIS6326:
74372b676d7Smrg       default:
74472b676d7Smrg	  if(CRT_CPUthresholdLow > 0x0f)  CRT_CPUthresholdLow  = 0x0f;
74572b676d7Smrg	  if(CRT_CPUthresholdHigh > 0x0f) CRT_CPUthresholdHigh = 0x0f;
74672b676d7Smrg       }
74772b676d7Smrg
74872b676d7Smrg       pReg->sisRegs3C4[0x08] = ((CRT_CPUthresholdLow & 0x0F) << 4) |
74972b676d7Smrg				(CRT_ENGthreshold & 0x0F);
75072b676d7Smrg
75172b676d7Smrg       pReg->sisRegs3C4[0x09] &= 0xF0;
75272b676d7Smrg       pReg->sisRegs3C4[0x09] |= (CRT_CPUthresholdHigh & 0x0F);
75372b676d7Smrg
75472b676d7Smrg       pReg->sisRegs3C4[0x3F] &= 0xEB;
75572b676d7Smrg       pReg->sisRegs3C4[0x3F] |= ((CRT_CPUthresholdHigh & 0x10) |
75672b676d7Smrg				  ((CRT_CPUthresholdLow & 0x10) >> 2));
75772b676d7Smrg
75872b676d7Smrg       if(pSiS->oldChipset >= OC_SIS530A) {
75972b676d7Smrg	  pReg->sisRegs3C4[0x3F] &= 0xDF;
76072b676d7Smrg	  pReg->sisRegs3C4[0x3F] |= 0x58;
76172b676d7Smrg       }
76272b676d7Smrg
76372b676d7Smrg       /* Set SiS6326 TV registers */
76472b676d7Smrg       if((pSiS->Chipset == PCI_CHIP_SIS6326) && (sis6326tvmode)) {
76572b676d7Smrg	  UChar tmp;
76672b676d7Smrg	  int index=0, i, j, k;
76772b676d7Smrg	  int fsc;
76872b676d7Smrg
76972b676d7Smrg	  if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
77072b676d7Smrg	     pReg->sisRegs3C4[0x0D] |= 0x04;
77172b676d7Smrg	     switch(width) {
77272b676d7Smrg	     case 800:
77372b676d7Smrg	        if((strcmp(mode->name, "PAL800x600U") == 0))  index = 4;
77472b676d7Smrg	        else	        			      index = 3;
77572b676d7Smrg	        break;
77672b676d7Smrg	     case 720: index = 5;  break;
77772b676d7Smrg	     case 640:
77872b676d7Smrg	     default:  index = 2;
77972b676d7Smrg	     }
78072b676d7Smrg	     for(i=0; i<14; i++) {
78172b676d7Smrg	        pReg->sis6326tv[SiS6326TVRegs1[i]] = SiS6326TVRegs1_PAL[index][i];
78272b676d7Smrg	     }
78372b676d7Smrg	     fsc = (SiS6326TVRegs1_PAL[index][2] << 16) |
78472b676d7Smrg		   (SiS6326TVRegs1_PAL[index][3] << 8)  |
78572b676d7Smrg		   (SiS6326TVRegs1_PAL[index][4]);
78672b676d7Smrg	  } else {
78772b676d7Smrg	     pReg->sisRegs3C4[0x0D] &= ~0x04;
78872b676d7Smrg	     if((strcmp(mode->name, "NTSC640x480U") == 0))  index = 5;
78972b676d7Smrg	     else 					    index = 4;
79072b676d7Smrg	     for(i=0; i<14; i++) {
79172b676d7Smrg	        pReg->sis6326tv[SiS6326TVRegs1[i]] = SiS6326TVRegs1_NTSC[index][i];
79272b676d7Smrg	     }
79372b676d7Smrg	     fsc = (SiS6326TVRegs1_NTSC[index][2] << 16) |
79472b676d7Smrg	           (SiS6326TVRegs1_NTSC[index][3] << 8)  |
79572b676d7Smrg	           (SiS6326TVRegs1_NTSC[index][4]);
79672b676d7Smrg	  }
79772b676d7Smrg	  if(pSiS->sis6326fscadjust) {
79872b676d7Smrg	     fsc += pSiS->sis6326fscadjust;
79972b676d7Smrg	     pReg->sis6326tv[2] = (fsc >> 16) & 0xff;
80072b676d7Smrg	     pReg->sis6326tv[3] = (fsc >> 8) & 0xff;
80172b676d7Smrg	     pReg->sis6326tv[4] = fsc & 0xff;
80272b676d7Smrg	  }
80372b676d7Smrg	  tmp = pReg->sis6326tv[0x43];
80472b676d7Smrg	  if(pSiS->SiS6326Flags & SIS6326_TVCVBS) tmp |= 0x10;
80572b676d7Smrg	  tmp |= 0x08;
80672b676d7Smrg	  pReg->sis6326tv[0x43] = tmp;
80772b676d7Smrg	  j = 0; k = 0;
80872b676d7Smrg	  for(i=0; i<=0x44; i++) {
80972b676d7Smrg	     if(SiS6326TVRegs1[j] == i) {
81072b676d7Smrg		j++;
81172b676d7Smrg		continue;
81272b676d7Smrg	     }
81372b676d7Smrg	     if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
81472b676d7Smrg		tmp = SiS6326TVRegs2_PAL[index][k];
81572b676d7Smrg	     } else {
81672b676d7Smrg		tmp = SiS6326TVRegs2_NTSC[index][k];
81772b676d7Smrg	     }
81872b676d7Smrg	     pReg->sis6326tv[i] = tmp;
81972b676d7Smrg	     k++;
82072b676d7Smrg	  }
82172b676d7Smrg	  pReg->sis6326tv[0x43] |= 0x08;
82272b676d7Smrg	  if((pSiS->ChipRev == 0xc1) || (pSiS->ChipRev == 0xc2)) {
82372b676d7Smrg	     pReg->sis6326tv[0x43] &= ~0x08;
82472b676d7Smrg	  }
82572b676d7Smrg
82672b676d7Smrg	  tmp = pReg->sis6326tv[0];
82772b676d7Smrg	  tmp |= 0x18;
82872b676d7Smrg	  if(pSiS->SiS6326Flags & SIS6326_TVCVBS)   tmp &= ~0x10;
82972b676d7Smrg	  if(pSiS->SiS6326Flags & SIS6326_TVSVIDEO) tmp &= ~0x08;
83072b676d7Smrg	  tmp |= 0x04;
83172b676d7Smrg	  pReg->sis6326tv[0] = tmp;
83272b676d7Smrg       }
83372b676d7Smrg
83472b676d7Smrg    } /* VESA */
83572b676d7Smrg
83672b676d7Smrg    return TRUE;
83772b676d7Smrg}
83872b676d7Smrg
83972b676d7Smrg/* Init a mode for SiS 300, 315, 330, 340 series
84072b676d7Smrg * This function is now only used for setting up some
84172b676d7Smrg * variables (eg. scrnOffset).
84272b676d7Smrg */
84372b676d7SmrgBool
84472b676d7SmrgSIS300Init(ScrnInfoPtr pScrn, DisplayModePtr mode)
84572b676d7Smrg{
84672b676d7Smrg    SISPtr    pSiS = SISPTR(pScrn);
84772b676d7Smrg    SISRegPtr pReg = &pSiS->ModeReg;
84872b676d7Smrg    UShort    temp;
84972b676d7Smrg    DisplayModePtr realmode = mode;
85072b676d7Smrg
85172b676d7Smrg    PDEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4, "SIS300Init()\n"));
85272b676d7Smrg
85372b676d7Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
85472b676d7Smrg	"virtualX = %d depth = %d Logical width = %d\n",
85572b676d7Smrg	pScrn->virtualX, pSiS->CurrentLayout.bitsPerPixel,
85672b676d7Smrg	pScrn->virtualX * pSiS->CurrentLayout.bitsPerPixel/8);
85772b676d7Smrg
85872b676d7Smrg#ifdef SISMERGED
85972b676d7Smrg    if(pSiS->MergedFB) {
86072b676d7Smrg       realmode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
86172b676d7Smrg    }
86272b676d7Smrg#endif
86372b676d7Smrg
86472b676d7Smrg    /* Copy current register settings to structure */
86572b676d7Smrg    (*pSiS->SiSSave)(pScrn, pReg);
86672b676d7Smrg
86772b676d7Smrg    /* Calculate Offset/Display Pitch */
86872b676d7Smrg    pSiS->scrnOffset = pSiS->CurrentLayout.displayWidth *
86972b676d7Smrg                          ((pSiS->CurrentLayout.bitsPerPixel + 7) / 8);
87072b676d7Smrg
87172b676d7Smrg    pSiS->scrnPitch = pSiS->scrnPitch2 = pSiS->scrnOffset;
87272b676d7Smrg    if(!(pSiS->VBFlags & CRT1_LCDA)) {
87372b676d7Smrg       if(realmode->Flags & V_INTERLACE) pSiS->scrnPitch <<= 1;
87472b676d7Smrg    }
87572b676d7Smrg    /* CRT2 mode can never be interlaced */
87672b676d7Smrg
87772b676d7Smrg#ifdef UNLOCK_ALWAYS
87872b676d7Smrg    outSISIDXREG(SISSR, 0x05, 0x86);
87972b676d7Smrg#endif
88072b676d7Smrg
88172b676d7Smrg    switch(pSiS->CurrentLayout.bitsPerPixel) {
88272b676d7Smrg	case 8:
88372b676d7Smrg	    pSiS->DstColor = 0x0000;
88472b676d7Smrg	    pSiS->SiS310_AccelDepth = 0x00000000;
88572b676d7Smrg	    break;
88672b676d7Smrg	case 16:
88772b676d7Smrg	    if(pSiS->CurrentLayout.depth == 15)
88872b676d7Smrg	        pSiS->DstColor = (short) 0x4000;
88972b676d7Smrg	    else
89072b676d7Smrg	        pSiS->DstColor = (short) 0x8000;
89172b676d7Smrg	    pSiS->SiS310_AccelDepth = 0x00010000;
89272b676d7Smrg	    break;
89372b676d7Smrg	case 32:
89472b676d7Smrg	    pSiS->DstColor = (short) 0xC000;
89572b676d7Smrg	    pSiS->SiS310_AccelDepth = 0x00020000;
89672b676d7Smrg	    break;
89772b676d7Smrg    }
89872b676d7Smrg
89972b676d7Smrg    /* Enable PCI LINEAR ADDRESSING (0x80), MMIO (0x01), PCI_IO (0x20) */
90072b676d7Smrg    pReg->sisRegs3C4[0x20] = 0xA1;
90172b676d7Smrg
90272b676d7Smrg    /* Now initialize TurboQueue. TB is always located at the very top of
90372b676d7Smrg     * the videoRAM (notably NOT the x framebuffer memory, which can/should
90472b676d7Smrg     * be limited by MaxXFbMem when using DRI). Also, enable the accelerators.
90572b676d7Smrg     */
90672b676d7Smrg    if(!pSiS->NoAccel) {
90772b676d7Smrg	pReg->sisRegs3C4[0x1E] |= 0x42;  /* Enable 2D accelerator */
90872b676d7Smrg	pReg->sisRegs3C4[0x1E] |= 0x18;  /* Enable 3D accelerator */
90972b676d7Smrg	switch(pSiS->VGAEngine) {
91072b676d7Smrg	case SIS_300_VGA:
91172b676d7Smrg	  if(pSiS->TurboQueue) {    		/* set Turbo Queue as 512k */
91272b676d7Smrg	    temp = ((pScrn->videoRam/64)-8);    /* 8=512k, 4=256k, 2=128k, 1=64k */
91372b676d7Smrg	    pReg->sisRegs3C4[0x26] = temp & 0xFF;
91472b676d7Smrg	    pReg->sisRegs3C4[0x27] =
91572b676d7Smrg		(pReg->sisRegs3C4[0x27] & 0xfc) | (((temp >> 8) & 3) | 0xF0);
91672b676d7Smrg	  }	/* line above new for saving D2&3 of status register */
91772b676d7Smrg	  break;
91872b676d7Smrg	case SIS_315_VGA:
91972b676d7Smrg#ifndef SISVRAMQ
92072b676d7Smrg	  /* See comments in sis_driver.c */
92172b676d7Smrg	  pReg->sisRegs3C4[0x27] = 0x1F;
92272b676d7Smrg	  pReg->sisRegs3C4[0x26] = 0x22;
92372b676d7Smrg	  pReg->sisMMIO85C0 = (pScrn->videoRam - 512) * 1024;
92472b676d7Smrg#endif
92572b676d7Smrg	  break;
92672b676d7Smrg	}
92772b676d7Smrg    }
92872b676d7Smrg
92972b676d7Smrg    return TRUE;
93072b676d7Smrg}
93172b676d7Smrg
93272b676d7Smrgstatic void
93372b676d7SmrgSiS6326TVDelay(ScrnInfoPtr pScrn, int delay)
93472b676d7Smrg{
93572b676d7Smrg    SISPtr  pSiS = SISPTR(pScrn);
93672b676d7Smrg    int i;
93772b676d7Smrg    UChar temp;
93872b676d7Smrg
93972b676d7Smrg    for(i=0; i<delay; i++) {
94072b676d7Smrg       inSISIDXREG(SISSR, 0x05, temp);
94172b676d7Smrg    }
94272b676d7Smrg    (void)temp;
94372b676d7Smrg}
94472b676d7Smrg
94572b676d7Smrgstatic int
94672b676d7SmrgSIS6326DoSense(ScrnInfoPtr pScrn, int tempbh, int tempbl, int tempch, int tempcl)
94772b676d7Smrg{
94872b676d7Smrg    UChar temp;
94972b676d7Smrg
95072b676d7Smrg    SiS6326SetTVReg(pScrn, 0x42, tempbl);
95172b676d7Smrg    temp = SiS6326GetTVReg(pScrn, 0x43);
95272b676d7Smrg    temp &= 0xfc;
95372b676d7Smrg    temp |= tempbh;
95472b676d7Smrg    SiS6326SetTVReg(pScrn, 0x43, temp);
95572b676d7Smrg    SiS6326TVDelay(pScrn, 0x1000);
95672b676d7Smrg    temp = SiS6326GetTVReg(pScrn, 0x43);
95772b676d7Smrg    temp |= 0x04;
95872b676d7Smrg    SiS6326SetTVReg(pScrn, 0x43, temp);
95972b676d7Smrg    SiS6326TVDelay(pScrn, 0x8000);
96072b676d7Smrg    temp = SiS6326GetTVReg(pScrn, 0x44);
96172b676d7Smrg    if(!(tempch & temp)) tempcl = 0;
96272b676d7Smrg    return tempcl;
96372b676d7Smrg}
96472b676d7Smrg
96572b676d7Smrgstatic void
96672b676d7SmrgSISSense6326(ScrnInfoPtr pScrn)
96772b676d7Smrg{
96872b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
96972b676d7Smrg    UChar  temp;
97072b676d7Smrg    int    result;
97172b676d7Smrg
97272b676d7Smrg    pSiS->SiS6326Flags &= (SIS6326_HASTV | SIS6326_TVPAL);
97372b676d7Smrg    temp = SiS6326GetTVReg(pScrn, 0x43);
97472b676d7Smrg    temp &= 0xfb;
97572b676d7Smrg    SiS6326SetTVReg(pScrn, 0x43, temp);
97672b676d7Smrg    result = SIS6326DoSense(pScrn, 0x01, 0xb0, 0x06, SIS6326_TVSVIDEO);  /* 0x02 */
97772b676d7Smrg    pSiS->SiS6326Flags |= result;
97872b676d7Smrg    result = SIS6326DoSense(pScrn, 0x01, 0xa0, 0x01, SIS6326_TVCVBS);    /* 0x04 */
97972b676d7Smrg    pSiS->SiS6326Flags |= result;
98072b676d7Smrg    temp = SiS6326GetTVReg(pScrn, 0x43);
98172b676d7Smrg    temp &= 0xfb;
98272b676d7Smrg    SiS6326SetTVReg(pScrn, 0x43, temp);
98372b676d7Smrg    if(pSiS->SiS6326Flags & (SIS6326_TVSVIDEO | SIS6326_TVCVBS)) {
98472b676d7Smrg       pSiS->SiS6326Flags |= SIS6326_TVDETECTED;
98572b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
98672b676d7Smrg	    "SiS6326: Detected TV connected to %s output\n",
98772b676d7Smrg		(((pSiS->SiS6326Flags & (SIS6326_TVSVIDEO | SIS6326_TVCVBS)) ==
98872b676d7Smrg		   (SIS6326_TVSVIDEO | SIS6326_TVCVBS)) ?
98972b676d7Smrg			"both SVIDEO and COMPOSITE" :
99072b676d7Smrg			   ((pSiS->SiS6326Flags & SIS6326_TVSVIDEO) ?
99172b676d7Smrg				"SVIDEO" : "COMPOSITE")));
99272b676d7Smrg    } else {
99372b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
99472b676d7Smrg	    "SiS6326: No TV detected\n");
99572b676d7Smrg    }
99672b676d7Smrg}
99772b676d7Smrg
99872b676d7Smrgstatic Bool
99972b676d7SmrgSISIsUMC(SISPtr pSiS)
100072b676d7Smrg{
100172b676d7Smrg    UShort p4_0f, p4_25, p4_27, temp;
100272b676d7Smrg
100372b676d7Smrg    inSISIDXREG(SISPART4, 0x0f, p4_0f);
100472b676d7Smrg    inSISIDXREG(SISPART4, 0x25, p4_25);
100572b676d7Smrg    inSISIDXREG(SISPART4, 0x27, p4_27);
100672b676d7Smrg    andSISIDXREG(SISPART4, 0x0f, 0x7f);
100772b676d7Smrg    orSISIDXREG(SISPART4, 0x25, 0x08);
100872b676d7Smrg    andSISIDXREG(SISPART4, 0x27, 0xfd);
100972b676d7Smrg    inSISIDXREG(SISPART4, 0x26, temp);
101072b676d7Smrg    outSISIDXREG(SISPART4, 0x27, p4_27);
101172b676d7Smrg    outSISIDXREG(SISPART4, 0x25, p4_25);
101272b676d7Smrg    outSISIDXREG(SISPART4, 0x0f, p4_0f);
101372b676d7Smrg    return((temp & 0x08) ? TRUE : FALSE);
101472b676d7Smrg}
101572b676d7Smrg
101672b676d7Smrg/* Detect video bridge and set VBFlags accordingly */
101772b676d7Smrgvoid SISVGAPreInit(ScrnInfoPtr pScrn)
101872b676d7Smrg{
101972b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
102072b676d7Smrg    int    temp,temp1,temp2,sistypeidx;
102172b676d7Smrg    int    upperlimitlvds, lowerlimitlvds;
102272b676d7Smrg    int    upperlimitch, lowerlimitch;
102372b676d7Smrg    int    chronteltype, chrontelidreg, upperlimitvb;
102472b676d7Smrg    static const char *detectvb = "Detected SiS%s video bridge (%s, ID %d; Rev 0x%x)\n";
102572b676d7Smrg#if 0
102672b676d7Smrg    UChar sr17=0;
102772b676d7Smrg#endif
102872b676d7Smrg    static const char *ChrontelTypeStr[] = {
102972b676d7Smrg	"7004",
103072b676d7Smrg	"7005",
103172b676d7Smrg	"7007",
103272b676d7Smrg	"7006",
103372b676d7Smrg	"7008",
103472b676d7Smrg	"7013",
103572b676d7Smrg	"7019",
103672b676d7Smrg	"7020",
103772b676d7Smrg	"(unknown)"
103872b676d7Smrg    };
103972b676d7Smrg    static const char *SiSVBTypeStr[] = {
104072b676d7Smrg	"301",		/* 0 */
104172b676d7Smrg	"301B",		/* 1 */
104272b676d7Smrg	"301B-DH",	/* 2 */
104372b676d7Smrg	"301LV",	/* 3 */
104472b676d7Smrg	"302LV",	/* 4 */
104572b676d7Smrg	"301C",		/* 5 */
104672b676d7Smrg	"302ELV",	/* 6 */
104772b676d7Smrg	"302B"		/* 7 */
104872b676d7Smrg    };
104972b676d7Smrg
105072b676d7Smrg    switch(pSiS->Chipset) {
105172b676d7Smrg       case PCI_CHIP_SIS300:
105272b676d7Smrg       case PCI_CHIP_SIS540:
105372b676d7Smrg       case PCI_CHIP_SIS630:
105472b676d7Smrg       case PCI_CHIP_SIS550:
105572b676d7Smrg       case PCI_CHIP_SIS315:
105672b676d7Smrg       case PCI_CHIP_SIS315H:
105772b676d7Smrg       case PCI_CHIP_SIS315PRO:
105872b676d7Smrg       case PCI_CHIP_SIS650:
105972b676d7Smrg       case PCI_CHIP_SIS330:
106072b676d7Smrg       case PCI_CHIP_SIS660:
106172b676d7Smrg       case PCI_CHIP_SIS340:
106272b676d7Smrg       case PCI_CHIP_XGIXG20:
106372b676d7Smrg       case PCI_CHIP_XGIXG40:
106472b676d7Smrg          pSiS->ModeInit = SIS300Init;
106572b676d7Smrg          break;
106672b676d7Smrg       default:
106772b676d7Smrg          pSiS->ModeInit = SISInit;
106872b676d7Smrg    }
106972b676d7Smrg
107072b676d7Smrg    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
107172b676d7Smrg       UChar sr0d;
107272b676d7Smrg       inSISIDXREG(SISSR, 0x0d, sr0d);
107372b676d7Smrg       if(sr0d & 0x04) {
107472b676d7Smrg	  pSiS->SiS6326Flags |= SIS6326_TVPAL;
107572b676d7Smrg       }
107672b676d7Smrg       SISSense6326(pScrn);
107772b676d7Smrg    }
107872b676d7Smrg
107972b676d7Smrg    pSiS->VBFlags = pSiS->VBFlags2 = 0; /* reset VBFlags */
108072b676d7Smrg    pSiS->SiS_Pr->SiS_UseLCDA = FALSE;
108172b676d7Smrg    pSiS->SiS_Pr->Backup = FALSE;
108272b676d7Smrg
108372b676d7Smrg    /* Videobridges only available for 300/315/330/340 series */
108472b676d7Smrg    if((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA))
108572b676d7Smrg       return;
108672b676d7Smrg
108772b676d7Smrg    /* No video bridge ever on XGI Z7 (XG20) */
108872b676d7Smrg    if(pSiS->ChipType == XGI_20)
108972b676d7Smrg       return;
109072b676d7Smrg
109172b676d7Smrg    inSISIDXREG(SISPART4, 0x00, temp);
109272b676d7Smrg    temp &= 0x0F;
109372b676d7Smrg    if(temp == 1) {
109472b676d7Smrg
109572b676d7Smrg        inSISIDXREG(SISPART4, 0x01, temp1);
109672b676d7Smrg	temp1 &= 0xff;
109772b676d7Smrg
109872b676d7Smrg	if(temp1 >= 0xC0) {
109972b676d7Smrg	   if(SISIsUMC(pSiS)) pSiS->VBFlags2 |= VB2_SISUMC;
110072b676d7Smrg	}
110172b676d7Smrg
110272b676d7Smrg        if(temp1 >= 0xE0) {
110372b676d7Smrg		inSISIDXREG(SISPART4, 0x39, temp2);
110472b676d7Smrg		if(temp2 == 0xff) {
110572b676d7Smrg		   pSiS->VBFlags2 |= VB2_302LV;
110672b676d7Smrg		   sistypeidx = 4;
110772b676d7Smrg		} else {
110872b676d7Smrg		   pSiS->VBFlags2 |= VB2_301C;	/* VB_302ELV; */
110972b676d7Smrg		   sistypeidx = 5; 		/* 6; */
111072b676d7Smrg		}
111172b676d7Smrg	} else if(temp1 >= 0xD0) {
111272b676d7Smrg		pSiS->VBFlags2 |= VB2_301LV;
111372b676d7Smrg		sistypeidx = 3;
111472b676d7Smrg	} else if(temp1 >= 0xC0) {
111572b676d7Smrg		pSiS->VBFlags2 |= VB2_301C;
111672b676d7Smrg		sistypeidx = 5;
111772b676d7Smrg	} else if(temp1 >= 0xB0) {
111872b676d7Smrg		pSiS->VBFlags2 |= VB2_301B;
111972b676d7Smrg		sistypeidx = 1;
112072b676d7Smrg		inSISIDXREG(SISPART4, 0x23, temp2);
112172b676d7Smrg		if(!(temp2 & 0x02)) {
112272b676d7Smrg		   pSiS->VBFlags2 |= VB2_30xBDH;
112372b676d7Smrg		   sistypeidx = 2;
112472b676d7Smrg		}
112572b676d7Smrg	} else {
112672b676d7Smrg		pSiS->VBFlags2 |= VB2_301;
112772b676d7Smrg		sistypeidx = 0;
112872b676d7Smrg	}
112972b676d7Smrg
113072b676d7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, detectvb, SiSVBTypeStr[sistypeidx],
113172b676d7Smrg				(pSiS->VBFlags2 & VB2_SISUMC) ? "UMC-0" : "Charter/UMC-1", 1, temp1);
113272b676d7Smrg
113372b676d7Smrg	SISSense30x(pScrn, FALSE);
113472b676d7Smrg
113572b676d7Smrg    } else if(temp == 2) {
113672b676d7Smrg
113772b676d7Smrg	inSISIDXREG(SISPART4, 0x01, temp1);
113872b676d7Smrg	temp1 &= 0xff;
113972b676d7Smrg
114072b676d7Smrg	if(temp1 >= 0xC0) {
114172b676d7Smrg	   if(SISIsUMC(pSiS)) pSiS->VBFlags2 |= VB2_SISUMC;
114272b676d7Smrg	}
114372b676d7Smrg
114472b676d7Smrg	if(temp1 >= 0xE0) {
114572b676d7Smrg		pSiS->VBFlags2 |= VB2_302LV;
114672b676d7Smrg		sistypeidx = 4;
114772b676d7Smrg	} else if(temp1 >= 0xD0) {
114872b676d7Smrg		pSiS->VBFlags2 |= VB2_301LV;
114972b676d7Smrg		sistypeidx = 3;
115072b676d7Smrg	} else {
115172b676d7Smrg		pSiS->VBFlags2 |= VB2_302B;
115272b676d7Smrg		sistypeidx = 7;
115372b676d7Smrg	}
115472b676d7Smrg
115572b676d7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, detectvb, SiSVBTypeStr[sistypeidx],
115672b676d7Smrg				(pSiS->VBFlags2 & VB2_SISUMC) ? "UMC-0" : "Charter/UMC-1", 2, temp1);
115772b676d7Smrg
115872b676d7Smrg	SISSense30x(pScrn, FALSE);
115972b676d7Smrg
116072b676d7Smrg    } else if (temp == 3) {
116172b676d7Smrg
116272b676d7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, detectvb, "303", "unsupported, unknown", temp, 0);
116372b676d7Smrg
116472b676d7Smrg    } else {
116572b676d7Smrg
116672b676d7Smrg	if(pSiS->NewCRLayout) {
116772b676d7Smrg	   inSISIDXREG(SISCR, 0x38, temp);
116872b676d7Smrg	   temp = (temp >> 5) & 0x07;
116972b676d7Smrg	} else {
117072b676d7Smrg	   inSISIDXREG(SISCR, 0x37, temp);
117172b676d7Smrg	   temp = (temp >> 1) & 0x07;
117272b676d7Smrg	}
117372b676d7Smrg	if(pSiS->VGAEngine == SIS_300_VGA) {
117472b676d7Smrg	   lowerlimitlvds = 2; upperlimitlvds = 4;
117572b676d7Smrg	   lowerlimitch   = 4; upperlimitch   = 5;
117672b676d7Smrg	   chronteltype = 1;   chrontelidreg  = 0x25;
117772b676d7Smrg	   upperlimitvb = upperlimitlvds;
117872b676d7Smrg	} else {
117972b676d7Smrg	   lowerlimitlvds = 2; upperlimitlvds = 3;
118072b676d7Smrg	   lowerlimitch   = 3; upperlimitch   = 3;
118172b676d7Smrg	   chronteltype = 2;   chrontelidreg  = 0x4b;
118272b676d7Smrg	   upperlimitvb = upperlimitlvds;
118372b676d7Smrg	   if(pSiS->NewCRLayout) {
118472b676d7Smrg	      upperlimitvb = 4;
118572b676d7Smrg	   }
118672b676d7Smrg	}
118772b676d7Smrg
118872b676d7Smrg	if((temp >= lowerlimitlvds) && (temp <= upperlimitlvds)) {
118972b676d7Smrg	   pSiS->VBFlags2 |= VB2_LVDS;
119072b676d7Smrg	   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
119172b676d7Smrg	          "Detected LVDS transmitter (External chip ID %d)\n", temp);
119272b676d7Smrg	}
119372b676d7Smrg	if((temp >= lowerlimitch) && (temp <= upperlimitch))  {
119472b676d7Smrg	   /* Set global for init301.c */
119572b676d7Smrg	   pSiS->SiS_Pr->SiS_IF_DEF_CH70xx = chronteltype;
119672b676d7Smrg
119772b676d7Smrg	   if(chronteltype == 1) {
119872b676d7Smrg	      /* Set general purpose IO for Chrontel communication */
119972b676d7Smrg	      SiS_SetChrontelGPIO(pSiS->SiS_Pr, 0x9c);
120072b676d7Smrg	   }
120172b676d7Smrg
120272b676d7Smrg	   /* Read Chrontel version number */
120372b676d7Smrg	   temp1 = SiS_GetCH70xx(pSiS->SiS_Pr, chrontelidreg);
120472b676d7Smrg	   if(chronteltype == 1) {
120572b676d7Smrg	      /* See Chrontel TB31 for explanation */
120672b676d7Smrg	      temp2 = SiS_GetCH700x(pSiS->SiS_Pr, 0x0e);
120772b676d7Smrg	      if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
120872b676d7Smrg		 SiS_SetCH700x(pSiS->SiS_Pr, 0x0e, 0x0b);
120972b676d7Smrg		 SiS_DDC2Delay(pSiS->SiS_Pr, 300);
121072b676d7Smrg	      }
121172b676d7Smrg	      temp2 = SiS_GetCH70xx(pSiS->SiS_Pr, chrontelidreg);
121272b676d7Smrg	      if(temp2 != temp1) temp1 = temp2;
121372b676d7Smrg	   }
121472b676d7Smrg	   if(temp1 == 0xFFFF) {	/* 0xFFFF = error reading DDC port */
121572b676d7Smrg	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
121672b676d7Smrg			"Detected Chrontel 70xx, but encountered error reading I2C port\n");
121772b676d7Smrg	      andSISIDXREG(SISCR, 0x32, ~0x07);
121872b676d7Smrg	      pSiS->postVBCR32 &= ~0x07;
121972b676d7Smrg	   } else if((temp1 >= 0x19) && (temp1 <= 200)) {
122072b676d7Smrg	      /* We only support device ids 0x19-200; other values may indicate DDC problems */
122172b676d7Smrg	      pSiS->VBFlags2 |= VB2_CHRONTEL;
122272b676d7Smrg	      switch (temp1) {
122372b676d7Smrg		case 0x32: temp2 = 0; pSiS->ChrontelType = CHRONTEL_700x; break;
122472b676d7Smrg		case 0x3A: temp2 = 1; pSiS->ChrontelType = CHRONTEL_700x; break;
122572b676d7Smrg		case 0x50: temp2 = 2; pSiS->ChrontelType = CHRONTEL_700x; break;
122672b676d7Smrg		case 0x2A: temp2 = 3; pSiS->ChrontelType = CHRONTEL_700x; break;
122772b676d7Smrg		case 0x40: temp2 = 4; pSiS->ChrontelType = CHRONTEL_700x; break;
122872b676d7Smrg		case 0x22: temp2 = 5; pSiS->ChrontelType = CHRONTEL_700x; break;
122972b676d7Smrg	        case 0x19: temp2 = 6; pSiS->ChrontelType = CHRONTEL_701x; break;
123072b676d7Smrg	        case 0x20: temp2 = 7; pSiS->ChrontelType = CHRONTEL_701x; break;  /* ID for 7020? */
123172b676d7Smrg		default:   temp2 = 8; pSiS->ChrontelType = CHRONTEL_701x; break;
123272b676d7Smrg	      }
123372b676d7Smrg	      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
123472b676d7Smrg			"Detected Chrontel %s TV encoder (ID 0x%02x; chip ID %d)\n",
123572b676d7Smrg					ChrontelTypeStr[temp2], temp1, temp);
123672b676d7Smrg
123772b676d7Smrg	      /* Sense connected TV's */
123872b676d7Smrg	      SISSenseChrontel(pScrn, FALSE);
123972b676d7Smrg
124072b676d7Smrg	   } else if(temp1 == 0) {
124172b676d7Smrg	      /* This indicates a communication problem, but it only occures if there
124272b676d7Smrg	       * is no TV attached. So we don't use TV in this case.
124372b676d7Smrg	       */
124472b676d7Smrg	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
124572b676d7Smrg			"Detected Chrontel TV encoder in promiscuous state (DDC/I2C mix-up)\n");
124672b676d7Smrg	      andSISIDXREG(SISCR, 0x32, ~0x07);
124772b676d7Smrg	      pSiS->postVBCR32 &= ~0x07;
124872b676d7Smrg	   } else {
124972b676d7Smrg	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
125072b676d7Smrg			"Chrontel: Unsupported device id (%d) detected\n",temp1);
125172b676d7Smrg	      andSISIDXREG(SISCR, 0x32, ~0x07);
125272b676d7Smrg	      pSiS->postVBCR32 &= ~0x07;
125372b676d7Smrg	   }
125472b676d7Smrg	   if(chronteltype == 1) {
125572b676d7Smrg	      /* Set general purpose IO for Chrontel communication */
125672b676d7Smrg	      SiS_SetChrontelGPIO(pSiS->SiS_Pr, 0x00);
125772b676d7Smrg	   }
125872b676d7Smrg	}
125972b676d7Smrg	if((pSiS->NewCRLayout) && (temp == 4)) {
126072b676d7Smrg	   pSiS->VBFlags2 |= VB2_CONEXANT;
126172b676d7Smrg	   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
126272b676d7Smrg	               "Detected Conexant video bridge - UNSUPPORTED\n");
126372b676d7Smrg	}
126472b676d7Smrg	if((pSiS->VGAEngine == SIS_300_VGA) && (temp == 3)) {
126572b676d7Smrg	    pSiS->VBFlags2 |= VB2_TRUMPION;
126672b676d7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
126772b676d7Smrg	               "Detected Trumpion Zurac (I/II/III) LVDS scaler\n");
126872b676d7Smrg	}
126972b676d7Smrg	if(temp > upperlimitvb) {
127072b676d7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
127172b676d7Smrg	               "Detected unknown bridge type (%d)\n", temp);
127272b676d7Smrg	}
127372b676d7Smrg    }
127472b676d7Smrg
127572b676d7Smrg   /* Old BIOSes store the detected CRT2 type in SR17, 16 and 13
127672b676d7Smrg    * instead of CR32. However, since our detection routines
127772b676d7Smrg    * store their results to CR32, we now copy the
127872b676d7Smrg    * remaining bits (for LCD and VGA) to CR32 for unified usage.
127972b676d7Smrg    * SR17[0] CRT1     [1] LCD       [2] TV    [3] VGA2
128072b676d7Smrg    *     [4] AVIDEO   [5] SVIDEO
128172b676d7Smrg    * SR13[0] SCART    [1] HiVision
128272b676d7Smrg    * SR16[5] PAL/NTSC [6] LCD-SCALE [7] OVERSCAN
128372b676d7Smrg    */
128472b676d7Smrg
128572b676d7Smrg#if 0
128672b676d7Smrg    inSISIDXREG(SISSR, 0x17, sr17);
128772b676d7Smrg    if( (pSiS->VGAEngine == SIS_300_VGA) &&
128872b676d7Smrg        (pSiS->Chipset != PCI_CHIP_SIS300) &&
128972b676d7Smrg        (sr17 & 0x0F) ) {
129072b676d7Smrg
129172b676d7Smrg	UChar cr32;
129272b676d7Smrg	inSISIDXREG(SISCR, 0x32, cr32);
129372b676d7Smrg
129472b676d7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
129572b676d7Smrg		"Converting SR17 (%02x) to CR32 (%02x)\n", sr17, cr32);
129672b676d7Smrg
129772b676d7Smrg	 if(sr17 & 0x01) {  	/* CRT1 */
129872b676d7Smrg		orSISIDXREG(SISCR, 0x32, 0x20);
129972b676d7Smrg		pSiS->postVBCR32 |= 0x20;
130072b676d7Smrg	 } else {
130172b676d7Smrg		andSISIDXREG(SISCR, 0x32, ~0x20);
130272b676d7Smrg		pSiS->postVBCR32 &= ~0x20;
130372b676d7Smrg	 }
130472b676d7Smrg
130572b676d7Smrg	 if(sr17 & 0x02) {	/* LCD */
130672b676d7Smrg		orSISIDXREG(SISCR, 0x32, 0x08);
130772b676d7Smrg		pSiS->postVBCR32 |= 0x08;
130872b676d7Smrg	 } else	{
130972b676d7Smrg		andSISIDXREG(SISCR, 0x32, ~0x08);
131072b676d7Smrg		pSiS->postVBCR32 &= ~0x08;
131172b676d7Smrg	 }
131272b676d7Smrg
131372b676d7Smrg	 /* No Hivision, no DVI here */
131472b676d7Smrg	 andSISIDXREG(SISCR,0x32,~0xc0);
131572b676d7Smrg	 pSiS->postVBCR32 &= ~0xc0;
131672b676d7Smrg    }
131772b676d7Smrg#endif
131872b676d7Smrg
131972b676d7Smrg    /* Try to find out if the bridge uses LCDA for low resolution and
132072b676d7Smrg     * text modes. If sisfb saved this for us, use it. Otherwise,
132172b676d7Smrg     * check if we are running on a low mode on LCD and read the
132272b676d7Smrg     * relevant registers ourselves.
132372b676d7Smrg     */
132472b676d7Smrg    if(pSiS->VGAEngine == SIS_315_VGA) {
132572b676d7Smrg
132672b676d7Smrg       if(pSiS->VBFlags2 & VB2_SISLCDABRIDGE) {
132772b676d7Smrg          if(pSiS->sisfblcda != 0xff) {
132872b676d7Smrg	     if((pSiS->sisfblcda & 0x03) == 0x03) {
132972b676d7Smrg		pSiS->SiS_Pr->SiS_UseLCDA = TRUE;
133072b676d7Smrg		pSiS->ChipFlags |= SiSCF_UseLCDA;
133172b676d7Smrg	     }
133272b676d7Smrg	  } else {
133372b676d7Smrg             inSISIDXREG(SISCR,0x34,temp);
133472b676d7Smrg	     if(temp <= 0x13) {
133572b676d7Smrg		inSISIDXREG(SISCR,0x38,temp);
133672b676d7Smrg		if((temp & 0x03) == 0x03) {
133772b676d7Smrg		   pSiS->SiS_Pr->SiS_UseLCDA = TRUE;
133872b676d7Smrg		   pSiS->ChipFlags |= SiSCF_UseLCDA;
133972b676d7Smrg		   pSiS->SiS_Pr->Backup = TRUE;
134072b676d7Smrg		} else {
134172b676d7Smrg		   orSISIDXREG(SISPART1,0x2f,0x01);  /* Unlock CRT2 */
134272b676d7Smrg		   inSISIDXREG(SISPART1,0x13,temp);
134372b676d7Smrg		   if(temp & 0x04) {
134472b676d7Smrg		      pSiS->SiS_Pr->SiS_UseLCDA = TRUE;
134572b676d7Smrg		      pSiS->ChipFlags |= SiSCF_UseLCDA;
134672b676d7Smrg		      pSiS->SiS_Pr->Backup = TRUE;
134772b676d7Smrg		   }
134872b676d7Smrg		}
134972b676d7Smrg	     }
135072b676d7Smrg	  }
135172b676d7Smrg	  if(pSiS->ChipFlags & SiSCF_UseLCDA) {
135272b676d7Smrg	     xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 3,
135372b676d7Smrg		"BIOS uses LCDA for low resolution and text modes\n");
135472b676d7Smrg	     if(pSiS->SiS_Pr->Backup == TRUE) {
135572b676d7Smrg		inSISIDXREG(SISCR,0x34,pSiS->SiS_Pr->Backup_Mode);
135672b676d7Smrg		inSISIDXREG(SISPART1,0x14,pSiS->SiS_Pr->Backup_14);
135772b676d7Smrg		inSISIDXREG(SISPART1,0x15,pSiS->SiS_Pr->Backup_15);
135872b676d7Smrg		inSISIDXREG(SISPART1,0x16,pSiS->SiS_Pr->Backup_16);
135972b676d7Smrg		inSISIDXREG(SISPART1,0x17,pSiS->SiS_Pr->Backup_17);
136072b676d7Smrg		inSISIDXREG(SISPART1,0x18,pSiS->SiS_Pr->Backup_18);
136172b676d7Smrg		inSISIDXREG(SISPART1,0x19,pSiS->SiS_Pr->Backup_19);
136272b676d7Smrg		inSISIDXREG(SISPART1,0x1a,pSiS->SiS_Pr->Backup_1a);
136372b676d7Smrg		inSISIDXREG(SISPART1,0x1b,pSiS->SiS_Pr->Backup_1b);
136472b676d7Smrg		inSISIDXREG(SISPART1,0x1c,pSiS->SiS_Pr->Backup_1c);
136572b676d7Smrg		inSISIDXREG(SISPART1,0x1d,pSiS->SiS_Pr->Backup_1d);
136672b676d7Smrg	     }
136772b676d7Smrg	  }
136872b676d7Smrg       }
136972b676d7Smrg    }
137072b676d7Smrg}
137172b676d7Smrg
137272b676d7Smrgstatic void
137372b676d7SmrgSiS_WriteAttr(SISPtr pSiS, int index, int value)
137472b676d7Smrg{
137572b676d7Smrg    (void)inSISREG(SISINPSTAT);
137672b676d7Smrg    index |= 0x20;
137772b676d7Smrg    outSISREG(SISAR, index);
137872b676d7Smrg    outSISREG(SISAR, value);
137972b676d7Smrg}
138072b676d7Smrg
138172b676d7Smrgstatic int
138272b676d7SmrgSiS_ReadAttr(SISPtr pSiS, int index)
138372b676d7Smrg{
138472b676d7Smrg    (void)inSISREG(SISINPSTAT);
138572b676d7Smrg    index |= 0x20;
138672b676d7Smrg    outSISREG(SISAR, index);
138772b676d7Smrg    return(inSISREG(SISARR));
138872b676d7Smrg}
138972b676d7Smrg
139072b676d7Smrgstatic void
139172b676d7SmrgSiS_EnablePalette(SISPtr pSiS)
139272b676d7Smrg{
139372b676d7Smrg    (void)inSISREG(SISINPSTAT);
139472b676d7Smrg    outSISREG(SISAR, 0x00);
139572b676d7Smrg    pSiS->VGAPaletteEnabled = TRUE;
139672b676d7Smrg}
139772b676d7Smrg
139872b676d7Smrgstatic void
139972b676d7SmrgSiS_DisablePalette(SISPtr pSiS)
140072b676d7Smrg{
140172b676d7Smrg    (void)inSISREG(SISINPSTAT);
140272b676d7Smrg    outSISREG(SISAR, 0x20);
140372b676d7Smrg    pSiS->VGAPaletteEnabled = FALSE;
140472b676d7Smrg}
140572b676d7Smrg
140672b676d7Smrgvoid
140772b676d7SmrgSISVGALock(SISPtr pSiS)
140872b676d7Smrg{
140972b676d7Smrg    orSISIDXREG(SISCR, 0x11, 0x80);  	/* Protect CRTC[0-7] */
141072b676d7Smrg}
141172b676d7Smrg
141272b676d7Smrgvoid
141372b676d7SmrgSiSVGAUnlock(SISPtr pSiS)
141472b676d7Smrg{
141572b676d7Smrg    andSISIDXREG(SISCR, 0x11, 0x7f);	/* Unprotect CRTC[0-7] */
141672b676d7Smrg}
141772b676d7Smrg
141872b676d7Smrg#define SIS_FONTS_SIZE (8 * 8192)
141972b676d7Smrg
142072b676d7Smrgvoid
142172b676d7SmrgSiSVGASaveFonts(ScrnInfoPtr pScrn)
142272b676d7Smrg{
142372b676d7Smrg#ifdef SIS_PC_PLATFORM
142472b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
142572b676d7Smrg    pointer vgaMemBase = pSiS->VGAMemBase;
142672b676d7Smrg    UChar miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn;
142772b676d7Smrg
142872b676d7Smrg    if((pSiS->fonts) || (vgaMemBase == NULL)) return;
142972b676d7Smrg
143072b676d7Smrg    /* If in graphics mode, don't save anything */
143172b676d7Smrg    attr10 = SiS_ReadAttr(pSiS, 0x10);
143272b676d7Smrg    if(attr10 & 0x01) return;
143372b676d7Smrg
143472b676d7Smrg    if(!(pSiS->fonts = xalloc(SIS_FONTS_SIZE * 2))) {
143572b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
143672b676d7Smrg		"Could not save console fonts, mem allocation failed\n");
143772b676d7Smrg       return;
143872b676d7Smrg    }
143972b676d7Smrg
144072b676d7Smrg    /* save the registers that are needed here */
144172b676d7Smrg    miscOut = inSISREG(SISMISCR);
144272b676d7Smrg    inSISIDXREG(SISGR, 0x04, gr4);
144372b676d7Smrg    inSISIDXREG(SISGR, 0x05, gr5);
144472b676d7Smrg    inSISIDXREG(SISGR, 0x06, gr6);
144572b676d7Smrg    inSISIDXREG(SISSR, 0x02, seq2);
144672b676d7Smrg    inSISIDXREG(SISSR, 0x04, seq4);
144772b676d7Smrg
144872b676d7Smrg    /* Force into color mode */
144972b676d7Smrg    outSISREG(SISMISCW, miscOut | 0x01);
145072b676d7Smrg
145172b676d7Smrg    inSISIDXREG(SISSR, 0x01, scrn);
145272b676d7Smrg    outSISIDXREG(SISSR, 0x00, 0x01);
145372b676d7Smrg    outSISIDXREG(SISSR, 0x01, scrn | 0x20);
145472b676d7Smrg    outSISIDXREG(SISSR, 0x00, 0x03);
145572b676d7Smrg
145672b676d7Smrg    SiS_WriteAttr(pSiS, 0x10, 0x01);  /* graphics mode */
145772b676d7Smrg
145872b676d7Smrg    /*font1 */
145972b676d7Smrg    outSISIDXREG(SISSR, 0x02, 0x04);  /* write to plane 2 */
146072b676d7Smrg    outSISIDXREG(SISSR, 0x04, 0x06);  /* enable plane graphics */
146172b676d7Smrg    outSISIDXREG(SISGR, 0x04, 0x02);  /* read plane 2 */
146272b676d7Smrg    outSISIDXREG(SISGR, 0x05, 0x00);  /* write mode 0, read mode 0 */
146372b676d7Smrg    outSISIDXREG(SISGR, 0x06, 0x05);  /* set graphics */
146472b676d7Smrg    slowbcopy_frombus(vgaMemBase, pSiS->fonts, SIS_FONTS_SIZE);
146572b676d7Smrg
146672b676d7Smrg    /* font2 */
146772b676d7Smrg    outSISIDXREG(SISSR, 0x02, 0x08);  /* write to plane 3 */
146872b676d7Smrg    outSISIDXREG(SISSR, 0x04, 0x06);  /* enable plane graphics */
146972b676d7Smrg    outSISIDXREG(SISGR, 0x04, 0x03);  /* read plane 3 */
147072b676d7Smrg    outSISIDXREG(SISGR, 0x05, 0x00);  /* write mode 0, read mode 0 */
147172b676d7Smrg    outSISIDXREG(SISGR, 0x06, 0x05);  /* set graphics */
147272b676d7Smrg    slowbcopy_frombus(vgaMemBase, pSiS->fonts + SIS_FONTS_SIZE, SIS_FONTS_SIZE);
147372b676d7Smrg
147472b676d7Smrg    inSISIDXREG(SISSR, 0x01, scrn);
147572b676d7Smrg    outSISIDXREG(SISSR, 0x00, 0x01);
147672b676d7Smrg    outSISIDXREG(SISSR, 0x01, scrn & ~0x20);
147772b676d7Smrg    outSISIDXREG(SISSR, 0x00, 0x03);
147872b676d7Smrg
147972b676d7Smrg    /* Restore clobbered registers */
148072b676d7Smrg    SiS_WriteAttr(pSiS, 0x10, attr10);
148172b676d7Smrg    outSISIDXREG(SISSR, 0x02, seq2);
148272b676d7Smrg    outSISIDXREG(SISSR, 0x04, seq4);
148372b676d7Smrg    outSISIDXREG(SISGR, 0x04, gr4);
148472b676d7Smrg    outSISIDXREG(SISGR, 0x05, gr5);
148572b676d7Smrg    outSISIDXREG(SISGR, 0x06, gr6);
148672b676d7Smrg    outSISREG(SISMISCW, miscOut);
148772b676d7Smrg#endif
148872b676d7Smrg}
148972b676d7Smrg
149072b676d7Smrgstatic void
149172b676d7SmrgSiSVGASaveMode(ScrnInfoPtr pScrn, SISRegPtr save)
149272b676d7Smrg{
149372b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
149472b676d7Smrg    int i;
149572b676d7Smrg
149672b676d7Smrg    save->sisRegMiscOut = inSISREG(SISMISCR);
149772b676d7Smrg
149872b676d7Smrg    for(i = 0; i < 25; i++) {
149972b676d7Smrg       inSISIDXREG(SISCR, i, save->sisRegs3D4[i]);
150072b676d7Smrg    }
150172b676d7Smrg
150272b676d7Smrg    SiS_EnablePalette(pSiS);
150372b676d7Smrg    for(i = 0; i < 21; i++) {
150472b676d7Smrg       save->sisRegsATTR[i] = SiS_ReadAttr(pSiS, i);
150572b676d7Smrg    }
150672b676d7Smrg    SiS_DisablePalette(pSiS);
150772b676d7Smrg
150872b676d7Smrg    for(i = 0; i < 9; i++) {
150972b676d7Smrg       inSISIDXREG(SISGR, i, save->sisRegsGR[i]);
151072b676d7Smrg    }
151172b676d7Smrg
151272b676d7Smrg    for(i = 1; i < 5; i++) {
151372b676d7Smrg       inSISIDXREG(SISSR, i, save->sisRegs3C4[i]);
151472b676d7Smrg    }
151572b676d7Smrg}
151672b676d7Smrg
151772b676d7Smrgstatic void
151872b676d7SmrgSiSVGASaveColormap(ScrnInfoPtr pScrn, SISRegPtr save)
151972b676d7Smrg{
152072b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
152172b676d7Smrg    int i;
152272b676d7Smrg
152372b676d7Smrg    if(pSiS->VGACMapSaved) return;
152472b676d7Smrg
152572b676d7Smrg    outSISREG(SISPEL, 0xff);
152672b676d7Smrg
152772b676d7Smrg    outSISREG(SISCOLIDXR, 0x00);
152872b676d7Smrg    for(i = 0; i < 768; i++) {
152972b676d7Smrg       save->sisDAC[i] = inSISREG(SISCOLDATA);
153072b676d7Smrg       (void)inSISREG(SISINPSTAT);
153172b676d7Smrg       (void)inSISREG(SISINPSTAT);
153272b676d7Smrg    }
153372b676d7Smrg
153472b676d7Smrg    SiS_DisablePalette(pSiS);
153572b676d7Smrg    pSiS->VGACMapSaved = TRUE;
153672b676d7Smrg}
153772b676d7Smrg
153872b676d7Smrgvoid
153972b676d7SmrgSiSVGASave(ScrnInfoPtr pScrn, SISRegPtr save, int flags)
154072b676d7Smrg{
154172b676d7Smrg    if(save == NULL) return;
154272b676d7Smrg
154372b676d7Smrg    if(flags & SISVGA_SR_CMAP)  SiSVGASaveColormap(pScrn, save);
154472b676d7Smrg    if(flags & SISVGA_SR_MODE)  SiSVGASaveMode(pScrn, save);
154572b676d7Smrg    if(flags & SISVGA_SR_FONTS) SiSVGASaveFonts(pScrn);
154672b676d7Smrg}
154772b676d7Smrg
154872b676d7Smrgvoid
154972b676d7SmrgSiSVGARestoreFonts(ScrnInfoPtr pScrn)
155072b676d7Smrg{
155172b676d7Smrg#ifdef SIS_PC_PLATFORM
155272b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
155372b676d7Smrg    pointer vgaMemBase = pSiS->VGAMemBase;
155472b676d7Smrg    UChar miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn;
155572b676d7Smrg
155672b676d7Smrg    if((!pSiS->fonts) || (vgaMemBase == NULL)) return;
155772b676d7Smrg
155872b676d7Smrg    /* save the registers that are needed here */
155972b676d7Smrg    miscOut = inSISREG(SISMISCR);
156072b676d7Smrg    attr10 = SiS_ReadAttr(pSiS, 0x10);
156172b676d7Smrg    inSISIDXREG(SISGR, 0x01, gr1);
156272b676d7Smrg    inSISIDXREG(SISGR, 0x03, gr3);
156372b676d7Smrg    inSISIDXREG(SISGR, 0x04, gr4);
156472b676d7Smrg    inSISIDXREG(SISGR, 0x05, gr5);
156572b676d7Smrg    inSISIDXREG(SISGR, 0x06, gr6);
156672b676d7Smrg    inSISIDXREG(SISGR, 0x08, gr8);
156772b676d7Smrg    inSISIDXREG(SISSR, 0x02, seq2);
156872b676d7Smrg    inSISIDXREG(SISSR, 0x04, seq4);
156972b676d7Smrg
157072b676d7Smrg    /* Force into color mode */
157172b676d7Smrg    outSISREG(SISMISCW, miscOut | 0x01);
157272b676d7Smrg    inSISIDXREG(SISSR, 0x01, scrn);
157372b676d7Smrg    outSISIDXREG(SISSR, 0x00, 0x01);
157472b676d7Smrg    outSISIDXREG(SISSR, 0x01, scrn | 0x20);
157572b676d7Smrg    outSISIDXREG(SISSR, 0x00, 0x03);
157672b676d7Smrg
157772b676d7Smrg    SiS_WriteAttr(pSiS, 0x10, 0x01);	  /* graphics mode */
157872b676d7Smrg    if(pScrn->depth == 4) {
157972b676d7Smrg       outSISIDXREG(SISGR, 0x03, 0x00);  /* don't rotate, write unmodified */
158072b676d7Smrg       outSISIDXREG(SISGR, 0x08, 0xFF);  /* write all bits in a byte */
158172b676d7Smrg       outSISIDXREG(SISGR, 0x01, 0x00);  /* all planes come from CPU */
158272b676d7Smrg    }
158372b676d7Smrg
158472b676d7Smrg    outSISIDXREG(SISSR, 0x02, 0x04); /* write to plane 2 */
158572b676d7Smrg    outSISIDXREG(SISSR, 0x04, 0x06); /* enable plane graphics */
158672b676d7Smrg    outSISIDXREG(SISGR, 0x04, 0x02); /* read plane 2 */
158772b676d7Smrg    outSISIDXREG(SISGR, 0x05, 0x00); /* write mode 0, read mode 0 */
158872b676d7Smrg    outSISIDXREG(SISGR, 0x06, 0x05); /* set graphics */
158972b676d7Smrg    slowbcopy_tobus(pSiS->fonts, vgaMemBase, SIS_FONTS_SIZE);
159072b676d7Smrg
159172b676d7Smrg    outSISIDXREG(SISSR, 0x02, 0x08); /* write to plane 3 */
159272b676d7Smrg    outSISIDXREG(SISSR, 0x04, 0x06); /* enable plane graphics */
159372b676d7Smrg    outSISIDXREG(SISGR, 0x04, 0x03); /* read plane 3 */
159472b676d7Smrg    outSISIDXREG(SISGR, 0x05, 0x00); /* write mode 0, read mode 0 */
159572b676d7Smrg    outSISIDXREG(SISGR, 0x06, 0x05); /* set graphics */
159672b676d7Smrg    slowbcopy_tobus(pSiS->fonts + SIS_FONTS_SIZE, vgaMemBase, SIS_FONTS_SIZE);
159772b676d7Smrg
159872b676d7Smrg    inSISIDXREG(SISSR, 0x01, scrn);
159972b676d7Smrg    outSISIDXREG(SISSR, 0x00, 0x01);
160072b676d7Smrg    outSISIDXREG(SISSR, 0x01, scrn & ~0x20);
160172b676d7Smrg    outSISIDXREG(SISSR, 0x00, 0x03);
160272b676d7Smrg
160372b676d7Smrg    /* restore the registers that were changed */
160472b676d7Smrg    outSISREG(SISMISCW, miscOut);
160572b676d7Smrg    SiS_WriteAttr(pSiS, 0x10, attr10);
160672b676d7Smrg    outSISIDXREG(SISGR, 0x01, gr1);
160772b676d7Smrg    outSISIDXREG(SISGR, 0x03, gr3);
160872b676d7Smrg    outSISIDXREG(SISGR, 0x04, gr4);
160972b676d7Smrg    outSISIDXREG(SISGR, 0x05, gr5);
161072b676d7Smrg    outSISIDXREG(SISGR, 0x06, gr6);
161172b676d7Smrg    outSISIDXREG(SISGR, 0x08, gr8);
161272b676d7Smrg    outSISIDXREG(SISSR, 0x02, seq2);
161372b676d7Smrg    outSISIDXREG(SISSR, 0x04, seq4);
161472b676d7Smrg#endif
161572b676d7Smrg}
161672b676d7Smrg
161772b676d7Smrgstatic void
161872b676d7SmrgSiSVGARestoreMode(ScrnInfoPtr pScrn, SISRegPtr restore)
161972b676d7Smrg{
162072b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
162172b676d7Smrg    int i;
162272b676d7Smrg
162372b676d7Smrg    outSISREG(SISMISCW, restore->sisRegMiscOut);
162472b676d7Smrg
162572b676d7Smrg    for(i = 1; i < 5; i++) {
162672b676d7Smrg       outSISIDXREG(SISSR, i, restore->sisRegs3C4[i]);
162772b676d7Smrg    }
162872b676d7Smrg
162972b676d7Smrg    outSISIDXREG(SISCR, 17, restore->sisRegs3D4[17] & ~0x80);
163072b676d7Smrg
163172b676d7Smrg    for(i = 0; i < 25; i++) {
163272b676d7Smrg       outSISIDXREG(SISCR, i, restore->sisRegs3D4[i]);
163372b676d7Smrg    }
163472b676d7Smrg
163572b676d7Smrg    for(i = 0; i < 9; i++) {
163672b676d7Smrg       outSISIDXREG(SISGR, i, restore->sisRegsGR[i]);
163772b676d7Smrg    }
163872b676d7Smrg
163972b676d7Smrg    SiS_EnablePalette(pSiS);
164072b676d7Smrg    for(i = 0; i < 21; i++) {
164172b676d7Smrg       SiS_WriteAttr(pSiS, i, restore->sisRegsATTR[i]);
164272b676d7Smrg    }
164372b676d7Smrg    SiS_DisablePalette(pSiS);
164472b676d7Smrg}
164572b676d7Smrg
164672b676d7Smrg
164772b676d7Smrgstatic void
164872b676d7SmrgSiSVGARestoreColormap(ScrnInfoPtr pScrn, SISRegPtr restore)
164972b676d7Smrg{
165072b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
165172b676d7Smrg    int i;
165272b676d7Smrg
165372b676d7Smrg    if(!pSiS->VGACMapSaved) return;
165472b676d7Smrg
165572b676d7Smrg    outSISREG(SISPEL, 0xff);
165672b676d7Smrg
165772b676d7Smrg    outSISREG(SISCOLIDX, 0x00);
165872b676d7Smrg    for(i = 0; i < 768; i++) {
165972b676d7Smrg       outSISREG(SISCOLDATA, restore->sisDAC[i]);
166072b676d7Smrg       (void)inSISREG(SISINPSTAT);
166172b676d7Smrg       (void)inSISREG(SISINPSTAT);
166272b676d7Smrg    }
166372b676d7Smrg
166472b676d7Smrg    SiS_DisablePalette(pSiS);
166572b676d7Smrg}
166672b676d7Smrg
166772b676d7Smrgvoid
166872b676d7SmrgSiSVGARestore(ScrnInfoPtr pScrn, SISRegPtr restore, int flags)
166972b676d7Smrg{
167072b676d7Smrg    if(restore == NULL) return;
167172b676d7Smrg
167272b676d7Smrg    if(flags & SISVGA_SR_MODE)  SiSVGARestoreMode(pScrn, restore);
167372b676d7Smrg    if(flags & SISVGA_SR_FONTS) SiSVGARestoreFonts(pScrn);
167472b676d7Smrg    if(flags & SISVGA_SR_CMAP)  SiSVGARestoreColormap(pScrn, restore);
167572b676d7Smrg}
167672b676d7Smrg
167772b676d7Smrgstatic void
167872b676d7SmrgSiS_SeqReset(SISPtr pSiS, Bool start)
167972b676d7Smrg{
168072b676d7Smrg    if(start) {
168172b676d7Smrg       outSISIDXREG(SISSR, 0x00, 0x01);	/* Synchronous Reset */
168272b676d7Smrg    } else {
168372b676d7Smrg       outSISIDXREG(SISSR, 0x00, 0x03);	/* End Reset */
168472b676d7Smrg    }
168572b676d7Smrg}
168672b676d7Smrg
168772b676d7Smrgvoid
168872b676d7SmrgSiSVGAProtect(ScrnInfoPtr pScrn, Bool on)
168972b676d7Smrg{
169072b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
169172b676d7Smrg    UChar  tmp;
169272b676d7Smrg
169372b676d7Smrg    if(!pScrn->vtSema) return;
169472b676d7Smrg
169572b676d7Smrg    if(on) {
169672b676d7Smrg       inSISIDXREG(SISSR, 0x01, tmp);
169772b676d7Smrg       SiS_SeqReset(pSiS, TRUE);		/* start synchronous reset */
169872b676d7Smrg       outSISIDXREG(SISSR, 0x01, tmp | 0x20);	/* disable display */
169972b676d7Smrg       SiS_EnablePalette(pSiS);
170072b676d7Smrg    } else {
170172b676d7Smrg       andSISIDXREG(SISSR, 0x01, ~0x20);	/* enable display */
170272b676d7Smrg       SiS_SeqReset(pSiS, FALSE);		/* clear synchronous reset */
170372b676d7Smrg       SiS_DisablePalette(pSiS);
170472b676d7Smrg    }
170572b676d7Smrg}
170672b676d7Smrg
170772b676d7Smrg#ifdef SIS_PC_PLATFORM
170872b676d7SmrgBool
170972b676d7SmrgSiSVGAMapMem(ScrnInfoPtr pScrn)
171072b676d7Smrg{
171172b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
171272b676d7Smrg
171372b676d7Smrg    /* Map only once */
171472b676d7Smrg    if(pSiS->VGAMemBase) return TRUE;
171572b676d7Smrg
171672b676d7Smrg    if(pSiS->VGAMapSize == 0) pSiS->VGAMapSize = (64 * 1024);
171772b676d7Smrg    if(pSiS->VGAMapPhys == 0) pSiS->VGAMapPhys = 0xA0000;
171872b676d7Smrg
171972b676d7Smrg#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
172072b676d7Smrg    pSiS->VGAMemBase = xf86MapDomainMemory(pScrn->scrnIndex, VIDMEM_MMIO_32BIT,
172172b676d7Smrg			pSiS->PciTag, pSiS->VGAMapPhys, pSiS->VGAMapSize);
172272b676d7Smrg#else
172372b676d7Smrg    pSiS->VGAMemBase = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO_32BIT,
172472b676d7Smrg			pSiS->VGAMapPhys, pSiS->VGAMapSize);
172572b676d7Smrg#endif
172672b676d7Smrg
172772b676d7Smrg    return(pSiS->VGAMemBase != NULL);
172872b676d7Smrg}
172972b676d7Smrg
173072b676d7Smrgvoid
173172b676d7SmrgSiSVGAUnmapMem(ScrnInfoPtr pScrn)
173272b676d7Smrg{
173372b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
173472b676d7Smrg
173572b676d7Smrg    if(pSiS->VGAMemBase == NULL) return;
173672b676d7Smrg
173772b676d7Smrg    xf86UnMapVidMem(pScrn->scrnIndex, pSiS->VGAMemBase, pSiS->VGAMapSize);
173872b676d7Smrg    pSiS->VGAMemBase = NULL;
173972b676d7Smrg}
174072b676d7Smrg#endif
174172b676d7Smrg
174272b676d7Smrg#if 0
174372b676d7Smrgstatic CARD32
174472b676d7SmrgSiS_HBlankKGA(DisplayModePtr mode, SISRegPtr regp, int nBits, unsigned int Flags)
174572b676d7Smrg{
174672b676d7Smrg    int    nExtBits = (nBits < 6) ? 0 : nBits - 6;
174772b676d7Smrg    CARD32 ExtBits;
174872b676d7Smrg    CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 6;
174972b676d7Smrg
175072b676d7Smrg    regp->sisRegs3D4[3] = (regp->sisRegs3D4[3] & ~0x1F) |
175172b676d7Smrg                          (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F);
175272b676d7Smrg    regp->sisRegs3D4[5] = (regp->sisRegs3D4[5] & ~0x80) |
175372b676d7Smrg                          ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2);
175472b676d7Smrg    ExtBits             = ((mode->CrtcHBlankEnd >> 3) - 1) & ExtBitMask;
175572b676d7Smrg
175672b676d7Smrg    if( (Flags & SISKGA_FIX_OVERSCAN) &&
175772b676d7Smrg        ((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3))) {
175872b676d7Smrg       int i = (regp->sisRegs3D4[3] & 0x1F)        |
175972b676d7Smrg	       ((regp->sisRegs3D4[5] & 0x80) >> 2) |
176072b676d7Smrg	       ExtBits;
176172b676d7Smrg       if(Flags & SISKGA_ENABLE_ON_ZERO) {
176272b676d7Smrg	  if( (i-- > (((mode->CrtcHBlankStart >> 3) - 1) & (0x3F | ExtBitMask))) &&
176372b676d7Smrg	      (mode->CrtcHBlankEnd == mode->CrtcHTotal) ) {
176472b676d7Smrg	     i = 0;
176572b676d7Smrg	  }
176672b676d7Smrg       } else if (Flags & SISKGA_BE_TOT_DEC) i--;
176772b676d7Smrg       regp->sisRegs3D4[3] = (regp->sisRegs3D4[3] & ~0x1F) | (i & 0x1F);
176872b676d7Smrg       regp->sisRegs3D4[5] = (regp->sisRegs3D4[5] & ~0x80) | ((i << 2) & 0x80);
176972b676d7Smrg       ExtBits = i & ExtBitMask;
177072b676d7Smrg    }
177172b676d7Smrg    return ExtBits >> 6;
177272b676d7Smrg}
177372b676d7Smrg#endif
177472b676d7Smrg
177572b676d7Smrgstatic CARD32
177672b676d7SmrgSiS_VBlankKGA(DisplayModePtr mode, SISRegPtr regp, int nBits, unsigned int Flags)
177772b676d7Smrg{
177872b676d7Smrg    CARD32 nExtBits   = (nBits < 8) ? 0 : (nBits - 8);
177972b676d7Smrg    CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 8;
178072b676d7Smrg    CARD32 ExtBits    = (mode->CrtcVBlankEnd - 1) & ExtBitMask;
178172b676d7Smrg    CARD32 BitMask    = (nBits < 7) ? 0 : ((1 << nExtBits) - 1);
178272b676d7Smrg    int VBlankStart   = (mode->CrtcVBlankStart - 1) & 0xFF;
178372b676d7Smrg    regp->sisRegs3D4[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
178472b676d7Smrg
178572b676d7Smrg    if((Flags & SISKGA_FIX_OVERSCAN) && (mode->CrtcVBlankEnd == mode->CrtcVTotal)) {
178672b676d7Smrg       int i = regp->sisRegs3D4[22] | ExtBits;
178772b676d7Smrg       if(Flags & SISKGA_ENABLE_ON_ZERO) {
178872b676d7Smrg	  if( ((BitMask && ((i & BitMask) > (VBlankStart & BitMask))) ||
178972b676d7Smrg	       ((i > VBlankStart)  &&  		            /* 8-bit case */
179072b676d7Smrg	        ((i & 0x7F) > (VBlankStart & 0x7F)))) &&    /* 7-bit case */
179172b676d7Smrg	      (!(regp->sisRegs3D4[9] & 0x9F)) ) {	    /* 1 scanline/row */
179272b676d7Smrg	     i = 0;
179372b676d7Smrg	  } else {
179472b676d7Smrg	     i--;
179572b676d7Smrg	  }
179672b676d7Smrg       } else if(Flags & SISKGA_BE_TOT_DEC) i--;
179772b676d7Smrg
179872b676d7Smrg       regp->sisRegs3D4[22] = i & 0xFF;
179972b676d7Smrg       ExtBits = i & 0xFF00;
180072b676d7Smrg    }
180172b676d7Smrg    return (ExtBits >> 8);
180272b676d7Smrg}
180372b676d7Smrg
180472b676d7SmrgBool
180572b676d7SmrgSiSVGAInit(ScrnInfoPtr pScrn, DisplayModePtr mode, int fixsync)
180672b676d7Smrg{
180772b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
180872b676d7Smrg    SISRegPtr regp = &pSiS->ModeReg;
180972b676d7Smrg    int depth = pScrn->depth;
181072b676d7Smrg    unsigned int i;
181172b676d7Smrg
181272b676d7Smrg    /* Sync */
181372b676d7Smrg    if((mode->Flags & (V_PHSYNC | V_NHSYNC)) && (mode->Flags & (V_PVSYNC | V_NVSYNC))) {
181472b676d7Smrg        regp->sisRegMiscOut = 0x23;
181572b676d7Smrg        if(mode->Flags & V_NHSYNC) regp->sisRegMiscOut |= 0x40;
181672b676d7Smrg        if(mode->Flags & V_NVSYNC) regp->sisRegMiscOut |= 0x80;
181772b676d7Smrg    } else {
181872b676d7Smrg        int VDisplay = mode->VDisplay;
181972b676d7Smrg
182072b676d7Smrg        if(mode->Flags & V_DBLSCAN) VDisplay *= 2;
182172b676d7Smrg        if(mode->VScan > 1)         VDisplay *= mode->VScan;
182272b676d7Smrg
182372b676d7Smrg        if(VDisplay < 400)        regp->sisRegMiscOut = 0xA3;	/* +hsync -vsync */
182472b676d7Smrg        else if (VDisplay < 480)  regp->sisRegMiscOut = 0x63;	/* -hsync +vsync */
182572b676d7Smrg        else if (VDisplay < 768)  regp->sisRegMiscOut = 0xE3;	/* -hsync -vsync */
182672b676d7Smrg        else                      regp->sisRegMiscOut = 0x23;	/* +hsync +vsync */
182772b676d7Smrg    }
182872b676d7Smrg
182972b676d7Smrg    regp->sisRegMiscOut |= (mode->ClockIndex & 0x03) << 2;
183072b676d7Smrg
183172b676d7Smrg    /* Seq */
183272b676d7Smrg    if(depth == 4) regp->sisRegs3C4[0] = 0x02;
183372b676d7Smrg    else	   regp->sisRegs3C4[0] = 0x00;
183472b676d7Smrg
183572b676d7Smrg    if(mode->Flags & V_CLKDIV2) regp->sisRegs3C4[1] = 0x09;
183672b676d7Smrg    else                        regp->sisRegs3C4[1] = 0x01;
183772b676d7Smrg
183872b676d7Smrg    regp->sisRegs3C4[2] = 0x0F;
183972b676d7Smrg
184072b676d7Smrg    regp->sisRegs3C4[3] = 0x00;
184172b676d7Smrg
184272b676d7Smrg    if(depth < 8)  regp->sisRegs3C4[4] = 0x06;
184372b676d7Smrg    else           regp->sisRegs3C4[4] = 0x0E;
184472b676d7Smrg
184572b676d7Smrg    /* CRTC */
184672b676d7Smrg    regp->sisRegs3D4[0]  = (mode->CrtcHTotal >> 3) - 5;
184772b676d7Smrg    regp->sisRegs3D4[1]  = (mode->CrtcHDisplay >> 3) - 1;
184872b676d7Smrg    regp->sisRegs3D4[2]  = (mode->CrtcHBlankStart >> 3) - 1;
184972b676d7Smrg    regp->sisRegs3D4[3]  = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80;
185072b676d7Smrg    i = (((mode->CrtcHSkew << 2) + 0x10) & ~0x1F);
185172b676d7Smrg    if(i < 0x80)  regp->sisRegs3D4[3] |= i;
185272b676d7Smrg    regp->sisRegs3D4[4]  = (mode->CrtcHSyncStart >> 3) - fixsync;
185372b676d7Smrg    regp->sisRegs3D4[5]  = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) |
185472b676d7Smrg			   (((mode->CrtcHSyncEnd >> 3) - fixsync) & 0x1F);
185572b676d7Smrg    regp->sisRegs3D4[6]  = (mode->CrtcVTotal - 2) & 0xFF;
185672b676d7Smrg    regp->sisRegs3D4[7]  = (((mode->CrtcVTotal - 2) & 0x100) >> 8)           |
185772b676d7Smrg			   (((mode->CrtcVDisplay - 1) & 0x100) >> 7)         |
185872b676d7Smrg			   (((mode->CrtcVSyncStart - fixsync) & 0x100) >> 6) |
185972b676d7Smrg			   (((mode->CrtcVBlankStart - 1) & 0x100) >> 5)      |
186072b676d7Smrg			   0x10                                              |
186172b676d7Smrg			   (((mode->CrtcVTotal - 2) & 0x200)   >> 4)         |
186272b676d7Smrg			   (((mode->CrtcVDisplay - 1) & 0x200) >> 3)         |
186372b676d7Smrg			   (((mode->CrtcVSyncStart - fixsync) & 0x200) >> 2);
186472b676d7Smrg    regp->sisRegs3D4[8]  = 0x00;
186572b676d7Smrg    regp->sisRegs3D4[9]  = (((mode->CrtcVBlankStart - 1) & 0x200) >> 4) | 0x40;
186672b676d7Smrg    if(mode->Flags & V_DBLSCAN) regp->sisRegs3D4[9] |= 0x80;
186772b676d7Smrg    if(mode->VScan >= 32)     regp->sisRegs3D4[9] |= 0x1F;
186872b676d7Smrg    else if (mode->VScan > 1) regp->sisRegs3D4[9] |= mode->VScan - 1;
186972b676d7Smrg    regp->sisRegs3D4[10] = 0x00;
187072b676d7Smrg    regp->sisRegs3D4[11] = 0x00;
187172b676d7Smrg    regp->sisRegs3D4[12] = 0x00;
187272b676d7Smrg    regp->sisRegs3D4[13] = 0x00;
187372b676d7Smrg    regp->sisRegs3D4[14] = 0x00;
187472b676d7Smrg    regp->sisRegs3D4[15] = 0x00;
187572b676d7Smrg    regp->sisRegs3D4[16] = (mode->CrtcVSyncStart - fixsync) & 0xFF;
187672b676d7Smrg    regp->sisRegs3D4[17] = ((mode->CrtcVSyncEnd - fixsync) & 0x0F) | 0x20;
187772b676d7Smrg    regp->sisRegs3D4[18] = (mode->CrtcVDisplay - 1) & 0xFF;
187872b676d7Smrg    regp->sisRegs3D4[19] = pScrn->displayWidth >> 4;
187972b676d7Smrg    regp->sisRegs3D4[20] = 0x00;
188072b676d7Smrg    regp->sisRegs3D4[21] = (mode->CrtcVBlankStart - 1) & 0xFF;
188172b676d7Smrg    regp->sisRegs3D4[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
188272b676d7Smrg    if(depth < 8) regp->sisRegs3D4[23] = 0xE3;
188372b676d7Smrg    else	  regp->sisRegs3D4[23] = 0xC3;
188472b676d7Smrg    regp->sisRegs3D4[24] = 0xFF;
188572b676d7Smrg
188672b676d7Smrg#if 0
188772b676d7Smrg    SiS_HBlankKGA(mode, regp, 0, SISKGA_FIX_OVERSCAN | SISKGA_ENABLE_ON_ZERO);
188872b676d7Smrg#endif
188972b676d7Smrg    SiS_VBlankKGA(mode, regp, 0, SISKGA_FIX_OVERSCAN | SISKGA_ENABLE_ON_ZERO);
189072b676d7Smrg
189172b676d7Smrg    /* GR */
189272b676d7Smrg    regp->sisRegsGR[0] = 0x00;
189372b676d7Smrg    regp->sisRegsGR[1] = 0x00;
189472b676d7Smrg    regp->sisRegsGR[2] = 0x00;
189572b676d7Smrg    regp->sisRegsGR[3] = 0x00;
189672b676d7Smrg    regp->sisRegsGR[4] = 0x00;
189772b676d7Smrg    if(depth == 4) regp->sisRegsGR[5] = 0x02;
189872b676d7Smrg    else           regp->sisRegsGR[5] = 0x40;
189972b676d7Smrg    regp->sisRegsGR[6] = 0x05;   /* only map 64k VGA memory !!!! */
190072b676d7Smrg    regp->sisRegsGR[7] = 0x0F;
190172b676d7Smrg    regp->sisRegsGR[8] = 0xFF;
190272b676d7Smrg
190372b676d7Smrg    /* Attr */
190472b676d7Smrg    for(i = 0; i <= 15; i++) {	/* standard colormap translation */
190572b676d7Smrg       regp->sisRegsATTR[i] = i;
190672b676d7Smrg    }
190772b676d7Smrg    if(depth == 4) regp->sisRegsATTR[16] = 0x81;
190872b676d7Smrg    else           regp->sisRegsATTR[16] = 0x41;
190972b676d7Smrg    if(depth >= 4) regp->sisRegsATTR[17] = 0xFF;
191072b676d7Smrg    else           regp->sisRegsATTR[17] = 0x01;
191172b676d7Smrg    regp->sisRegsATTR[18] = 0x0F;
191272b676d7Smrg    regp->sisRegsATTR[19] = 0x00;
191372b676d7Smrg    regp->sisRegsATTR[20] = 0x00;
191472b676d7Smrg
191572b676d7Smrg    return TRUE;
191672b676d7Smrg}
191772b676d7Smrg
191872b676d7Smrgstatic void
191972b676d7SmrgSISVGABlankScreen(ScrnInfoPtr pScrn, Bool on)
192072b676d7Smrg{
192172b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
192272b676d7Smrg    UChar  tmp;
192372b676d7Smrg
192472b676d7Smrg    inSISIDXREG(SISSR, 0x01, tmp);
192572b676d7Smrg    if(on) tmp &= ~0x20;
192672b676d7Smrg    else   tmp |= 0x20;
192772b676d7Smrg    SiS_SeqReset(pSiS, TRUE);
192872b676d7Smrg    outSISIDXREG(SISSR, 0x01, tmp);
192972b676d7Smrg    SiS_SeqReset(pSiS, FALSE);
193072b676d7Smrg}
193172b676d7Smrg
193272b676d7SmrgBool
193372b676d7SmrgSiSVGASaveScreen(ScreenPtr pScreen, int mode)
193472b676d7Smrg{
193572b676d7Smrg    ScrnInfoPtr pScrn = NULL;
193672b676d7Smrg    Bool on = xf86IsUnblank(mode);
193772b676d7Smrg
193872b676d7Smrg    if(pScreen == NULL) return FALSE;
193972b676d7Smrg
194072b676d7Smrg    pScrn = xf86Screens[pScreen->myNum];
194172b676d7Smrg
194272b676d7Smrg    if(pScrn->vtSema) {
194372b676d7Smrg       SISVGABlankScreen(pScrn, on);
194472b676d7Smrg    }
194572b676d7Smrg    return TRUE;
194672b676d7Smrg}
194772b676d7Smrg
194872b676d7Smrg#undef SIS_FONTS_SIZE
194972b676d7Smrg
195072b676d7Smrg
1951