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