diff options
Diffstat (limited to 'drivers/video/fbdev/sis')
-rw-r--r-- | drivers/video/fbdev/sis/300vtbl.h | 1072 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/310vtbl.h | 1339 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/Makefile | 7 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/init.c | 3655 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/init.h | 1541 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/init301.c | 11071 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/init301.h | 456 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/initdef.h | 708 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/initextlfb.c | 231 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/oem300.h | 840 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/oem310.h | 430 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/sis.h | 586 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/sis_accel.c | 423 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/sis_accel.h | 400 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/sis_main.c | 6844 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/sis_main.h | 781 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/vgatypes.h | 97 | ||||
-rw-r--r-- | drivers/video/fbdev/sis/vstruct.h | 551 |
18 files changed, 31032 insertions, 0 deletions
diff --git a/drivers/video/fbdev/sis/300vtbl.h b/drivers/video/fbdev/sis/300vtbl.h new file mode 100644 index 0000000..e4b4a26 --- /dev/null +++ b/drivers/video/fbdev/sis/300vtbl.h @@ -0,0 +1,1072 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Register settings for SiS 300 series + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +static const struct SiS_Ext SiS300_EModeIDTable[] = +{ + {0x6a,0x2212,0x0102,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x? */ + {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, + {0x2f,0x021b,0x0100,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10,-1}, /* 640x400x8 */ + {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, + {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11,-1}, /* 720x480x8 */ + {0x32,0x6a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12,-1}, /* 720x576x8 */ + {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11,-1}, /* 720x480x16 */ + {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12,-1}, /* 720x576x16 */ + {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11,-1}, /* 720x480x32 */ + {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12,-1}, /* 720x576x32 */ + {0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, /* 1024x768x? */ + {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, /* 1024x768x8 */ + {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1}, /* 1280x1024x8 */ + {0x3c,0x063b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1}, + {0x3d,0x067d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1}, + {0x40,0x921c,0x010d,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23,-1}, /* 320x200x15 */ + {0x41,0x921d,0x010e,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23,-1}, /* 320x200x16 */ + {0x43,0x0a1c,0x0110,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, + {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, + {0x46,0x2a1c,0x0113,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x15 */ + {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x16 */ + {0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, + {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, + {0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1}, + {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1}, + {0x50,0x921b,0x0132,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24,-1}, /* 320x240x8 */ + {0x51,0xb21b,0x0133,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25,-1}, /* 400x300x8 */ + {0x52,0x921b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26,-1}, /* 512x384x8 */ + {0x56,0x921d,0x0135,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24,-1}, /* 320x240x16 */ + {0x57,0xb21d,0x0136,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25,-1}, /* 400x300x16 */ + {0x58,0x921d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26,-1}, /* 512x384x16 */ + {0x59,0x921b,0x0138,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23,-1}, /* 320x200x8 */ + {0x5c,0x921f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26,-1}, /* 512x384x32 */ + {0x5d,0x021d,0x0139,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10,-1}, /* 640x400x16 */ + {0x5e,0x021f,0x0000,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10,-1}, /* 640x400x32 */ + {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, + {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x32 */ + {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, + {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1}, + {0x66,0x06ff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1}, + {0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1}, + {0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1}, + {0x6b,0x07ff,0x0000,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1}, + {0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1}, /* 2048x1536x8 */ + {0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1}, /* 2048x1536x16 */ + {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d,-1}, /* 800x480x8 */ + {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1}, /* 1024x576x8 */ + {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1}, /* 1024x576x16 */ + {0x75,0x0e3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1280x720x16 */ + {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d,-1}, /* 800x480x32 */ + {0x77,0x4a3f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1}, /* 1024x576x32 */ + {0x78,0x0eff,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1280x720x32 */ + {0x79,0x0e3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1280x720x8 */ + {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d,-1}, /* 800x480x16 */ + {0x7c,0x0a3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1}, /* 1280x960x8 */ + {0x7d,0x0a7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1}, /* 1280x960x16 */ + {0x7e,0x0aff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1}, /* 1280x960x32 */ + {0x20,0x4a1b,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1}, /* 1024x600 */ + {0x21,0x4a3d,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1}, + {0x22,0x4a7f,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1}, + {0x23,0x4a1b,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1}, /* 1152x768 */ + {0x24,0x4a3d,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1}, + {0x25,0x4a7f,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1}, + {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1}, /* 1152x864 */ + {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1}, + {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1}, + {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x39,-1}, /* 848x480 */ + {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x39,-1}, + {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x39,-1}, + {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3b,-1}, /* 856x480 */ + {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3b,-1}, + {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3b,-1}, + {0x48,0x6a3b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1360x768 */ + {0x4b,0x6a7d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3d,-1}, + {0x4e,0x6aff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3d,-1}, + {0x4f,0x921f,0x0000,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23,-1}, /* 320x200x32 */ + {0x53,0x921f,0x0000,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24,-1}, /* 320x240x32 */ + {0x54,0xb21f,0x0000,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25,-1}, /* 400x300x32 */ + {0x55,0x2e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3e,-1}, /* 1280x768 */ + {0x5a,0x2e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3e,-1}, + {0x5b,0x2eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3e,-1}, + {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3f,-1}, /* 768x576x8 */ + {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3f,-1}, /* 768x576x16 */ + {0x61,0x6a1f,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3f,-1}, /* 768x576x32 */ + {0x67,0x6e3b,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x40,-1}, /* 1360x1024x8 (BARCO) */ + {0x6f,0x6e7d,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x40,-1}, /* 1360x1024x16 (BARCO) */ + {0x72,0x6eff,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x40,-1}, /* 1360x1024x32 (BARCO) */ + {0xff,0x0000,0xffff,0, 0x00,0x00,0x00,0x00,0x00} +}; + +static const struct SiS_Ext2 SiS300_RefIndex[] = +{ + {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 00 */ + {0x0467,0x0e,0x04,0x05,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 01 */ + {0x0067,0x0f,0x07,0x48,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 02 - CRT1CRTC was 0x4f */ + {0x0067,0x10,0x06,0x8b,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 03 */ + {0x0147,0x11,0x08,0x00,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 04 */ + {0x0147,0x12,0x0c,0x00,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 05 */ + {0x0047,0x11,0x0e,0x00,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 06 - CRT1CRTC was 0x51 */ + {0x0047,0x11,0x13,0x00,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 07 */ + {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 08 */ + {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 09 */ + {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0a */ + {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0b */ + {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0c */ + {0xc047,0x0a,0x08,0x00,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0d */ + {0xc047,0x0b,0x0a,0x00,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0e */ + {0xc047,0x0c,0x10,0x00,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0f */ + {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0, 0x4a, 0x49}, /* 10 */ + {0xc06f,0x31,0x01,0x06,0x13,0x31, 720, 480, 0, 0x00, 0x00}, /* 11 */ + {0x006f,0x32,0x4a,0x06,0x14,0x32, 720, 576, 0, 0x00, 0x00}, /* 12 */ /* 4a was 03 */ + {0x0187,0x15,0x05,0x00,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 13 */ + {0xc877,0x16,0x09,0x06,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 14 */ + {0xc067,0x17,0x0b,0x49,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 15 - CRT1CRTC was 0x97 */ + {0x0267,0x18,0x0d,0x00,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 16 */ + {0x0047,0x19,0x11,0x8c,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 17 - CRT1CRTC was 0x59 */ + {0x0047,0x1a,0x12,0x00,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 18 */ + {0x0007,0x1b,0x16,0x00,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 19 - CRT1CRTC was 0x5b */ + {0x0387,0x1c,0x0d,0x00,0x07,0x3a,1280,1024, 0, 0x00, 0x00}, /* 1a - CRT1CRTC was 0x5c */ + {0x0077,0x1d,0x14,0x07,0x07,0x3a,1280,1024, 0, 0x00, 0x00}, /* 1b */ + {0x0047,0x1e,0x17,0x00,0x07,0x3a,1280,1024, 0, 0x00, 0x00}, /* 1c */ + {0x0007,0x1f,0x18,0x00,0x07,0x3a,1280,1024, 0, 0x00, 0x00}, /* 1d */ + {0x0007,0x20,0x19,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 1e - CRT1CRTC was 0x60 */ + {0x0007,0x21,0x1a,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 1f */ + {0x0007,0x22,0x1b,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 20 */ + {0x0007,0x23,0x1d,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 21 - CRT1CRTC was 0x63 */ + {0x0007,0x24,0x1e,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 22 */ + {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0, 0x4b, 0x4b}, /* 23 */ + {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0, 0x00, 0x00}, /* 24 */ + {0x0077,0x02,0x04,0x05,0x05,0x51, 400, 300, 0, 0x00, 0x00}, /* 25 */ + {0xc877,0x03,0x09,0x06,0x06,0x52, 512, 384, 0, 0x00, 0x00}, /* 26 */ /* was c077 */ + {0x8207,0x25,0x1f,0x00,0x00,0x68,1920,1440, 0, 0x00, 0x00}, /* 27 */ + {0x0007,0x26,0x20,0x00,0x00,0x6c,2048,1536, 0, 0x00, 0x00}, /* 28 */ + {0x0067,0x27,0x14,0x08,0x0a,0x6e,1280, 960, 0, 0x00, 0x00}, /* 29 - 1280x960-60 */ + {0x0027,0x45,0x3c,0x08,0x0a,0x6e,1280, 960, 0, 0x00, 0x00}, /* 2a - 1280x960-85 */ + {0xc077,0x33,0x09,0x06,0x00,0x20,1024, 600, 0, 0x00, 0x00}, /* 2b */ + {0xc077,0x34,0x0b,0x06,0x00,0x23,1152, 768, 0, 0x00, 0x00}, /* 2c */ /* VCLK 0x09 */ + {0x0077,0x35,0x27,0x08,0x18,0x70, 800, 480, 0, 0x00, 0x00}, /* 2d */ + {0x0047,0x36,0x37,0x08,0x18,0x70, 800, 480, 0, 0x00, 0x00}, /* 2e */ + {0x0047,0x37,0x08,0x08,0x18,0x70, 800, 480, 0, 0x00, 0x00}, /* 2f */ + {0x0077,0x38,0x09,0x09,0x19,0x71,1024, 576, 0, 0x00, 0x00}, /* 30 */ + {0x0047,0x39,0x38,0x09,0x19,0x71,1024, 576, 0, 0x00, 0x00}, /* 31 */ + {0x0047,0x3a,0x11,0x09,0x19,0x71,1024, 576, 0, 0x00, 0x00}, /* 32 */ + {0x0077,0x3b,0x39,0x0a,0x0c,0x75,1280, 720, 0, 0x00, 0x00}, /* 33 */ + {0x0047,0x3c,0x3a,0x0a,0x0c,0x75,1280, 720, 0, 0x00, 0x00}, /* 34 */ + {0x0007,0x3d,0x3b,0x0a,0x0c,0x75,1280, 720, 0, 0x00, 0x00}, /* 35 */ + {0x0067,0x49,0x35,0x06,0x1a,0x29,1152, 864, 0, 0x00, 0x00}, /* 36 1152x864-60Hz */ + {0x0067,0x3e,0x34,0x06,0x1a,0x29,1152, 864, 0, 0x00, 0x00}, /* 37 1152x864-75Hz */ + {0x0047,0x44,0x3a,0x06,0x1a,0x29,1152, 864, 0, 0x00, 0x00}, /* 38 1152x864-85Hz */ + {0x00c7,0x3f,0x28,0x00,0x16,0x39, 848, 480, 0, 0x00, 0x00}, /* 39 848x480-38Hzi */ + {0xc067,0x40,0x3d,0x0b,0x16,0x39, 848, 480, 0, 0x00, 0x00}, /* 3a 848x480-60Hz */ + {0x00c7,0x41,0x28,0x00,0x17,0x3f, 856, 480, 0, 0x00, 0x00}, /* 3b 856x480-38Hzi */ + {0xc067,0x42,0x28,0x0c,0x17,0x3f, 856, 480, 0, 0x00, 0x00}, /* 3c 856x480-60Hz */ + {0x0067,0x43,0x3e,0x0d,0x1b,0x48,1360, 768, 0, 0x00, 0x00}, /* 3d 1360x768-60Hz */ + {0x0077,0x46,0x3f,0x08,0x08,0x55,1280, 768, 0, 0x00, 0x00}, /* 3e 1280x768-60Hz */ + {0x006f,0x47,0x4c,0x06,0x15,0x5f, 768, 576, 0, 0x00, 0x00}, /* 3f 768x576 */ + {0x0027,0x48,0x13,0x08,0x00,0x67,1360,1024, 0, 0x00, 0x00}, /* 40 1360x1024-59Hz (BARCO1366 only) */ + {0xffff, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00} +}; + +static const struct SiS_VBMode SiS300_VBModeIDTable[] = +{ + {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, + {0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x02}, + {0x03,0x00,0x00,0x00,0x02,0x00,0x02,0x00}, + {0x03,0x00,0x00,0x00,0x02,0x00,0x02,0x01}, + {0x03,0x00,0x00,0x00,0x03,0x00,0x03,0x02}, + {0x05,0x00,0x00,0x01,0x04,0x00,0x00,0x00}, + {0x06,0x00,0x00,0x01,0x05,0x00,0x02,0x00}, + {0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x01}, + {0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x02}, + {0x0d,0x00,0x00,0x01,0x04,0x00,0x00,0x00}, + {0x0e,0x00,0x00,0x01,0x05,0x00,0x02,0x00}, + {0x0f,0x00,0x00,0x01,0x05,0x00,0x02,0x01}, + {0x10,0x00,0x00,0x01,0x05,0x00,0x02,0x01}, + {0x11,0x00,0x00,0x01,0x05,0x00,0x02,0x03}, + {0x12,0x00,0x00,0x01,0x05,0x00,0x02,0x03}, + {0x13,0x00,0x00,0x01,0x04,0x00,0x04,0x00}, + {0x6a,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x2e,0x00,0x00,0x01,0x05,0x00,0x06,0x08}, + {0x2f,0x00,0x00,0x01,0x05,0x00,0x06,0x06}, + {0x30,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x31,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x32,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x33,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x34,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x35,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x36,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x37,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x38,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x3a,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x40,0x00,0x00,0x01,0x04,0x00,0x05,0x05}, + {0x41,0x00,0x00,0x01,0x04,0x00,0x05,0x05}, + {0x43,0x00,0x00,0x01,0x05,0x00,0x06,0x08}, + {0x44,0x00,0x00,0x01,0x05,0x00,0x06,0x08}, + {0x46,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x47,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x49,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x4a,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x4c,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x4d,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x4f,0x00,0x00,0x01,0x04,0x00,0x05,0x05}, + {0x50,0x00,0x00,0x01,0x04,0x00,0x05,0x07}, + {0x51,0x00,0x00,0x01,0x07,0x00,0x07,0x09}, + {0x52,0x00,0x00,0x01,0x00,0x00,0x09,0x0b}, + {0x53,0x00,0x00,0x01,0x04,0x00,0x05,0x07}, + {0x54,0x00,0x00,0x01,0x07,0x00,0x07,0x09}, + {0x56,0x00,0x00,0x01,0x04,0x00,0x05,0x07}, + {0x57,0x00,0x00,0x01,0x07,0x00,0x07,0x09}, + {0x58,0x00,0x00,0x01,0x00,0x00,0x09,0x0b}, + {0x59,0x00,0x00,0x01,0x04,0x00,0x05,0x05}, + {0x5c,0x00,0x00,0x01,0x00,0x00,0x09,0x0b}, + {0x5d,0x00,0x00,0x01,0x05,0x00,0x06,0x06}, + {0x5e,0x00,0x00,0x01,0x05,0x00,0x06,0x06}, + {0x5f,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x60,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x61,0x00,0x00,0x01,0x06,0x00,0x00,0x00}, + {0x62,0x00,0x00,0x01,0x05,0x00,0x06,0x08}, + {0x63,0x00,0x00,0x01,0x07,0x00,0x08,0x0a}, + {0x64,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c}, + {0x65,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x6c,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0x6d,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}, + {0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +}; + +static const struct SiS_CRT1Table SiS300_CRT1Table[] = +{ + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 0x00 - 320x200 */ + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, /* HRE [4],[15] is invalid - but correcting it does not work */ + 0x00}}, + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, /* 0x01 */ + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, /* HRE [4],[15] is invalid - but correcting it does not work */ + 0x00}}, + {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, /* 0x02 */ + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, + 0x01}}, + {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, + 0x01}}, + {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* 0x05 - corrected 640x480-60 */ + 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, + 0x00}}, + {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, /* 0x06 - corrected 640x480-72 */ + 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, + 0x00}}, + {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, + 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, + 0x00}}, + {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, + 0x00}}, + {{0x67,0x4f,0x4f,0x8b,0x57,0x83,0x10,0x3e, /* 0x09 - corrected 640x480-100 */ + 0xe7,0x8d,0xdf,0xe6,0x11,0x00,0x00,0x05, + 0x00}}, + {{0x67,0x4f,0x4f,0x8b,0x57,0x83,0x10,0x3e, /* 0x0a - corrected 640x480-120 */ + 0xe7,0x8d,0xdf,0xe6,0x11,0x00,0x00,0x05, + 0x00}}, + {{0x63,0x4f,0x4f,0x87,0x56,0x9d,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x01, + 0x00}}, + {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, + 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, /* Corrected VDE, VBE */ + 0x00}}, + {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, + 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, + 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, + 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, + 0x01}}, + {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, + 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, + 0x01}}, + {{0x8c,0x63,0x63,0x87,0x72,0x16,0x7e,0xf0, + 0x59,0x8d,0x57,0x57,0x7f,0x00,0x00,0x06, + 0x01}}, + {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0, + 0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06, + 0x01}}, + {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0, /* 0x14 */ + 0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06, + 0x01}}, + {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, + 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, + 0x00}}, + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, + 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, + 0x01}}, + {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, + 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, + 0x01}}, + {{0x9f,0x7f,0x7f,0x83,0x83,0x93,0x1e,0xf5, /* 0x1a */ + 0x00,0x84,0xff,0xff,0x1f,0x10,0x00,0x02, + 0x01}}, + {{0xa2,0x7f,0x7f,0x86,0x84,0x94,0x37,0xf5, + 0x0b,0x82,0xff,0xff,0x38,0x10,0x00,0x02, + 0x01}}, + {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, + 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, + 0x00}}, + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, /* 0x1e */ + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, + 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, + 0x01}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, /* 36: 1600x1200x85Hz */ + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, + {{0x3f,0xef,0xef,0x83,0xfd,0x1a,0xda,0x1f, /* 37: 1920x1440x60Hz */ + 0xa0,0x84,0x9f,0x9f,0xdb,0x1f,0x01,0x01, + 0x00}}, + {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, + 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, + 0x00}}, + {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, /* 0x27: 1280x960-60 - correct */ + 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, /* 0x28 */ + 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, + 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, + 0x01}}, + {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, + 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, + 0x01}}, + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, + 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, + 0x01}}, + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, + 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, + 0x01}}, + {{0xa7,0x7f,0x7f,0x88,0x89,0x15,0x26,0xf1, + 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, + 0x01}}, + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, + 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, + 0x01}}, + {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, /* 0x32: 720x576, corrected to 60Hz */ + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, /* 0x33 - 1024x600 */ + 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, + 0x01}}, + {{0xa3,0x8f,0x8f,0x97,0x96,0x97,0x24,0xf5, /* 0x34 - 1152x768 - corrected */ + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, /* 0x35 */ + 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, + 0x01}}, /* 0x35 */ + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, + 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, + 0x01}}, /* 0x36 */ + {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, + 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, + 0x01}}, /* 0x37 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, + 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, + 0x01}}, /* 0x38 */ + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, + 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, + 0x01}}, /* 0x39 */ + {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, /* 95 was 15 - illegal HBE! */ + 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, + 0x01}}, /* 0x3a */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x3b */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x3c */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, + 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, + 0x01}}, /* 0x3d */ + {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, /* 1152x864-75 */ + 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, + 0x01}}, /* 0x3e */ + {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, /* 848x480-38i */ + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x3f */ + {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, /* 848x480-60 */ + 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, + 0x00}}, /* 0x40 */ + {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, /* 856x480-38i */ + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x41 */ + {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, /* 856x480-60 */ + 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, + 0x00}}, /* 0x42 */ + {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, /* 1360x768-60 */ + 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, + 0x01}}, /* 0x43 */ + {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, /* 1152x864-84 */ + 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, + 0x01}}, /* 0x44 */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* 1280x960-85 */ + 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, + 0x01}}, /* 0x45 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, /* 1280x768-60 */ + 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, + 0x01}}, /* 0x46 */ + {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, /* 768x576, corrected to 60Hz */ + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, /* 0x47 */ + {{0xce,0xa9,0xa9,0x92,0xb1,0x07,0x28,0x52, /* 1360x1024 (Barco iQ Pro R300) */ + 0x02,0x8e,0xff,0x00,0x29,0x0d,0x00,0x03, + 0x00}}, /* 0x48 */ + {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, /* 1152x864-60 */ + 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, + 0x41}}, /* 0x49 */ + {{0x5c,0x4f,0x4f,0x80,0x57,0x80,0xa3,0x1f, /* fake 640x400@60Hz (for LCD and TV, not actually used) */ + 0x98,0x8c,0x8f,0x96,0xa4,0x30,0x00,0x05, + 0x40}}, /* 0x4a */ + {{0x2c,0x27,0x27,0x90,0x2d,0x92,0xa4,0x1f, /* fake 320x200@60Hz (for LCD and TV, not actually used) */ + 0x98,0x8c,0x8f,0x96,0xa5,0x30,0x00,0x04, + 0x00}} /* 0x4b */ +}; + +static const struct SiS_MCLKData SiS300_MCLKData_630[] = +{ + { 0x5a,0x64,0x80, 66}, + { 0xb3,0x45,0x80, 83}, + { 0x37,0x61,0x80,100}, + { 0x37,0x22,0x80,133}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100} +}; + +static const struct SiS_MCLKData SiS300_MCLKData_300[] = +{ + { 0x68,0x43,0x80,125}, + { 0x68,0x43,0x80,125}, + { 0x68,0x43,0x80,125}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100}, + { 0x37,0x61,0x80,100} +}; + +static struct SiS_VCLKData SiS300_VCLKData[] = +{ + { 0x1b,0xe1, 25}, /* 0x00 */ + { 0x4e,0xe4, 28}, /* 0x01 */ + { 0x57,0xe4, 32}, /* 0x02 */ + { 0xc3,0xc8, 36}, /* 0x03 */ + { 0x42,0xc3, 40}, /* 0x04 */ + { 0x5d,0xc4, 45}, /* 0x05 */ + { 0x52,0x65, 50}, /* 0x06 */ + { 0x53,0x65, 50}, /* 0x07 */ + { 0x6d,0x66, 56}, /* 0x08 */ + { 0x5a,0x64, 65}, /* 0x09 */ + { 0x46,0x44, 68}, /* 0x0a */ + { 0x3e,0x43, 75}, /* 0x0b */ + { 0x6d,0x46, 76}, /* 0x0c */ /* 800x600 | LVDS_2(CH), MITAC(CH); - 730, A901(301B): 0xb1,0x46, 76 */ + { 0x41,0x43, 79}, /* 0x0d */ + { 0x31,0x42, 79}, /* 0x0e */ + { 0x46,0x25, 85}, /* 0x0f */ + { 0x78,0x29, 87}, /* 0x10 */ + { 0x62,0x44, 95}, /* 0x11 */ + { 0x2b,0x22,105}, /* 0x12 */ + { 0x49,0x24,106}, /* 0x13 */ + { 0xc3,0x28,108}, /* 0x14 */ + { 0x3c,0x23,109}, /* 0x15 */ + { 0xf7,0x2c,132}, /* 0x16 */ + { 0xd4,0x28,136}, /* 0x17 */ + { 0x41,0x05,158}, /* 0x18 */ + { 0x43,0x05,162}, /* 0x19 */ + { 0xe1,0x0f,175}, /* 0x1a */ + { 0xfc,0x12,189}, /* 0x1b */ + { 0xde,0x26,194}, /* 0x1c */ + { 0x54,0x05,203}, /* 0x1d */ + { 0x3f,0x03,230}, /* 0x1e */ + { 0x30,0x02,234}, /* 0x1f */ + { 0x24,0x01,266}, /* 0x20 */ + { 0x52,0x2a, 54}, /* 0x21 */ /* 301 TV */ + { 0x52,0x6a, 27}, /* 0x22 */ /* 301 TV */ + { 0x62,0x24, 70}, /* 0x23 */ /* 301 TV */ + { 0x62,0x64, 70}, /* 0x24 */ /* 301 TV */ + { 0xa8,0x4c, 30}, /* 0x25 */ /* 301 TV */ + { 0x20,0x26, 33}, /* 0x26 */ /* 301 TV */ + { 0x31,0xc2, 39}, /* 0x27 */ + { 0xbf,0xc8, 35}, /* 0x28 */ /* 856x480 */ + { 0x60,0x36, 30}, /* 0x29 */ /* CH/UNTSC TEXT | LVDS_2(CH) - 730, A901(301B), Mitac(CH): 0xe0, 0xb6, 30 */ + { 0x40,0x4a, 28}, /* 0x2a */ /* CH-TV */ + { 0x9f,0x46, 44}, /* 0x2b */ /* CH-TV */ + { 0x97,0x2c, 26}, /* 0x2c */ /* CH-TV */ + { 0x44,0xe4, 25}, /* 0x2d */ /* CH-TV */ + { 0x7e,0x32, 47}, /* 0x2e */ /* CH-TV */ + { 0x8a,0x24, 31}, /* 0x2f */ /* CH/PAL TEXT | LVDS_2(CH), Mitac(CH) - 730, A901(301B): 0x57, 0xe4, 31 */ + { 0x97,0x2c, 26}, /* 0x30 */ /* CH-TV */ + { 0xce,0x3c, 39}, /* 0x31 */ /* CH-TV */ + { 0x52,0x4a, 36}, /* 0x32 */ /* CH/PAL 800x600 5/6 */ + { 0x34,0x61, 95}, /* 0x33 */ + { 0x78,0x27,108}, /* 0x34 */ /* Replacement for index 0x14 for 630 (?) */ + { 0x70,0x28, 90}, /* 0x35 */ /* 1152x864@60 */ + { 0x45,0x6b, 21}, /* 0x36 */ /* Chrontel SuperOverscan */ + { 0x52,0xe2, 49}, /* 0x37 */ /* 16:9 modes */ + { 0x2b,0x61, 78}, /* 0x38 */ /* 16:9 modes */ + { 0x70,0x44,108}, /* 0x39 */ /* 16:9 modes */ + { 0x54,0x42,135}, /* 0x3a */ /* 16:9 modes */ + { 0x41,0x22,157}, /* 0x3b */ /* 16:9 modes */ + { 0x52,0x07,149}, /* 0x3c */ /* 1280x960-85 */ + { 0x62,0xc6, 34}, /* 0x3d */ /* 848x480-60 */ + { 0x30,0x23, 88}, /* 0x3e */ /* 1360x768-60 */ + { 0x70,0x29, 81}, /* 0x3f */ /* 1280x768-60 */ + { 0x72,0x2a, 76}, /* 0x40 */ /* test for SiS730 --- LIMIT for table (&0x3f) */ + { 0x15,0x21, 79}, /* 0x41 */ /* test for SiS730 */ + { 0xa1,0x42,108}, /* 0x42 */ /* 1280x960 LCD */ + { 0x37,0x61,100}, /* 0x43 */ /* 1280x960 LCD */ + { 0xe3,0x9a,106}, /* 0x44 */ /* 1360x1024 - special for Barco iQ R300 */ + { 0xe2,0x46,135}, /* 0x45 */ /* 1280x1024-75, better clock for VGA2 */ + { 0x70,0x29, 81}, /* 0x46 */ /* unused */ + { 0, 0, 0}, /* 0x47 custom (will be filled out) */ + { 0xce,0x25,189}, /* 0x48 */ /* Replacement for index 0x1b for 730 (and 540?) */ + { 0x15,0xe1, 20}, /* 0x49 */ /* 640x400@60 (fake, not actually used) */ + { 0x5f,0xc6, 33}, /* 0x4a */ /* 720x576@60 */ + { 0x37,0x5a, 10}, /* 0x4b */ /* 320x200@60 (fake, not actually used) */ + { 0x2b,0xc2, 35} /* 0x4c */ /* 768@576@60 */ +}; + +static const unsigned char SiS300_SR15[4 * 8] = +{ + 0x01,0x09,0xa3,0x00, + 0x43,0x43,0x43,0x00, + 0x1e,0x1e,0x1e,0x00, + 0x2a,0x2a,0x2a,0x00, + 0x06,0x06,0x06,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 +}; + +static const struct SiS_PanelDelayTbl SiS300_PanelDelayTbl[] = +{ + {{0x05,0xaa}}, + {{0x05,0x14}}, + {{0x05,0x36}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x90}}, + {{0x05,0x90}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x05,0x14}}, + {{0x20,0x80}}, + {{0x05,0x14}}, + {{0x05,0x40}}, + {{0x05,0x60}} +}; + +/**************************************************************/ +/* SIS VIDEO BRIDGE ----------------------------------------- */ +/**************************************************************/ + +static const struct SiS_LCDData SiS300_St2LCD1024x768Data[] = +{ + { 62, 25, 800, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 104, 45, 945, 496,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 31, 18,1008, 624,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +static const struct SiS_LCDData SiS300_ExtLCD1024x768Data[] = +{ + { 12, 5, 896, 512,1344, 806}, + { 12, 5, 896, 510,1344, 806}, + { 32, 15,1008, 505,1344, 806}, + { 32, 15,1008, 514,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +static const struct SiS_LCDData SiS300_St2LCD1280x1024Data[] = +{ + { 22, 5, 800, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 13, 5,1024, 675,1560,1152}, + { 16, 9,1266, 804,1688,1072}, + { 1, 1,1688,1066,1688,1066} +}; + +static const struct SiS_LCDData SiS300_ExtLCD1280x1024Data[] = +{ + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 500,1688,1066}, + { 211, 75,1024, 625,1688,1066}, + { 211, 120,1280, 798,1688,1066}, + { 1, 1,1688,1066,1688,1066} +}; + +static const struct SiS_Part2PortTbl SiS300_CRT2Part2_1024x768_1[] = +{ /* VESA Timing */ + {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}} +}; + +static const struct SiS_Part2PortTbl SiS300_CRT2Part2_1024x768_2[] = +{ /* Non-VESA */ + {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x28,0x13,0xe7,0x0b,0xe8,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x38,0x18,0x16,0x00,0x00,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}} +}; + +static const struct SiS_Part2PortTbl SiS300_CRT2Part2_1024x768_3[] = +{ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} +}; + +/**************************************************************/ +/* LVDS/Chrontel -------------------------------------------- */ +/**************************************************************/ + +/* Custom data for Barco iQ R series */ +static const struct SiS_LVDSData SiS300_LVDSBARCO1366Data_1[]= +{ + { 832, 438,1331, 806}, + { 832, 388,1331, 806}, + { 832, 438,1331, 806}, + { 832, 388,1331, 806}, + { 832, 518,1331, 806}, + {1050, 638,1344, 806}, + {1344, 806,1344, 806}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066} /* 1360x1024 */ +}; + +/* Custom data for Barco iQ R series */ +static const struct SiS_LVDSData SiS300_LVDSBARCO1366Data_2[]= +{ + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066} /* 1360x1024 */ +}; + +/* Custom data for Barco iQ G series */ +static const struct SiS_LVDSData SiS300_LVDSBARCO1024Data_1[]= +{ + { 832, 438,1331, 806}, + { 832, 409,1331, 806}, + { 832, 438,1331, 806}, + { 832, 409,1331, 806}, + { 832, 518,1331, 806}, /* 640x480 */ + {1050, 638,1344, 806}, /* 800x600 */ + {1344, 806,1344, 806}, /* 1024x768 */ +}; + +/* Custom data for 848x480 and 856x480 parallel LVDS panels */ +static const struct SiS_LVDSData SiS300_LVDS848x480Data_1[]= +{ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 640x480 TODO */ + {1088, 525,1088, 525}, /* 800x600 TODO */ + {1088, 525,1088, 525}, /* 1024x768 TODO */ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 848x480 */ + {1088, 525,1088, 525}, /* 856x480 */ + {1088, 525,1088, 525} /* 1360x768 TODO */ +}; + +/* Custom data for 848x480 parallel panel */ +static const struct SiS_LVDSData SiS300_LVDS848x480Data_2[]= +{ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 640x480 */ + {1088, 525,1088, 525}, /* 800x600 */ + {1088, 525,1088, 525}, /* 1024x768 */ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 848x480 */ + {1088, 525,1088, 525}, /* 856x480 */ + {1088, 525,1088, 525} /* 1360x768 TODO */ +}; + +static const struct SiS_LVDSData SiS300_CHTVUPALData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 750, 840, 750}, + { 936, 836, 936, 836} +}; + +static const struct SiS_LVDSData SiS300_CHTVOPALData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 960, 750, 960, 750} +}; + +static const struct SiS_LVDSData SiS300_CHTVSOPALData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 500, 840, 500}, + { 944, 625, 944, 625} +}; + +/* Custom des data for Barco iQ R200/300/400 (BIOS 2.00.07) */ +static const struct SiS_LVDSDes SiS300_PanelType04_1a[] = /* 1280x1024 (1366x1024) */ +{ + {1330, 798}, /* 320x200 */ + {1330, 794}, + {1330, 798}, + {1330, 794}, + {1330, 0}, /* 640x480 / 320x240 */ + {1343, 0}, /* 800x600 / 400x300 */ + { 0, 805}, /* 1024x768 / 512x384 */ + {1688,1066}, /* 1280x1024 */ + { 0, 0} /* 1360x1024 */ +}; + +static const struct SiS_LVDSDes SiS300_PanelType04_2a[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805}, + {1688,1066}, + { 0, 0} +}; + +/* Custom des data for Barco iQ G200/300/400 (BIOS 2.00.07) */ +static const struct SiS_LVDSDes SiS300_PanelType04_1b[] = /* 1024x768 */ +{ + {1330, 798}, /* 320x200 */ + {1330, 794}, + {1330, 798}, + {1330, 794}, + {1330, 0}, /* 640x480 / 320x240 */ + {1343, 0}, /* 800x600 / 400x300 */ + { 0, 805} /* 1024x768 / 512x384 */ +}; + +static const struct SiS_LVDSDes SiS300_PanelType04_2b[] = +{ + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + { 0, 805} +}; + +/* CRT1 CRTC for slave modes */ + +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1UNTSC[] = +{ + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x5d,0x4f,0x81,0x53,0x9c,0x56,0xba, + 0x18,0x84,0xdf,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x80,0x63,0x84,0x6c,0x17,0xec,0xf0, + 0x90,0x8c,0x57,0xed,0x20,0x00,0x06, + 0x01 }} +}; + +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1ONTSC[] = +{ + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x5d,0x4f,0x81,0x56,0x9c,0x0b,0x3e, + 0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x7d,0x63,0x81,0x6a,0x16,0xba,0xf0, + 0x7f,0x86,0x57,0xbb,0x00,0x00,0x06, + 0x01 }} +}; + +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1UPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x55,0x80,0xec,0xba, + 0x50,0x84,0xdf,0xed,0x00,0x00,0x05, + 0x00 }}, + {{0x70,0x63,0x94,0x68,0x8d,0x42,0xf1, + 0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05, + 0x01 }} +}; + +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1OPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba, + 0x20,0x83,0xdf,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0, + 0x90,0x8c,0x57,0xed,0x20,0x00,0x05, + 0x01 }} +}; + +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1SOPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba, /* TODO */ + 0x20,0x83,0xdf,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0, /* TODO */ + 0x90,0x8c,0x57,0xed,0x20,0x00,0x05, + 0x01 }} +}; + +static const struct SiS_CHTVRegData SiS300_CHTVReg_UNTSC[] = +{ + {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x6a,0x6a,0x00,0x2d,0xfa,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 17: 640x480 NTSC 7/8 */ + {{0x8d,0xc4,0x00,0x3b,0xfb,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 24: 800x600 NTSC 7/10 */ +}; + +static const struct SiS_CHTVRegData SiS300_CHTVReg_ONTSC[] = +{ + {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x69,0x6a,0x00,0x1e,0xfd,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 16: 640x480 NTSC 1/1 */ + {{0x8c,0xb4,0x00,0x32,0xf9,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 23: 800x600 NTSC 3/4 */ +}; + +static const struct SiS_CHTVRegData SiS300_CHTVReg_UPAL[] = +{ + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x63,0x94,0x01,0x50,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 15: 640x480 PAL 5/6 */ + {{0x84,0x64,0x01,0x4e,0x2f,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 21: 800x600 PAL 3/4 */ + +}; + +static const struct SiS_CHTVRegData SiS300_CHTVReg_OPAL[] = +{ + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */ + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x61,0x94,0x01,0x36,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 14: 640x480 PAL 1/1 */ + {{0x83,0x76,0x01,0x40,0x31,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 20: 800x600 PAL 5/6 */ + +}; + +static const struct SiS_CHTVRegData SiS300_CHTVReg_SOPAL[] = +{ + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */ + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, + {{0x60,0x30,0x00,0x10,0x00,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 13: 640x480 PAL 5/4 */ + {{0x81,0x50,0x00,0x1b,0x00,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 19: 800x600 PAL 1/1 */ +}; + +static const unsigned char SiS300_CHTVVCLKUNTSC[] = { 0x29,0x29,0x29,0x29,0x2a,0x2e }; + +static const unsigned char SiS300_CHTVVCLKONTSC[] = { 0x2c,0x2c,0x2c,0x2c,0x2d,0x2b }; + +static const unsigned char SiS300_CHTVVCLKSONTSC[] = { 0x2c,0x2c,0x2c,0x2c,0x2d,0x2b }; + +static const unsigned char SiS300_CHTVVCLKUPAL[] = { 0x2f,0x2f,0x2f,0x2f,0x2f,0x31 }; + +static const unsigned char SiS300_CHTVVCLKOPAL[] = { 0x2f,0x2f,0x2f,0x2f,0x30,0x32 }; + +static const unsigned char SiS300_CHTVVCLKSOPAL[] = { 0x2f,0x2f,0x2f,0x2f,0x36,0x29 }; + + diff --git a/drivers/video/fbdev/sis/310vtbl.h b/drivers/video/fbdev/sis/310vtbl.h new file mode 100644 index 0000000..54fcbbf --- /dev/null +++ b/drivers/video/fbdev/sis/310vtbl.h @@ -0,0 +1,1339 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Register settings for SiS 315/330/340 series + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +static const struct SiS_Ext SiS310_EModeIDTable[] = +{ + {0x6a,0x2212,0x0102,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x? */ + {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */ + {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ + {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */ + {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ + {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */ + {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */ + {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */ + {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */ + {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */ + {0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x? */ + {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */ + {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x8 */ + {0x3c,0x0e3b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x8 */ + {0x3d,0x0e7d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x16 */ + {0x40,0x9a1c,0x010d,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x15 */ + {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x16 */ + {0x43,0x0a1c,0x0110,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, + {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */ + {0x46,0x2a1c,0x0113,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, + {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */ + {0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x07,0x13, 4}, + {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */ + {0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, + {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x16 */ + {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x8 */ + {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x8 */ + {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x8 */ + {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x16 */ + {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x16 */ + {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x16 */ + {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x8 */ + {0x5a,0x021b,0x0138,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x8 fstn */ + {0x5b,0x0a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x16 fstn */ + {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x32 */ + {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, + {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */ + {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */ + {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */ + {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */ + {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x32 */ + {0x66,0x0eff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x32 */ + {0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x8 */ + {0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x16 */ + {0x6b,0x07ff,0x0141,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x32 */ + {0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x8 */ + {0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x16 */ + {0x6e,0x07ff,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x32 */ + {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x8 */ + {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x8 */ + {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x16 */ + {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x16 */ + {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x32 */ + {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x32 */ + {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x32 */ + {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x8 */ + {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x16 */ + {0x7c,0x0e3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x8 */ + {0x7d,0x0e7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x16 */ + {0x7e,0x0eff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x32 */ + {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x8 */ + {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x16 */ + {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x32 */ + {0x26,0x0e3b,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x43, 9}, /* 1400x1050x8 */ + {0x27,0x0e7d,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x43, 9}, /* 1400x1050x16 */ + {0x28,0x0eff,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x43, 9}, /* 1400x1050x32*/ + {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x45,-1}, /* 1152x864 */ + {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x45,-1}, + {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x45,-1}, + {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x48,-1}, /* 848x480 */ + {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x48,-1}, + {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x48,-1}, + {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x4a,-1}, /* 856x480 */ + {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x4a,-1}, + {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x4a,-1}, + {0x48,0x6a3b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4c,-1}, /* 1360x768 */ + {0x4b,0x6a7d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4c,-1}, + {0x4e,0x6aff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4c,-1}, + {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x32 */ + {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x32 */ + {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x32 */ + {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4d,-1}, /* 768x576 */ + {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4d,-1}, + {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4d,-1}, + {0x14,0x0e3b,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4e, 7}, /* 1280x800 */ + {0x15,0x0e7d,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4e, 7}, + {0x16,0x0eff,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4e, 7}, + {0x17,0x0e3b,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x51, 9}, /* 1680x1050 */ + {0x18,0x0e7d,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x51, 9}, + {0x19,0x0eff,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x51, 9}, + {0x2c,0x267b,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x52,-1}, /* 1920x1080(i) */ + {0x2d,0x26fd,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x52,-1}, + {0x73,0x27ff,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x52,-1}, + {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x53,-1}, /* 960x540 */ + {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x53,-1}, + {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x53,-1}, + {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x54,-1}, /* 960x600 */ + {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x54,-1}, + {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x54,-1}, + {0x1a,0x0e3b,0x0000,SIS_RI_1280x854, 0x00,0x00,0x00,0x00,0x55, 8}, /* 1280x854 */ + {0x1b,0x0e7d,0x0000,SIS_RI_1280x854, 0x00,0x00,0x00,0x00,0x55, 8}, + {0x1c,0x0eff,0x0000,SIS_RI_1280x854, 0x00,0x00,0x00,0x00,0x55, 8}, + {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1} +}; + +static const struct SiS_Ext2 SiS310_RefIndex[] = +{ + {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x0 */ + {0x0067,0x0e,0x04,0x05,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1 */ + {0x0067,0x0f,0x08,0x48,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2 */ + {0x0067,0x10,0x07,0x8b,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x3 */ + {0x0047,0x11,0x0a,0x00,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4 */ + {0x0047,0x12,0x0d,0x00,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x5 */ + {0x0047,0x13,0x13,0x00,0x05,0x6a, 800, 600, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x6 */ + {0x0107,0x14,0x1c,0x00,0x05,0x6a, 800, 600, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x7 */ + {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x8 */ + {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x9 */ + {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xa */ + {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xb */ + {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xc */ + {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xd */ + {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xe */ + {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xf */ + {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e, 0x00, 0x00, 0x00, 0x00}, /* 0x10 */ + {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x11 */ + {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x12 (6f was 03) */ + {0x0087,0x15,0x06,0x00,0x06,0x37,1024, 768, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x13 */ + {0xc877,0x16,0x0b,0x06,0x06,0x37,1024, 768, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x14 */ + {0xc067,0x17,0x0f,0x49,0x06,0x37,1024, 768, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x15 */ + {0x0067,0x18,0x11,0x00,0x06,0x37,1024, 768, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x16 */ + {0x0047,0x19,0x16,0x8c,0x06,0x37,1024, 768, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x17 */ + {0x0107,0x1a,0x1b,0x00,0x06,0x37,1024, 768, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x18 */ + {0x0107,0x1b,0x1f,0x00,0x06,0x37,1024, 768, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x19 */ + {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1a */ + {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1b */ + {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1c */ + {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1d */ + {0x0227,0x20,0x21,0x09,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1e */ + {0x0407,0x21,0x22,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1f */ + {0x0407,0x22,0x23,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x20 */ + {0x0407,0x23,0x25,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x21 */ + {0x0007,0x24,0x26,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x22 */ + {0x0007,0x25,0x2c,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x23 */ + {0x0007,0x26,0x34,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x24 */ + {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0x30, 0x56, 0x4e, 0x00, 0x00, 0x00, 0x00}, /* 0x25 */ + {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x26 */ + {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x27 */ + {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x28 */ + {0x8007,0x27,0x27,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x29 */ + {0x4007,0x28,0x29,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2a */ + {0x4007,0x29,0x2e,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2b */ + {0x4007,0x2a,0x30,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2c */ + {0x4007,0x2b,0x35,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2d */ + {0x4005,0x2c,0x39,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2e */ + {0x4007,0x2d,0x2b,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2f */ + {0x4007,0x2e,0x31,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x30 */ + {0x4007,0x2f,0x33,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x31 */ + {0x4007,0x30,0x37,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x32 */ + {0x4005,0x31,0x38,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x33 */ + {0x2077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00, 0x32, 0x40, 0x5e, 0x73}, /* 0x34 */ + {0x2047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00, 0x33, 0x07, 0xff, 0xff}, /* 0x35 */ + {0x2047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00, 0x34, 0x0a, 0xff, 0xff}, /* 0x36 */ + {0x2077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00, 0x35, 0x0b, 0x5f, 0x74}, /* 0x37 */ + {0x2047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00, 0x36, 0x11, 0xff, 0xff}, /* 0x38 */ + {0x2047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00, 0x37, 0x16, 0xff, 0xff}, /* 0x39 */ + {0x3137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00, 0x38, 0x19, 0x60, 0x75}, /* 0x3a */ + {0x3107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00, 0x39, 0x1e, 0xff, 0xff}, /* 0x3b */ + {0x3307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00, 0x3a, 0x20, 0xff, 0xff}, /* 0x3c */ + {0x0127,0x3b,0x19,0x08,0x0a,0x7c,1280, 960, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x3d */ + {0x0227,0x4c,0x59,0x08,0x0a,0x7c,1280, 960, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x3e */ + {0xc07f,0x4e,0x00,0x06,0x04,0x5a, 320, 240, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x3f */ /* FSTN 320x240 */ + {0x2077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00, 0x58, 0x19, 0x42, 0x5b}, /* 0x40 */ /* 0x5b was 0x12 */ + {0x2077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00, 0x59, 0x1e, 0xff, 0xff}, /* 0x41 */ + {0x2077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00, 0x5a, 0x20, 0xff, 0xff}, /* 0x42 */ + {0x0127,0x43,0x4d,0x08,0x0b,0x26,1400,1050, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x43 */ + {0x0207,0x4b,0x5a,0x08,0x0b,0x26,1400,1050, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x44 1400x1050-75Hz */ + {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x45 1152x864-60Hz */ + {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x46 1152x864-75Hz */ + {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x47 1152x864-85Hz */ + {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x48 848x480-38Hzi */ + {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x49 848x480-60Hz */ + {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4a 856x480-38Hzi */ + {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4b 856x480-60Hz */ + {0x0067,0x49,0x58,0x0c,0x1b,0x48,1360, 768, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4c 1360x768-60Hz */ + {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4d 768x576-56Hz */ + {0x2067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30, 0x00, 0x00, 0x5b, 0x19, 0x4f, 0x5c}, /* 0x4e 1280x800-60Hz */ + {0x2067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30, 0x00, 0x00, 0x5c, 0x1e, 0xff, 0xff}, /* 0x4f 1280x800-75Hz */ + {0x2067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30, 0x00, 0x00, 0x5d, 0x20, 0xff, 0xff}, /* 0x50 1280x800-85Hz */ + {0x0067,0x50,0x5d,0x0c,0x0e,0x17,1680,1050, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x51 1680x1050-60Hz */ + {0x0087,0x51,0x69,0x00,0x00,0x2c,1920,1080, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x52 1920x1080 60Hzi */ + {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x53 960x540 60Hz */ + {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x54 960x600 60Hz */ + {0x2067,0x61,0x76,0x0d,0x22,0x1a,1280, 854, 0x30, 0x00, 0x00, 0x62, 0x19, 0x61, 0x76}, /* 0x55 1280x854-60Hz */ + {0x2067,0x61,0x76,0x0d,0x22,0x1a,1280, 854, 0x30, 0x00, 0x00, 0x63, 0x1e, 0xff, 0xff}, /* 0x56 1280x854-75Hz */ + {0x2067,0x61,0x76,0x0d,0x22,0x1a,1280, 854, 0x30, 0x00, 0x00, 0x64, 0x20, 0xff, 0xff}, /* 0x57 1280x854-85Hz */ + {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +static const struct SiS_CRT1Table SiS310_CRT1Table[] = +{ + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, /* 0x0 */ + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, + 0x00}}, /* 0x1 */ + {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, + 0x01}}, /* 0x2 */ + {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, + 0x01}}, /* 0x3 */ + {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, /* 0x4 */ + {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* corrected 640x480-60 */ + 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, + 0x00}}, /* 0x5 */ + {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, /* corrected 640x480-72 */ + 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, + 0x00}}, /* 0x6 */ + {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, + 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, + 0x00}}, /* 0x7 */ + {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, + 0x00}}, /* 0x8 */ + {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, /* Corrected VBE */ + 0x61}}, /* 0x9 */ + {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, + 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, + 0x61}}, /* 0xa */ + {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, + 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, /* Corrected VBE */ + 0x61}}, /* 0xb */ + {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, + 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, /* Corrected VDE, VBE */ + 0x00}}, /* 0xc */ + {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, + 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, + 0x01}}, /* 0xd */ + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, + 0x01}}, /* 0xe */ + {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, + 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, + 0x01}}, /* 0xf */ + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, + 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, + 0x01}}, /* 0x10 */ + {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, + 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, + 0x01}}, /* 0x11 */ + {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0, + 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06, + 0x61}}, /* 0x12 */ + {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0, + 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06, + 0x61}}, /* 0x13 */ + {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0, + 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06, + 0x61}}, /* 0x14 */ + {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, + 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, + 0x00}}, /* 0x15 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, /* 0x16 */ + {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, /* 0x17 */ + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, + 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, + 0x01}}, /* 0x18 */ + {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, + 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, + 0x01}}, /* 0x19 */ + {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5, + 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02, + 0x62}}, /* 0x1a */ + {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5, + 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02, + 0x62}}, /* 0x1b */ + {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, + 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, + 0x00}}, /* 0x1c */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, /* 0x1d */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, /* 0x1e */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, + 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, + 0x01}}, /* 0x1f */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x20 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x21 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x22 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x23 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x24 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x25 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x26 */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x27 */ + {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f, + 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05, + 0x63}}, /* 0x28 */ + {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f, + 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05, + 0x63}}, /* 0x29 */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x2a */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x2b */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x2c */ + {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba, + 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05, + 0x44}}, /* 0x2d */ + {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba, + 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05, + 0x44}}, /* 0x2e */ + {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba, + 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05, + 0x44}}, /* 0x2f */ + {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba, + 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05, + 0x44}}, /* 0x30 */ + {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, + 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, + 0x00}}, /* 0x31 */ + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, + 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, + 0x01}}, /* 0x32 */ + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, + 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, + 0x01}}, /* 0x33 */ + {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, + 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, + 0x01}}, /* 0x34 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, + 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, + 0x01}}, /* 0x35 */ + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, + 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, + 0x01}}, /* 0x36 */ + {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, /* 95 was 15 - illegal HBE! */ + 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, + 0x01}}, /* 0x37 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x38 */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x39 */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, + 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, + 0x01}}, /* 0x3a */ + {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, /* 1280x960-60 - corrected */ + 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, + 0x01}}, /* 0x3b */ + {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, /* 0x3c */ + {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, /* 720x576, corrected to 60Hz */ + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, /* 0x3d */ + {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15, + 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02, + 0x00}}, /* 0x3e */ + {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, + 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, + 0x00}}, /* 0x3f */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, + 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, + 0x01}}, /* 0x40 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, /* 0x41 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, + 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, + 0x01}}, /* 0x42 */ + {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10, + 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03, + 0x00}}, /* 0x43 */ + {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, /* 1152x864-75 */ + 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, + 0x01}}, /* 0x44 */ + {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, /* 848x480-38i */ + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x45 */ + {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, /* 848x480-60 */ + 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, + 0x00}}, /* 0x46 */ + {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, /* 856x480-38i */ + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x47 */ + {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, /* 856x480-60 */ + 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, + 0x00}}, /* 0x48 */ + {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, /* 1360x768-60 */ + 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, + 0x01}}, /* 0x49 */ + {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, /* 1152x864-84 */ + 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, + 0x01}}, /* 0x4a */ + {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, /* 1400x1050-75 */ + 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03, + 0x00}}, /* 0x4b */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* 1280x960-85 */ + 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, + 0x01}}, /* 0x4c */ + {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, /* 768x576, corrected to 60Hz */ + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, /* 0x4d */ + {{0x5f,0x27,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* FSTN 320x240 (working) */ + 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, + 0x00}}, /* 0x4e */ + {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, /* 1280x800-60 */ + 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, + 0x21}}, /* 0x4f */ + {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, /* 1680x1050-60 */ + 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c, + 0x20}}, /* 0x50 */ + {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, /* 1920x1080-60i */ + 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00, + 0x61}}, /* 0x51 */ + {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, /* 960x540-60 */ + 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02, + 0x41}}, /* 0x52 */ + {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0, /* 960x600-60 */ + 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02, + 0x01}}, /* 0x53 */ + {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, /* 1152x864-60 */ + 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, + 0x41}}, /* 0x54 */ + {{0x5c,0x4f,0x4f,0x80,0x57,0x80,0xa3,0x1f, /* fake 640x400@60Hz (for LCD and TV, not actually used) */ + 0x98,0x8c,0x8f,0x96,0xa4,0x30,0x00,0x05, + 0x40}}, /* 0x55 */ + {{0x2c,0x27,0x27,0x90,0x2d,0x92,0xa4,0x1f, /* fake 320x200@60Hz (for LCD and TV, not actually used) */ + 0x98,0x8c,0x8f,0x96,0xa5,0x30,0x00,0x04, + 0x00}}, /* 0x56 */ + {{0xd7,0xc7,0xc7,0x9b,0xd1,0x15,0xd1,0x10, /* 1600x1200 for LCDA */ + 0xb2,0x86,0xaf,0xb0,0xd2,0x2f,0x00,0x03, + 0x00}}, /* 0x57 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xdc, /* 1280x768 (1280x1024) 60 Hz */ + 0x92,0x86,0xff,0x91,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x58 */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xdc, /* 1280x768 (1280x1024) 75 Hz */ + 0x92,0x86,0xff,0x91,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x59 */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xdc, /* 1280x768 (1280x1024) 85 Hz */ + 0x95,0x89,0xff,0x94,0x2f,0x21,0x00,0x07, + 0x01}}, /* 0x5a */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xde, /* 1280x800 (1280x1024) 60 Hz */ + 0xa2,0x86,0x1f,0xa1,0x29,0x01,0x00,0x07, + 0x01}}, /* 0x5b */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xde, /* 1280x800 (1280x1024) 75 Hz */ + 0xa2,0x86,0x1f,0xa1,0x29,0x01,0x00,0x07, + 0x01}}, /* 0x5c */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xde, /* 1280x800 (1280x1024) 85 Hz */ + 0xa5,0x89,0x1f,0xa4,0x2f,0x01,0x00,0x07, + 0x01}}, /* 0x5d */ + {{0x7f,0x63,0x63,0x83,0x6d,0x1d,0x0b,0x3e, /* 800x480 (wide) 60 Hz */ + 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x06, + 0x00}}, /* 0x5e */ + {{0xa0,0x7f,0x7f,0x84,0x85,0x97,0x52,0xf0, /* 1024x576 (wide) 60 Hz */ + 0x41,0x85,0x3f,0x40,0x53,0x00,0x00,0x02, + 0x01}}, /* 0x5f */ + {{0xc9,0x9f,0x9f,0x8d,0xb0,0x15,0xec,0xf0, /* 1280x720 (wide) 60 Hz */ + 0xd4,0x89,0xcf,0xd3,0xed,0x20,0x00,0x07, + 0x01}}, /* 0x60 */ + {{0xcb,0x9f,0x9f,0x8f,0xa5,0x13,0x5b,0xff, /* 1280x854-60 wide */ + 0x56,0x89,0x55,0x55,0x5c,0x30,0x00,0x07, + 0x01}}, /* 0x61 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xde, /* 1280x854 (1280x1024) 60 Hz */ + 0xbd,0x81,0x55,0xbc,0x29,0x01,0x00,0x07, + 0x41}}, /* 0x62 */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xde, /* 1280x854 (1280x1024) 75 Hz */ + 0xbd,0x81,0x55,0xbc,0x29,0x01,0x00,0x07, + 0x41}}, /* 0x63 */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xde, /* 1280x854 (1280x1024) 85 Hz */ + 0xc0,0x84,0x55,0xbf,0x2f,0x01,0x00,0x07, + 0x41}} /* 0x64 */ +}; + +static const struct SiS_MCLKData SiS310_MCLKData_0_315[] = +{ + { 0x3b,0x22,0x01,143}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166} +}; + +static const struct SiS_MCLKData SiS310_MCLKData_0_650[] = +{ + { 0x5a,0x64,0x82, 66}, + { 0xb3,0x45,0x82, 83}, + { 0x37,0x61,0x82,100}, + { 0x37,0x22,0x82,133}, + { 0x37,0x61,0x82,100}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133} +}; + +static const struct SiS_MCLKData SiS310_MCLKData_0_330[] = +{ + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x7c,0x08,0x01,200}, + { 0x79,0x06,0x01,250}, + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x01,200}, + { 0x79,0x06,0x01,250} +}; + +static const struct SiS_MCLKData SiS310_MCLKData_0_660[] = +{ + { 0x5c,0x23,0x82,166}, + { 0x5c,0x23,0x82,166}, + { 0x37,0x21,0x82,200}, + { 0x37,0x22,0x82,133}, + { 0x29,0x21,0x82,150}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x37,0x21,0x82,200} +}; + +static const struct SiS_MCLKData SiS310_MCLKData_0_760[] = +{ + { 0x37,0x22,0x82,133}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x7c,0x08,0x82,200}, + { 0x29,0x21,0x82,150}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x37,0x21,0x82,200} +}; + +static const struct SiS_MCLKData SiS310_MCLKData_0_761[] = +{ + { 0x37,0x22,0x82,133}, /* Preliminary */ + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x7c,0x08,0x82,200}, + { 0x29,0x21,0x82,150}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x37,0x21,0x82,200} +}; + +static const struct SiS_MCLKData SiS310_MCLKData_0_340[] = +{ + { 0x79,0x06,0x01,250}, + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x80,200}, + { 0x79,0x06,0x80,250}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300} +}; + +static const struct SiS_MCLKData SiS310_MCLKData_1[] = /* ECLK */ +{ + { 0x29,0x21,0x82,150}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x37,0x21,0x82,200}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133}, + { 0x37,0x22,0x82,133} +}; + +static const struct SiS_MCLKData SiS310_MCLKData_1_340[] = +{ + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x80,200}, + { 0x79,0x06,0x80,250}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300} +}; + +static struct SiS_VCLKData SiS310_VCLKData[] = +{ + { 0x1b,0xe1, 25}, /* 0x00 */ + { 0x4e,0xe4, 28}, /* 0x01 */ + { 0x57,0xe4, 31}, /* 0x02 */ + { 0xc3,0xc8, 36}, /* 0x03 */ + { 0x42,0xe2, 40}, /* 0x04 */ + { 0xfe,0xcd, 43}, /* 0x05 */ + { 0x5d,0xc4, 44}, /* 0x06 */ + { 0x52,0xe2, 49}, /* 0x07 */ + { 0x53,0xe2, 50}, /* 0x08 */ + { 0x74,0x67, 52}, /* 0x09 */ + { 0x6d,0x66, 56}, /* 0x0a */ + { 0x5a,0x64, 65}, /* 0x0b */ /* was 6c c3 - WRONG */ + { 0x46,0x44, 67}, /* 0x0c */ + { 0xb1,0x46, 68}, /* 0x0d */ + { 0xd3,0x4a, 72}, /* 0x0e */ + { 0x29,0x61, 75}, /* 0x0f */ + { 0x6e,0x46, 76}, /* 0x10 */ + { 0x2b,0x61, 78}, /* 0x11 */ + { 0x31,0x42, 79}, /* 0x12 */ + { 0xab,0x44, 83}, /* 0x13 */ + { 0x46,0x25, 84}, /* 0x14 */ + { 0x78,0x29, 86}, /* 0x15 */ + { 0x62,0x44, 94}, /* 0x16 */ + { 0x2b,0x41,104}, /* 0x17 */ + { 0x3a,0x23,105}, /* 0x18 */ + { 0x70,0x44,108}, /* 0x19 */ + { 0x3c,0x23,109}, /* 0x1a */ + { 0x5e,0x43,113}, /* 0x1b */ + { 0xbc,0x44,116}, /* 0x1c */ + { 0xe0,0x46,132}, /* 0x1d */ + { 0x54,0x42,135}, /* 0x1e */ + { 0xea,0x2a,139}, /* 0x1f */ + { 0x41,0x22,157}, /* 0x20 */ + { 0x70,0x24,162}, /* 0x21 */ + { 0x30,0x21,175}, /* 0x22 */ + { 0x4e,0x22,189}, /* 0x23 */ + { 0xde,0x26,194}, /* 0x24 */ + { 0x62,0x06,202}, /* 0x25 */ + { 0x3f,0x03,229}, /* 0x26 */ + { 0xb8,0x06,234}, /* 0x27 */ + { 0x34,0x02,253}, /* 0x28 */ + { 0x58,0x04,255}, /* 0x29 */ + { 0x24,0x01,265}, /* 0x2a */ + { 0x9b,0x02,267}, /* 0x2b */ + { 0x70,0x05,270}, /* 0x2c */ + { 0x25,0x01,272}, /* 0x2d */ + { 0x9c,0x02,277}, /* 0x2e */ + { 0x27,0x01,286}, /* 0x2f */ + { 0x3c,0x02,291}, /* 0x30 */ + { 0xef,0x0a,292}, /* 0x31 */ + { 0xf6,0x0a,310}, /* 0x32 */ + { 0x95,0x01,315}, /* 0x33 */ + { 0xf0,0x09,324}, /* 0x34 */ + { 0xfe,0x0a,331}, /* 0x35 */ + { 0xf3,0x09,332}, /* 0x36 */ + { 0xea,0x08,340}, /* 0x37 */ + { 0xe8,0x07,376}, /* 0x38 */ + { 0xde,0x06,389}, /* 0x39 */ + { 0x52,0x2a, 54}, /* 0x3a 301 TV */ + { 0x52,0x6a, 27}, /* 0x3b 301 TV */ + { 0x62,0x24, 70}, /* 0x3c 301 TV */ + { 0x62,0x64, 70}, /* 0x3d 301 TV */ + { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ + { 0x20,0x26, 33}, /* 0x3f 301 TV */ + { 0x31,0xc2, 39}, /* 0x40 */ + { 0x60,0x36, 30}, /* 0x41 Chrontel */ + { 0x40,0x4a, 28}, /* 0x42 Chrontel */ + { 0x9f,0x46, 44}, /* 0x43 Chrontel */ + { 0x97,0x2c, 26}, /* 0x44 */ + { 0x44,0xe4, 25}, /* 0x45 Chrontel */ + { 0x7e,0x32, 47}, /* 0x46 Chrontel */ + { 0x8a,0x24, 31}, /* 0x47 Chrontel */ + { 0x97,0x2c, 26}, /* 0x48 Chrontel */ + { 0xce,0x3c, 39}, /* 0x49 */ + { 0x52,0x4a, 36}, /* 0x4a Chrontel */ + { 0x34,0x61, 95}, /* 0x4b */ + { 0x78,0x27,108}, /* 0x4c - was 102 */ + { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ + { 0x41,0x4e, 21}, /* 0x4e */ + { 0xa1,0x4a, 29}, /* 0x4f Chrontel */ + { 0x19,0x42, 42}, /* 0x50 */ + { 0x54,0x46, 58}, /* 0x51 Chrontel */ + { 0x25,0x42, 61}, /* 0x52 */ + { 0x44,0x44, 66}, /* 0x53 Chrontel */ + { 0x3a,0x62, 70}, /* 0x54 Chrontel */ + { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ + { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ + { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + { 0x52,0x07,149}, /* 0x59 1280x960-85 */ + { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ + { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ + { 0x45,0x25, 83}, /* 0x5c 1280x800 */ + { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ + { 0x70,0x24,162}, /* 0x5e 1600x1200 */ + { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */ + { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ + { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ + { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ + { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ + { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ + { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ + { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ + { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ + { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ + { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ + { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ + { 0x45,0x25, 83}, /* 0x6c 1280x800 */ + { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ + { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ + { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + { 0x2b,0xc2, 35}, /* 0x71 768x576@60 */ + { 0xa8,0x42,131}, /* 0x72 1600x1200@60 for LCDA */ + { 0x1b,0xc1, 34}, /* 0x73 800x480 60Hz (wide) */ + { 0x41,0x64, 48}, /* 0x74 1024x576 60Hz (wide) */ + { 0x52,0x27, 75}, /* 0x75 1280x720 60Hz (wide) */ + { 0x75,0x13, 84} /* 0x76 1280x854 60Hz (wide) */ +}; + +static struct SiS_VBVCLKData SiS310_VBVCLKData[] = +{ + { 0x1b,0xe1, 25}, /* 0x00 */ + { 0x4e,0xe4, 28}, /* 0x01 */ + { 0x57,0xe4, 31}, /* 0x02 */ + { 0xc3,0xc8, 36}, /* 0x03 */ + { 0x42,0x47, 40}, /* 0x04 */ + { 0xfe,0xcd, 43}, /* 0x05 */ + { 0x5d,0xc4, 44}, /* 0x06 */ + { 0x52,0x47, 49}, /* 0x07 */ + { 0x53,0x47, 50}, /* 0x08 */ + { 0x74,0x67, 52}, /* 0x09 */ + { 0x6d,0x66, 56}, /* 0x0a */ + { 0x35,0x62, 65}, /* 0x0b */ /* Was 0x5a,0x64 - 650/LVDS+301: 35,62 */ + { 0x46,0x44, 67}, /* 0x0c */ + { 0xb1,0x46, 68}, /* 0x0d */ + { 0xd3,0x4a, 72}, /* 0x0e */ + { 0x29,0x61, 75}, /* 0x0f */ + { 0x6d,0x46, 75}, /* 0x10 */ + { 0x41,0x43, 78}, /* 0x11 */ + { 0x31,0x42, 79}, /* 0x12 */ + { 0xab,0x44, 83}, /* 0x13 */ + { 0x46,0x25, 84}, /* 0x14 */ + { 0x78,0x29, 86}, /* 0x15 */ + { 0x62,0x44, 94}, /* 0x16 */ + { 0x2b,0x22,104}, /* 0x17 */ + { 0x49,0x24,105}, /* 0x18 */ + { 0xf8,0x2f,108}, /* 0x19 */ /* 1400x1050 LCD */ + { 0x3c,0x23,109}, /* 0x1a */ + { 0x5e,0x43,113}, /* 0x1b */ + { 0xbc,0x44,116}, /* 0x1c */ + { 0xe0,0x46,132}, /* 0x1d */ + { 0xe2,0x46,135}, /* 0x1e */ /* 1280x1024-75, better clock for VGA2 */ + { 0xe5,0x46,139}, /* 0x1f */ /* 1024x768-120, better clock for VGA2 */ + { 0x15,0x01,157}, /* 0x20 */ /* 1280x1024-85, better clock for VGA2 */ + { 0x70,0x09,162}, /* 0x21 */ /* 1600x1200-60, better clock for VGA2 */ + { 0x30,0x21,175}, /* 0x22 */ + { 0x4e,0x22,189}, /* 0x23 */ + { 0xde,0x26,194}, /* 0x24 */ + { 0x70,0x07,202}, /* 0x25 */ + { 0x3f,0x03,229}, /* 0x26 */ + { 0xb8,0x06,234}, /* 0x27 */ + { 0x34,0x02,253}, /* 0x28 */ + { 0x58,0x04,255}, /* 0x29 */ + { 0x24,0x01,265}, /* 0x2a */ + { 0x9b,0x02,267}, /* 0x2b */ + { 0x70,0x05,270}, /* 0x2c */ + { 0x25,0x01,272}, /* 0x2d */ + { 0x9c,0x02,277}, /* 0x2e */ + { 0x27,0x01,286}, /* 0x2f */ + { 0x3c,0x02,291}, /* 0x30 */ + { 0xef,0x0a,292}, /* 0x31 */ + { 0xf6,0x0a,310}, /* 0x32 */ + { 0x95,0x01,315}, /* 0x33 */ + { 0xf0,0x09,324}, /* 0x34 */ + { 0xfe,0x0a,331}, /* 0x35 */ + { 0xf3,0x09,332}, /* 0x36 */ + { 0xea,0x08,340}, /* 0x37 */ + { 0xe8,0x07,376}, /* 0x38 */ + { 0xde,0x06,389}, /* 0x39 */ + { 0x52,0x2a, 54}, /* 0x3a 301 TV - start */ + { 0x52,0x6a, 27}, /* 0x3b 301 TV */ + { 0x62,0x24, 70}, /* 0x3c 301 TV */ + { 0x62,0x64, 70}, /* 0x3d 301 TV */ + { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ + { 0x20,0x26, 33}, /* 0x3f 301 TV */ + { 0x31,0xc2, 39}, /* 0x40 */ + { 0x2e,0x48, 25}, /* 0x41 Replacement for LCD on 315 for index 0 */ + { 0x24,0x46, 25}, /* 0x42 Replacement for LCD on 315 for modes 0x01, 0x03, 0x0f, 0x10, 0x12 */ + { 0x26,0x64, 28}, /* 0x43 Replacement for LCD on 315 for index 1 */ + { 0x37,0x64, 40}, /* 0x44 Replacement for LCD on 315 for index 4 */ + { 0xa1,0x42,108}, /* 0x45 1280x960 LCD */ + { 0x37,0x61,100}, /* 0x46 1280x960 LCD */ + { 0x78,0x27,108}, /* 0x47 */ + { 0x97,0x2c, 26}, /* 0x48 UNUSED */ + { 0xce,0x3c, 39}, /* 0x49 UNUSED */ + { 0x52,0x4a, 36}, /* 0x4a UNUSED */ + { 0x34,0x61, 95}, /* 0x4b UNUSED */ + { 0x78,0x27,108}, /* 0x4c UNUSED */ + { 0x66,0x43,123}, /* 0x4d 1400x1050-60 */ + { 0x41,0x4e, 21}, /* 0x4e */ + { 0xa1,0x4a, 29}, /* 0x4f UNUSED */ + { 0x19,0x42, 42}, /* 0x50 UNUSED */ + { 0x54,0x46, 58}, /* 0x51 UNUSED */ + { 0x25,0x42, 61}, /* 0x52 UNUSED */ + { 0x44,0x44, 66}, /* 0x53 UNUSED */ + { 0x3a,0x62, 70}, /* 0x54 UNUSED */ + { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ + { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP, UNUSED */ + { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ + { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) TEMP, UNUSED */ + { 0x52,0x07,149}, /* 0x59 1280x960-85 */ + { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ + { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD (TMDS) */ + { 0xce,0x1e, 73}, /* 0x5c 1280x800_2 LCD (SiS LVDS) - (CRT1: 45 25 83) */ + { 0xbe,0x44,121}, /* 0x5d 1680x1050 LCD */ + { 0x70,0x24,162}, /* 0x5e 1600x1200 LCD */ + { 0x52,0x27, 75}, /* 0x5f 1280x720 (TMDS + HDTV) (correct) */ + { 0xc8,0x48, 77}, /* 0x60 1280x768_2 (SiS LVDS) */ + { 0x31,0x42, 79}, /* 0x61 1280x768_3 (SiS LVDS) - temp */ + { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + { 0x9c,0x62, 69}, /* 0x63 1280x720 (SiS LVDS) */ + { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ + { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ + { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ + { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ + { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ + { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced (UNUSED) */ + { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ + { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ + { 0x9c,0x62, 69}, /* 0x6c 1280x800 (SiS TMDS) (special) */ + { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ + { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ + { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + { 0x2b,0xc2, 35}, /* 0x71 768@576@60 */ + { 0xa8,0x42,131}, /* 0x72 1600x1200@60 for LCDA */ + { 0x1b,0xc1, 34}, /* 0x73 800x480 60Hz (wide) */ + { 0x41,0x64, 48}, /* 0x74 1024x576 60Hz (wide) */ + { 0x52,0x27, 75}, /* 0x75 1280x720 60Hz (wide) */ + { 0x75,0x13, 84} /* 0x76 1280x854 60Hz (SiS LVDS) LCD */ +}; + +static const unsigned char SiS310_SR15[4 * 8] = +{ + 0x00,0x04,0x60,0x60, + 0x0f,0x0f,0x0f,0x0f, + 0xba,0xba,0xba,0xba, + 0xa9,0xa9,0xac,0xac, + 0xa0,0xa0,0xa0,0xa8, + 0x00,0x00,0x02,0x02, + 0x30,0x30,0x40,0x40, + 0x00,0xa5,0xfb,0xf6 +}; + +static const struct SiS_PanelDelayTbl SiS310_PanelDelayTbl[] = +{ + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}}, + {{0x10,0x40}} +}; + +static const struct SiS_PanelDelayTbl SiS310_PanelDelayTblLVDS[] = +{ + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}}, + {{0x28,0xc8}} +}; + +/**************************************************************/ +/* SIS VIDEO BRIDGE ----------------------------------------- */ +/**************************************************************/ + +static const struct SiS_LCDData SiS310_St2LCD1024x768Data[] = +{ + { 62, 25, 800, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 104, 45, 945, 496,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 31, 18,1008, 624,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +static const struct SiS_LCDData SiS310_ExtLCD1024x768Data[] = +{ + { 42, 25,1536, 419,1344, 806}, + { 48, 25,1536, 369,1344, 806}, + { 42, 25,1536, 419,1344, 806}, + { 48, 25,1536, 369,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +static const struct SiS_LCDData SiS310_St2LCD1280x1024Data[] = +{ + { 22, 5, 800, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 13, 5,1024, 675,1560,1152}, + { 16, 9,1266, 804,1688,1072}, + { 1, 1,1688,1066,1688,1066} +}; + +static const struct SiS_LCDData SiS310_ExtLCD1280x1024Data[] = +{ + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 500,1688,1066}, + { 211, 75,1024, 625,1688,1066}, + { 211, 120,1280, 798,1688,1066}, + { 1, 1,1688,1066,1688,1066} +}; + +static const struct SiS_Part2PortTbl SiS310_CRT2Part2_1024x768_1[] = +{ + {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x38,0x13,0x16,0x0c,0xe6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} +}; + +/**************************************************************/ +/* LVDS, CHRONTEL ------------------------------------------- */ +/**************************************************************/ + +static const struct SiS_LVDSData SiS310_CHTVUPALData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 960, 750, 960, 750}, + {1400,1000,1400,1000} +}; + +static const struct SiS_LVDSData SiS310_CHTVOPALData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 944, 625, 944, 625}, + {1400, 875,1400, 875} +}; + +static const struct SiS_LVDSData SiS310_CHTVUPALMData[] = +{ + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 784, 600, 784, 600}, + {1064, 750,1064, 750}, + {1160, 945,1160, 945} +}; + +static const struct SiS_LVDSData SiS310_CHTVOPALMData[] = +{ + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 784, 525, 784, 525}, + {1040, 700,1040, 700}, + {1160, 840,1160, 840} +}; + +static const struct SiS_LVDSData SiS310_CHTVUPALNData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 960, 750, 960, 750}, + {1400,1000,1400,1000} +}; + +static const struct SiS_LVDSData SiS310_CHTVOPALNData[] = +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 944, 625, 944, 625}, + {1400, 875,1400, 875} +}; + +static const struct SiS_LVDSData SiS310_CHTVSOPALData[] = /* (super overscan - no effect on 7019) */ +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + { 840, 625, 840, 625}, + { 944, 625, 944, 625}, + {1400, 875,1400, 875} +}; + +/* CRT1 CRTC for Chrontel TV slave modes */ + +static const struct SiS_LVDSCRT1Data SiS310_CHTVCRT1UNTSC[] = +{ + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, + 0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x5d,0x4f,0x81,0x56,0x99,0x56,0xba, + 0x0a,0x84,0xdf,0x57,0x00,0x00,0x01, + 0x00 }}, + {{0x80,0x63,0x84,0x6d,0x0f,0xec,0xf0, + 0x7a,0x8f,0x57,0xed,0x20,0x00,0x06, + 0x01 }}, + {{0x8c,0x7f,0x90,0x86,0x09,0xaf,0xf5, + 0x36,0x88,0xff,0xb0,0x10,0x00,0x02, + 0x01}} +}; + +static const struct SiS_LVDSCRT1Data SiS310_CHTVCRT1ONTSC[] = +{ + {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, + 0x00 }}, + {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x5d,0x4f,0x81,0x58,0x9d,0x0b,0x3e, + 0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01, + 0x00 }}, + {{0x7d,0x63,0x81,0x68,0x0e,0xba,0xf0, + 0x78,0x8a,0x57,0xbb,0x20,0x00,0x06, + 0x01 }}, + {{0x8c,0x7f,0x90,0x82,0x06,0x46,0xf5, + 0x15,0x88,0xff,0x47,0x70,0x00,0x02, + 0x01 }} +}; + +static const struct SiS_LVDSCRT1Data SiS310_CHTVCRT1UPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x6f,0xba, + 0x15,0x83,0xdf,0x70,0x00,0x00,0x01, + 0x00 }}, + {{0x73,0x63,0x97,0x69,0x8b,0xec,0xf0, + 0x90,0x8c,0x57,0xed,0x20,0x00,0x05, + 0x01 }}, + {{0xaa,0x7f,0x8e,0x8e,0x96,0xe6,0xf5, + 0x50,0x88,0xff,0xe7,0x10,0x00,0x02, + 0x01}} +}; + +static const struct SiS_LVDSCRT1Data SiS310_CHTVCRT1OPAL[] = +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, + 0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05, + 0x00 }}, + {{0x64,0x4f,0x88,0x58,0x9d,0x6f,0xba, + 0x15,0x83,0xdf,0x70,0x00,0x00,0x01, + 0x00 }}, + {{0x71,0x63,0x95,0x69,0x8c,0x6f,0xf0, + 0x5a,0x8b,0x57,0x70,0x20,0x00,0x05, + 0x01 }}, + {{0xaa,0x7f,0x8e,0x8f,0x96,0x69,0xf5, + 0x28,0x88,0xff,0x6a,0x10,0x00,0x02, + 0x01 }} +}; + +static const struct SiS_CHTVRegData SiS310_CHTVReg_UNTSC[] = +{ + {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x6a,0x77,0xbb,0x6e,0x84,0x2e,0x02,0x5a,0x04,0x00,0x80,0x20,0x7e,0x80,0x98,0x00}}, + {{0xcf,0x77,0xb7,0xc8,0x84,0x3b,0x02,0x5a,0x04,0x00,0x80,0x19,0x88,0x30,0x7f,0x00}}, + {{0xee,0x77,0xbb,0x66,0x87,0x32,0x01,0x5a,0x04,0x00,0x80,0x1b,0xd3,0xf2,0x36,0x00}} +}; /* WRONG: 0x02: should be 0xfx, because if CIVEnable is clear, this should be set; + 0x07: Blacklevel: NTSC/PAL-M: Should be 131 (0x83), and not 0x50/0x5a + PAL/PAL-N: 110 (0x6e) + NTSC-J: 102 (0x66) + 0x0c-0x0f: CIV is not default as in datasheet + MISSING: 0x21: Should set D1 to ZERO (for NTSC, PAL-M) or ONE (PAL, NTSC-J) + Most of this is wrong in all NTSC and PAL register arrays. But I won't correct + it as long as it works. For NTSC-J, the blacklevel is corrected in init301.c; + for PAL-M and PAL-N all above is corrected. + */ + +static const struct SiS_CHTVRegData SiS310_CHTVReg_ONTSC[] = +{ + {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x69,0x77,0xbb,0x6e,0x84,0x1e,0x00,0x5a,0x04,0x00,0x80,0x25,0x1a,0x43,0x04,0x00}}, + {{0xce,0x77,0xb7,0xb6,0x83,0x2c,0x02,0x5a,0x04,0x00,0x80,0x1c,0x00,0x82,0x97,0x00}}, + {{0xed,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x9f,0xc1,0x0c,0x00}} +}; + +static const struct SiS_CHTVRegData SiS310_CHTVReg_UPAL[] = +{ + {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x12,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}}, + {{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x5a,0x05,0x00,0x80,0x1f,0x84,0x3d,0x28,0x00}}, + {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x20,0x3e,0xe4,0x22,0x00}} +}; + +static const struct SiS_CHTVRegData SiS310_CHTVReg_OPAL[] = +{ + {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}}, + {{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x5a,0x05,0x00,0x80,0x26,0x78,0x19,0x34,0x00}}, + {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x25,0x8c,0xb2,0x2a,0x00}} +}; + +static const struct SiS_CHTVRegData SiS310_CHTVReg_UPALM[] = +{ + {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x72,0x77,0xfb,0x6e,0x84,0x2e,0x02,0x83,0x04,0x00,0x80,0x20,0x76,0xdb,0x6e,0x00}}, + {{0xd7,0x77,0xf7,0xc8,0x84,0x3b,0x02,0x83,0x04,0x00,0x80,0x19,0x84,0x0a,0xc7,0x00}}, + {{0xf6,0x77,0xfb,0x66,0x87,0x32,0x01,0x83,0x04,0x00,0x80,0x1b,0xdc,0xb0,0x8d,0x00}} +#if 0 /* Correct blacklevel and CFRB */ + {{0x72,0x77,0xbb,0x6e,0x84,0x2e,0x02,0x5a,0x04,0x00,0x80,0x20,0x76,0xdb,0x6e,0x00}}, + {{0xd7,0x77,0xb7,0xc8,0x84,0x3b,0x02,0x5a,0x04,0x00,0x80,0x19,0x84,0x0a,0xc7,0x00}}, + {{0xf6,0x77,0xbb,0x66,0x87,0x32,0x01,0x5a,0x04,0x00,0x80,0x1b,0xdc,0xb0,0x8d,0x00}} +#endif +}; + +static const struct SiS_CHTVRegData SiS310_CHTVReg_OPALM[] = +{ + {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, + {{0x71,0x77,0xfb,0x6e,0x84,0x1e,0x00,0x83,0x04,0x00,0x80,0x25,0x1a,0x1f,0x59,0x00}}, + {{0xd6,0x77,0xf7,0xb6,0x83,0x2c,0x02,0x83,0x04,0x00,0x80,0x1b,0xf8,0x1f,0x82,0x00}}, + {{0xf5,0x77,0xfb,0x66,0x8c,0x21,0x02,0x83,0x04,0x00,0x80,0x1f,0x58,0x46,0x9f,0x00}} +#if 0 /* Correct blacklevel and CFRB */ + {{0x71,0x77,0xbb,0x6e,0x84,0x1e,0x00,0x5a,0x04,0x00,0x80,0x25,0x1a,0x1f,0x59,0x00}}, + {{0xd6,0x77,0xb7,0xb6,0x83,0x2c,0x02,0x5a,0x04,0x00,0x80,0x1b,0xf8,0x1f,0x82,0x00}}, + {{0xf5,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x58,0x46,0x9f,0x00}} +#endif +}; + +static const struct SiS_CHTVRegData SiS310_CHTVReg_UPALN[] = +{ + {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x12,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}} +#if 0 /* Correct blacklevel, CIV and CFRB */ + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x1f,0x0d,0x54,0x5e,0x00}}, + {{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x5a,0x05,0x00,0x80,0x19,0x78,0xef,0x35,0x00}}, + {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x1a,0x33,0x3f,0x2f,0x00}} +#endif +}; + +static const struct SiS_CHTVRegData SiS310_CHTVReg_OPALN[] = +{ + {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, + {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}} +#if 0 /* Correct blacklevel, CIV and CFRB */ + {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x1f,0x0d,0x54,0x5e,0x00}}, + {{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x5a,0x05,0x00,0x80,0x1f,0x15,0xc0,0x1e,0x00}}, + {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x1d,0xf1,0x6c,0xcb,0x00}} +#endif +}; + +static const unsigned char SiS310_CHTVVCLKUNTSC[] = { 0x41,0x41,0x41,0x41,0x42,0x46,0x53 }; +static const unsigned char SiS310_CHTVVCLKONTSC[] = { 0x48,0x48,0x48,0x48,0x45,0x43,0x51 }; + +static const unsigned char SiS310_CHTVVCLKUPAL[] = { 0x47,0x47,0x47,0x47,0x48,0x4a,0x54 }; +static const unsigned char SiS310_CHTVVCLKOPAL[] = { 0x47,0x47,0x47,0x47,0x48,0x4f,0x52 }; + +static const unsigned char SiS310_CHTVVCLKUPALM[] = { 0x41,0x41,0x41,0x41,0x42,0x46,0x53 }; +static const unsigned char SiS310_CHTVVCLKOPALM[] = { 0x48,0x48,0x48,0x48,0x45,0x43,0x51 }; + +static const unsigned char SiS310_CHTVVCLKUPALN[] = { 0x47,0x47,0x47,0x47,0x48,0x4a,0x54 }; +static const unsigned char SiS310_CHTVVCLKOPALN[] = { 0x47,0x47,0x47,0x47,0x48,0x4f,0x52 }; + + diff --git a/drivers/video/fbdev/sis/Makefile b/drivers/video/fbdev/sis/Makefile new file mode 100644 index 0000000..f7c0046 --- /dev/null +++ b/drivers/video/fbdev/sis/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the SiS framebuffer device driver +# + +obj-$(CONFIG_FB_SIS) += sisfb.o + +sisfb-objs := sis_main.o sis_accel.o init.o init301.o initextlfb.o diff --git a/drivers/video/fbdev/sis/init.c b/drivers/video/fbdev/sis/init.c new file mode 100644 index 0000000..bd40f5e --- /dev/null +++ b/drivers/video/fbdev/sis/init.c @@ -0,0 +1,3655 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Mode initializing code (CRT1 section) for + * for SiS 300/305/540/630/730, + * SiS 315/550/[M]650/651/[M]661[FGM]X/[M]74x[GX]/330/[M]76x[GX], + * XGI Volari V3XT/V5/V8, Z7 + * (Universal module for Linux kernel framebuffer and X.org/XFree86 4.x) + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + * Formerly based on non-functional code-fragements for 300 series by SiS, Inc. + * Used by permission. + */ + +#include "init.h" + +#ifdef CONFIG_FB_SIS_300 +#include "300vtbl.h" +#endif + +#ifdef CONFIG_FB_SIS_315 +#include "310vtbl.h" +#endif + +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(PAGE,SiSSetMode) +#endif + +/*********************************************/ +/* POINTER INITIALIZATION */ +/*********************************************/ + +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) +static void +InitCommonPointer(struct SiS_Private *SiS_Pr) +{ + SiS_Pr->SiS_SModeIDTable = SiS_SModeIDTable; + SiS_Pr->SiS_StResInfo = SiS_StResInfo; + SiS_Pr->SiS_ModeResInfo = SiS_ModeResInfo; + SiS_Pr->SiS_StandTable = SiS_StandTable; + + SiS_Pr->SiS_NTSCTiming = SiS_NTSCTiming; + SiS_Pr->SiS_PALTiming = SiS_PALTiming; + SiS_Pr->SiS_HiTVSt1Timing = SiS_HiTVSt1Timing; + SiS_Pr->SiS_HiTVSt2Timing = SiS_HiTVSt2Timing; + + SiS_Pr->SiS_HiTVExtTiming = SiS_HiTVExtTiming; + SiS_Pr->SiS_HiTVGroup3Data = SiS_HiTVGroup3Data; + SiS_Pr->SiS_HiTVGroup3Simu = SiS_HiTVGroup3Simu; +#if 0 + SiS_Pr->SiS_HiTVTextTiming = SiS_HiTVTextTiming; + SiS_Pr->SiS_HiTVGroup3Text = SiS_HiTVGroup3Text; +#endif + + SiS_Pr->SiS_StPALData = SiS_StPALData; + SiS_Pr->SiS_ExtPALData = SiS_ExtPALData; + SiS_Pr->SiS_StNTSCData = SiS_StNTSCData; + SiS_Pr->SiS_ExtNTSCData = SiS_ExtNTSCData; + SiS_Pr->SiS_St1HiTVData = SiS_StHiTVData; + SiS_Pr->SiS_St2HiTVData = SiS_St2HiTVData; + SiS_Pr->SiS_ExtHiTVData = SiS_ExtHiTVData; + SiS_Pr->SiS_St525iData = SiS_StNTSCData; + SiS_Pr->SiS_St525pData = SiS_St525pData; + SiS_Pr->SiS_St750pData = SiS_St750pData; + SiS_Pr->SiS_Ext525iData = SiS_ExtNTSCData; + SiS_Pr->SiS_Ext525pData = SiS_ExtNTSCData; + SiS_Pr->SiS_Ext750pData = SiS_Ext750pData; + + SiS_Pr->pSiS_OutputSelect = &SiS_OutputSelect; + SiS_Pr->pSiS_SoftSetting = &SiS_SoftSetting; + + SiS_Pr->SiS_LCD1280x720Data = SiS_LCD1280x720Data; + SiS_Pr->SiS_StLCD1280x768_2Data = SiS_StLCD1280x768_2Data; + SiS_Pr->SiS_ExtLCD1280x768_2Data = SiS_ExtLCD1280x768_2Data; + SiS_Pr->SiS_LCD1280x800Data = SiS_LCD1280x800Data; + SiS_Pr->SiS_LCD1280x800_2Data = SiS_LCD1280x800_2Data; + SiS_Pr->SiS_LCD1280x854Data = SiS_LCD1280x854Data; + SiS_Pr->SiS_LCD1280x960Data = SiS_LCD1280x960Data; + SiS_Pr->SiS_StLCD1400x1050Data = SiS_StLCD1400x1050Data; + SiS_Pr->SiS_ExtLCD1400x1050Data = SiS_ExtLCD1400x1050Data; + SiS_Pr->SiS_LCD1680x1050Data = SiS_LCD1680x1050Data; + SiS_Pr->SiS_StLCD1600x1200Data = SiS_StLCD1600x1200Data; + SiS_Pr->SiS_ExtLCD1600x1200Data = SiS_ExtLCD1600x1200Data; + SiS_Pr->SiS_NoScaleData = SiS_NoScaleData; + + SiS_Pr->SiS_LVDS320x240Data_1 = SiS_LVDS320x240Data_1; + SiS_Pr->SiS_LVDS320x240Data_2 = SiS_LVDS320x240Data_2; + SiS_Pr->SiS_LVDS640x480Data_1 = SiS_LVDS640x480Data_1; + SiS_Pr->SiS_LVDS800x600Data_1 = SiS_LVDS800x600Data_1; + SiS_Pr->SiS_LVDS1024x600Data_1 = SiS_LVDS1024x600Data_1; + SiS_Pr->SiS_LVDS1024x768Data_1 = SiS_LVDS1024x768Data_1; + + SiS_Pr->SiS_LVDSCRT1320x240_1 = SiS_LVDSCRT1320x240_1; + SiS_Pr->SiS_LVDSCRT1320x240_2 = SiS_LVDSCRT1320x240_2; + SiS_Pr->SiS_LVDSCRT1320x240_2_H = SiS_LVDSCRT1320x240_2_H; + SiS_Pr->SiS_LVDSCRT1320x240_3 = SiS_LVDSCRT1320x240_3; + SiS_Pr->SiS_LVDSCRT1320x240_3_H = SiS_LVDSCRT1320x240_3_H; + SiS_Pr->SiS_LVDSCRT1640x480_1 = SiS_LVDSCRT1640x480_1; + SiS_Pr->SiS_LVDSCRT1640x480_1_H = SiS_LVDSCRT1640x480_1_H; +#if 0 + SiS_Pr->SiS_LVDSCRT11024x600_1 = SiS_LVDSCRT11024x600_1; + SiS_Pr->SiS_LVDSCRT11024x600_1_H = SiS_LVDSCRT11024x600_1_H; + SiS_Pr->SiS_LVDSCRT11024x600_2 = SiS_LVDSCRT11024x600_2; + SiS_Pr->SiS_LVDSCRT11024x600_2_H = SiS_LVDSCRT11024x600_2_H; +#endif + + SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData; + SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData; + + SiS_Pr->SiS_PanelMinLVDS = Panel_800x600; /* lowest value LVDS/LCDA */ + SiS_Pr->SiS_PanelMin301 = Panel_1024x768; /* lowest value 301 */ +} +#endif + +#ifdef CONFIG_FB_SIS_300 +static void +InitTo300Pointer(struct SiS_Private *SiS_Pr) +{ + InitCommonPointer(SiS_Pr); + + SiS_Pr->SiS_VBModeIDTable = SiS300_VBModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiS300_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiS300_RefIndex; + SiS_Pr->SiS_CRT1Table = SiS300_CRT1Table; + if(SiS_Pr->ChipType == SIS_300) { + SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_300; /* 300 */ + } else { + SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_630; /* 630, 730 */ + } + SiS_Pr->SiS_VCLKData = SiS300_VCLKData; + SiS_Pr->SiS_VBVCLKData = (struct SiS_VBVCLKData *)SiS300_VCLKData; + + SiS_Pr->SiS_SR15 = SiS300_SR15; + + SiS_Pr->SiS_PanelDelayTbl = SiS300_PanelDelayTbl; + SiS_Pr->SiS_PanelDelayTblLVDS = SiS300_PanelDelayTbl; + + SiS_Pr->SiS_ExtLCD1024x768Data = SiS300_ExtLCD1024x768Data; + SiS_Pr->SiS_St2LCD1024x768Data = SiS300_St2LCD1024x768Data; + SiS_Pr->SiS_ExtLCD1280x1024Data = SiS300_ExtLCD1280x1024Data; + SiS_Pr->SiS_St2LCD1280x1024Data = SiS300_St2LCD1280x1024Data; + + SiS_Pr->SiS_CRT2Part2_1024x768_1 = SiS300_CRT2Part2_1024x768_1; + SiS_Pr->SiS_CRT2Part2_1024x768_2 = SiS300_CRT2Part2_1024x768_2; + SiS_Pr->SiS_CRT2Part2_1024x768_3 = SiS300_CRT2Part2_1024x768_3; + + SiS_Pr->SiS_CHTVUPALData = SiS300_CHTVUPALData; + SiS_Pr->SiS_CHTVOPALData = SiS300_CHTVOPALData; + SiS_Pr->SiS_CHTVUPALMData = SiS_CHTVUNTSCData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVOPALMData = SiS_CHTVONTSCData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVUPALNData = SiS300_CHTVUPALData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVOPALNData = SiS300_CHTVOPALData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVSOPALData = SiS300_CHTVSOPALData; + + SiS_Pr->SiS_LVDS848x480Data_1 = SiS300_LVDS848x480Data_1; + SiS_Pr->SiS_LVDS848x480Data_2 = SiS300_LVDS848x480Data_2; + SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS300_LVDSBARCO1024Data_1; + SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS300_LVDSBARCO1366Data_1; + SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS300_LVDSBARCO1366Data_2; + + SiS_Pr->SiS_PanelType04_1a = SiS300_PanelType04_1a; + SiS_Pr->SiS_PanelType04_2a = SiS300_PanelType04_2a; + SiS_Pr->SiS_PanelType04_1b = SiS300_PanelType04_1b; + SiS_Pr->SiS_PanelType04_2b = SiS300_PanelType04_2b; + + SiS_Pr->SiS_CHTVCRT1UNTSC = SiS300_CHTVCRT1UNTSC; + SiS_Pr->SiS_CHTVCRT1ONTSC = SiS300_CHTVCRT1ONTSC; + SiS_Pr->SiS_CHTVCRT1UPAL = SiS300_CHTVCRT1UPAL; + SiS_Pr->SiS_CHTVCRT1OPAL = SiS300_CHTVCRT1OPAL; + SiS_Pr->SiS_CHTVCRT1SOPAL = SiS300_CHTVCRT1SOPAL; + SiS_Pr->SiS_CHTVReg_UNTSC = SiS300_CHTVReg_UNTSC; + SiS_Pr->SiS_CHTVReg_ONTSC = SiS300_CHTVReg_ONTSC; + SiS_Pr->SiS_CHTVReg_UPAL = SiS300_CHTVReg_UPAL; + SiS_Pr->SiS_CHTVReg_OPAL = SiS300_CHTVReg_OPAL; + SiS_Pr->SiS_CHTVReg_UPALM = SiS300_CHTVReg_UNTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_OPALM = SiS300_CHTVReg_ONTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_UPALN = SiS300_CHTVReg_UPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_OPALN = SiS300_CHTVReg_OPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_SOPAL = SiS300_CHTVReg_SOPAL; + SiS_Pr->SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC; + SiS_Pr->SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC; + SiS_Pr->SiS_CHTVVCLKUPAL = SiS300_CHTVVCLKUPAL; + SiS_Pr->SiS_CHTVVCLKOPAL = SiS300_CHTVVCLKOPAL; + SiS_Pr->SiS_CHTVVCLKUPALM = SiS300_CHTVVCLKUNTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVVCLKOPALM = SiS300_CHTVVCLKONTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVVCLKUPALN = SiS300_CHTVVCLKUPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVVCLKOPALN = SiS300_CHTVVCLKOPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVVCLKSOPAL = SiS300_CHTVVCLKSOPAL; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static void +InitTo310Pointer(struct SiS_Private *SiS_Pr) +{ + InitCommonPointer(SiS_Pr); + + SiS_Pr->SiS_EModeIDTable = SiS310_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiS310_RefIndex; + SiS_Pr->SiS_CRT1Table = SiS310_CRT1Table; + if(SiS_Pr->ChipType >= SIS_340) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_340; /* 340 + XGI */ + } else if(SiS_Pr->ChipType >= SIS_761) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_761; /* 761 - preliminary */ + } else if(SiS_Pr->ChipType >= SIS_760) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_760; /* 760 */ + } else if(SiS_Pr->ChipType >= SIS_661) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_660; /* 661/741 */ + } else if(SiS_Pr->ChipType == SIS_330) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_330; /* 330 */ + } else if(SiS_Pr->ChipType > SIS_315PRO) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_650; /* 550, 650, 740 */ + } else { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_315; /* 315 */ + } + if(SiS_Pr->ChipType >= SIS_340) { + SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1_340; + } else { + SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1; + } + SiS_Pr->SiS_VCLKData = SiS310_VCLKData; + SiS_Pr->SiS_VBVCLKData = SiS310_VBVCLKData; + + SiS_Pr->SiS_SR15 = SiS310_SR15; + + SiS_Pr->SiS_PanelDelayTbl = SiS310_PanelDelayTbl; + SiS_Pr->SiS_PanelDelayTblLVDS = SiS310_PanelDelayTblLVDS; + + SiS_Pr->SiS_St2LCD1024x768Data = SiS310_St2LCD1024x768Data; + SiS_Pr->SiS_ExtLCD1024x768Data = SiS310_ExtLCD1024x768Data; + SiS_Pr->SiS_St2LCD1280x1024Data = SiS310_St2LCD1280x1024Data; + SiS_Pr->SiS_ExtLCD1280x1024Data = SiS310_ExtLCD1280x1024Data; + + SiS_Pr->SiS_CRT2Part2_1024x768_1 = SiS310_CRT2Part2_1024x768_1; + + SiS_Pr->SiS_CHTVUPALData = SiS310_CHTVUPALData; + SiS_Pr->SiS_CHTVOPALData = SiS310_CHTVOPALData; + SiS_Pr->SiS_CHTVUPALMData = SiS310_CHTVUPALMData; + SiS_Pr->SiS_CHTVOPALMData = SiS310_CHTVOPALMData; + SiS_Pr->SiS_CHTVUPALNData = SiS310_CHTVUPALNData; + SiS_Pr->SiS_CHTVOPALNData = SiS310_CHTVOPALNData; + SiS_Pr->SiS_CHTVSOPALData = SiS310_CHTVSOPALData; + + SiS_Pr->SiS_CHTVCRT1UNTSC = SiS310_CHTVCRT1UNTSC; + SiS_Pr->SiS_CHTVCRT1ONTSC = SiS310_CHTVCRT1ONTSC; + SiS_Pr->SiS_CHTVCRT1UPAL = SiS310_CHTVCRT1UPAL; + SiS_Pr->SiS_CHTVCRT1OPAL = SiS310_CHTVCRT1OPAL; + SiS_Pr->SiS_CHTVCRT1SOPAL = SiS310_CHTVCRT1OPAL; + + SiS_Pr->SiS_CHTVReg_UNTSC = SiS310_CHTVReg_UNTSC; + SiS_Pr->SiS_CHTVReg_ONTSC = SiS310_CHTVReg_ONTSC; + SiS_Pr->SiS_CHTVReg_UPAL = SiS310_CHTVReg_UPAL; + SiS_Pr->SiS_CHTVReg_OPAL = SiS310_CHTVReg_OPAL; + SiS_Pr->SiS_CHTVReg_UPALM = SiS310_CHTVReg_UPALM; + SiS_Pr->SiS_CHTVReg_OPALM = SiS310_CHTVReg_OPALM; + SiS_Pr->SiS_CHTVReg_UPALN = SiS310_CHTVReg_UPALN; + SiS_Pr->SiS_CHTVReg_OPALN = SiS310_CHTVReg_OPALN; + SiS_Pr->SiS_CHTVReg_SOPAL = SiS310_CHTVReg_OPAL; + + SiS_Pr->SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC; + SiS_Pr->SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC; + SiS_Pr->SiS_CHTVVCLKUPAL = SiS310_CHTVVCLKUPAL; + SiS_Pr->SiS_CHTVVCLKOPAL = SiS310_CHTVVCLKOPAL; + SiS_Pr->SiS_CHTVVCLKUPALM = SiS310_CHTVVCLKUPALM; + SiS_Pr->SiS_CHTVVCLKOPALM = SiS310_CHTVVCLKOPALM; + SiS_Pr->SiS_CHTVVCLKUPALN = SiS310_CHTVVCLKUPALN; + SiS_Pr->SiS_CHTVVCLKOPALN = SiS310_CHTVVCLKOPALN; + SiS_Pr->SiS_CHTVVCLKSOPAL = SiS310_CHTVVCLKOPAL; +} +#endif + +bool +SiSInitPtr(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef CONFIG_FB_SIS_300 + InitTo300Pointer(SiS_Pr); +#else + return false; +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + InitTo310Pointer(SiS_Pr); +#else + return false; +#endif + } + return true; +} + +/*********************************************/ +/* HELPER: Get ModeID */ +/*********************************************/ + +static +unsigned short +SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, + int Depth, bool FSTN, int LCDwidth, int LCDheight) +{ + unsigned short ModeIndex = 0; + + switch(HDisplay) + { + case 320: + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + else if(VDisplay == 240) { + if((VBFlags & CRT2_LCD) && (FSTN)) + ModeIndex = ModeIndex_320x240_FSTN[Depth]; + else + ModeIndex = ModeIndex_320x240[Depth]; + } + break; + case 400: + if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 800) && (LCDwidth >= 600))) { + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + } + break; + case 512: + if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 1024) && (LCDwidth >= 768))) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 720: + if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; + else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth]; + break; + case 768: + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; + break; + case 848: + if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; + break; + case 856: + if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; + break; + case 960: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; + else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth]; + } + break; + case 1024: + if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; + else if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + else if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 600) ModeIndex = ModeIndex_1024x600[Depth]; + } + break; + case 1152: + if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; + if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth]; + } + break; + case 1280: + switch(VDisplay) { + case 720: + ModeIndex = ModeIndex_1280x720[Depth]; + break; + case 768: + if(VGAEngine == SIS_300_VGA) { + ModeIndex = ModeIndex_300_1280x768[Depth]; + } else { + ModeIndex = ModeIndex_310_1280x768[Depth]; + } + break; + case 800: + if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_1280x800[Depth]; + } + break; + case 854: + if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_1280x854[Depth]; + } + break; + case 960: + ModeIndex = ModeIndex_1280x960[Depth]; + break; + case 1024: + ModeIndex = ModeIndex_1280x1024[Depth]; + break; + } + break; + case 1360: + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth]; + } + break; + case 1400: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) { + ModeIndex = ModeIndex_1400x1050[Depth]; + } + } + break; + case 1600: + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + break; + case 1680: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } + break; + case 1920: + if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth]; + else if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1080) ModeIndex = ModeIndex_1920x1080[Depth]; + } + break; + case 2048: + if(VDisplay == 1536) { + if(VGAEngine == SIS_300_VGA) { + ModeIndex = ModeIndex_300_2048x1536[Depth]; + } else { + ModeIndex = ModeIndex_310_2048x1536[Depth]; + } + } + break; + } + + return ModeIndex; +} + +unsigned short +SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, + int Depth, bool FSTN, unsigned short CustomT, int LCDwidth, int LCDheight, + unsigned int VBFlags2) +{ + unsigned short ModeIndex = 0; + + if(VBFlags2 & (VB2_LVDS | VB2_30xBDH)) { + + switch(HDisplay) + { + case 320: + if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) { + if(VDisplay == 200) { + if(!FSTN) ModeIndex = ModeIndex_320x200[Depth]; + } else if(VDisplay == 240) { + if(!FSTN) ModeIndex = ModeIndex_320x240[Depth]; + else if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_320x240_FSTN[Depth]; + } + } + } + break; + case 400: + if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) { + if(!((VGAEngine == SIS_300_VGA) && (VBFlags2 & VB2_TRUMPION))) { + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + } + } + break; + case 512: + if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) { + if(!((VGAEngine == SIS_300_VGA) && (VBFlags2 & VB2_TRUMPION))) { + if(LCDwidth >= 1024 && LCDwidth != 1152 && LCDheight >= 768) { + if(VDisplay == 384) { + ModeIndex = ModeIndex_512x384[Depth]; + } + } + } + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) { + if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) + ModeIndex = ModeIndex_640x400[Depth]; + } + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + break; + case 848: + if(CustomT == CUT_PANEL848) { + if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; + } + break; + case 856: + if(CustomT == CUT_PANEL856) { + if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; + } + break; + case 1024: + if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + else if(VGAEngine == SIS_300_VGA) { + if((VDisplay == 600) && (LCDheight == 600)) { + ModeIndex = ModeIndex_1024x600[Depth]; + } + } + break; + case 1152: + if(VGAEngine == SIS_300_VGA) { + if((VDisplay == 768) && (LCDheight == 768)) { + ModeIndex = ModeIndex_1152x768[Depth]; + } + } + break; + case 1280: + if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; + else if(VGAEngine == SIS_315_VGA) { + if((VDisplay == 768) && (LCDheight == 768)) { + ModeIndex = ModeIndex_310_1280x768[Depth]; + } + } + break; + case 1360: + if(VGAEngine == SIS_300_VGA) { + if(CustomT == CUT_BARCO1366) { + if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth]; + } + } + if(CustomT == CUT_PANEL848) { + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + } + break; + case 1400: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; + } + break; + case 1600: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + } + break; + } + + } else if(VBFlags2 & VB2_SISBRIDGE) { + + switch(HDisplay) + { + case 320: + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth]; + break; + case 400: + if(LCDwidth >= 800 && LCDheight >= 600) { + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + } + break; + case 512: + if(LCDwidth >= 1024 && LCDheight >= 768 && LCDwidth != 1152) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 720: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; + else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth]; + } + break; + case 768: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + } + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; + } + break; + case 848: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; + } + break; + case 856: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; + } + break; + case 960: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; + else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth]; + } + break; + case 1024: + if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; + } + break; + case 1152: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; + } + break; + case 1280: + switch(VDisplay) { + case 720: + ModeIndex = ModeIndex_1280x720[Depth]; + break; + case 768: + if(VGAEngine == SIS_300_VGA) { + ModeIndex = ModeIndex_300_1280x768[Depth]; + } else { + ModeIndex = ModeIndex_310_1280x768[Depth]; + } + break; + case 800: + if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_1280x800[Depth]; + } + break; + case 854: + if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_1280x854[Depth]; + } + break; + case 960: + ModeIndex = ModeIndex_1280x960[Depth]; + break; + case 1024: + ModeIndex = ModeIndex_1280x1024[Depth]; + break; + } + break; + case 1360: + if(VGAEngine == SIS_315_VGA) { /* OVER1280 only? */ + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + } + break; + case 1400: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags2 & VB2_LCDOVER1280BRIDGE) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; + } + } + break; + case 1600: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags2 & VB2_LCDOVER1280BRIDGE) { + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + } + } + break; +#ifndef VB_FORBID_CRT2LCD_OVER_1600 + case 1680: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags2 & VB2_LCDOVER1280BRIDGE) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } + } + break; + case 1920: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags2 & VB2_LCDOVER1600BRIDGE) { + if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth]; + } + } + break; + case 2048: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags2 & VB2_LCDOVER1600BRIDGE) { + if(VDisplay == 1536) ModeIndex = ModeIndex_310_2048x1536[Depth]; + } + } + break; +#endif + } + } + + return ModeIndex; +} + +unsigned short +SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, int Depth, + unsigned int VBFlags2) +{ + unsigned short ModeIndex = 0; + + if(VBFlags2 & VB2_CHRONTEL) { + + switch(HDisplay) + { + case 512: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + break; + case 1024: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + } + break; + } + + } else if(VBFlags2 & VB2_SISTVBRIDGE) { + + switch(HDisplay) + { + case 320: + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth]; + break; + case 400: + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + break; + case 512: + if( ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR750P | TV_YPBPR1080I))) || + (VBFlags & TV_HIVISION) || + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 720: + if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) { + if(VDisplay == 480) { + ModeIndex = ModeIndex_720x480[Depth]; + } else if(VDisplay == 576) { + if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) || + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) + ModeIndex = ModeIndex_720x576[Depth]; + } + } + break; + case 768: + if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) { + if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) || + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) { + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + } + } + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + else if(VDisplay == 480) { + if(!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P))) { + ModeIndex = ModeIndex_800x480[Depth]; + } + } + break; + case 960: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 600) { + if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { + ModeIndex = ModeIndex_960x600[Depth]; + } + } + } + break; + case 1024: + if(VDisplay == 768) { + if(VBFlags2 & VB2_30xBLV) { + ModeIndex = ModeIndex_1024x768[Depth]; + } + } else if(VDisplay == 576) { + if( (VBFlags & TV_HIVISION) || + ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)) || + ((VBFlags2 & VB2_30xBLV) && + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL))) ) { + ModeIndex = ModeIndex_1024x576[Depth]; + } + } + break; + case 1280: + if(VDisplay == 720) { + if((VBFlags & TV_HIVISION) || + ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)))) { + ModeIndex = ModeIndex_1280x720[Depth]; + } + } else if(VDisplay == 1024) { + if((VBFlags & TV_HIVISION) || + ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { + ModeIndex = ModeIndex_1280x1024[Depth]; + } + } + break; + } + } + return ModeIndex; +} + +unsigned short +SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, int Depth, + unsigned int VBFlags2) +{ + if(!(VBFlags2 & VB2_SISVGA2BRIDGE)) return 0; + + if(HDisplay >= 1920) return 0; + + switch(HDisplay) + { + case 1600: + if(VDisplay == 1200) { + if(VGAEngine != SIS_315_VGA) return 0; + if(!(VBFlags2 & VB2_30xB)) return 0; + } + break; + case 1680: + if(VDisplay == 1050) { + if(VGAEngine != SIS_315_VGA) return 0; + if(!(VBFlags2 & VB2_30xB)) return 0; + } + break; + } + + return SiS_GetModeID(VGAEngine, 0, HDisplay, VDisplay, Depth, false, 0, 0); +} + + +/*********************************************/ +/* HELPER: SetReg, GetReg */ +/*********************************************/ + +void +SiS_SetReg(SISIOADDRESS port, u8 index, u8 data) +{ + outb(index, port); + outb(data, port + 1); +} + +void +SiS_SetRegByte(SISIOADDRESS port, u8 data) +{ + outb(data, port); +} + +void +SiS_SetRegShort(SISIOADDRESS port, u16 data) +{ + outw(data, port); +} + +void +SiS_SetRegLong(SISIOADDRESS port, u32 data) +{ + outl(data, port); +} + +u8 +SiS_GetReg(SISIOADDRESS port, u8 index) +{ + outb(index, port); + return inb(port + 1); +} + +u8 +SiS_GetRegByte(SISIOADDRESS port) +{ + return inb(port); +} + +u16 +SiS_GetRegShort(SISIOADDRESS port) +{ + return inw(port); +} + +u32 +SiS_GetRegLong(SISIOADDRESS port) +{ + return inl(port); +} + +void +SiS_SetRegANDOR(SISIOADDRESS Port, u8 Index, u8 DataAND, u8 DataOR) +{ + u8 temp; + + temp = SiS_GetReg(Port, Index); + temp = (temp & (DataAND)) | DataOR; + SiS_SetReg(Port, Index, temp); +} + +void +SiS_SetRegAND(SISIOADDRESS Port, u8 Index, u8 DataAND) +{ + u8 temp; + + temp = SiS_GetReg(Port, Index); + temp &= DataAND; + SiS_SetReg(Port, Index, temp); +} + +void +SiS_SetRegOR(SISIOADDRESS Port, u8 Index, u8 DataOR) +{ + u8 temp; + + temp = SiS_GetReg(Port, Index); + temp |= DataOR; + SiS_SetReg(Port, Index, temp); +} + +/*********************************************/ +/* HELPER: DisplayOn, DisplayOff */ +/*********************************************/ + +void +SiS_DisplayOn(struct SiS_Private *SiS_Pr) +{ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xDF); +} + +void +SiS_DisplayOff(struct SiS_Private *SiS_Pr) +{ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20); +} + + +/*********************************************/ +/* HELPER: Init Port Addresses */ +/*********************************************/ + +void +SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr) +{ + SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; + SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; + SiS_Pr->SiS_P3c0 = BaseAddr + 0x10; + SiS_Pr->SiS_P3ce = BaseAddr + 0x1e; + SiS_Pr->SiS_P3c2 = BaseAddr + 0x12; + SiS_Pr->SiS_P3ca = BaseAddr + 0x1a; + SiS_Pr->SiS_P3c6 = BaseAddr + 0x16; + SiS_Pr->SiS_P3c7 = BaseAddr + 0x17; + SiS_Pr->SiS_P3c8 = BaseAddr + 0x18; + SiS_Pr->SiS_P3c9 = BaseAddr + 0x19; + SiS_Pr->SiS_P3cb = BaseAddr + 0x1b; + SiS_Pr->SiS_P3cc = BaseAddr + 0x1c; + SiS_Pr->SiS_P3cd = BaseAddr + 0x1d; + SiS_Pr->SiS_P3da = BaseAddr + 0x2a; + SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; + SiS_Pr->SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10; + SiS_Pr->SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12; + SiS_Pr->SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14; + SiS_Pr->SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; + SiS_Pr->SiS_DDC_Port = BaseAddr + 0x14; + SiS_Pr->SiS_VidCapt = BaseAddr + SIS_VIDEO_CAPTURE; + SiS_Pr->SiS_VidPlay = BaseAddr + SIS_VIDEO_PLAYBACK; +} + +/*********************************************/ +/* HELPER: GetSysFlags */ +/*********************************************/ + +static void +SiS_GetSysFlags(struct SiS_Private *SiS_Pr) +{ + unsigned char cr5f, temp1, temp2; + + /* 661 and newer: NEVER write non-zero to SR11[7:4] */ + /* (SR11 is used for DDC and in enable/disablebridge) */ + SiS_Pr->SiS_SensibleSR11 = false; + SiS_Pr->SiS_MyCR63 = 0x63; + if(SiS_Pr->ChipType >= SIS_330) { + SiS_Pr->SiS_MyCR63 = 0x53; + if(SiS_Pr->ChipType >= SIS_661) { + SiS_Pr->SiS_SensibleSR11 = true; + } + } + + /* You should use the macros, not these flags directly */ + + SiS_Pr->SiS_SysFlags = 0; + if(SiS_Pr->ChipType == SIS_650) { + cr5f = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0; + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x5c,0x07); + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8; + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x5c,0xf8); + temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8; + if((!temp1) || (temp2)) { + switch(cr5f) { + case 0x80: + case 0x90: + case 0xc0: + SiS_Pr->SiS_SysFlags |= SF_IsM650; + break; + case 0xa0: + case 0xb0: + case 0xe0: + SiS_Pr->SiS_SysFlags |= SF_Is651; + break; + } + } else { + switch(cr5f) { + case 0x90: + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8; + switch(temp1) { + case 0x00: SiS_Pr->SiS_SysFlags |= SF_IsM652; break; + case 0x40: SiS_Pr->SiS_SysFlags |= SF_IsM653; break; + default: SiS_Pr->SiS_SysFlags |= SF_IsM650; break; + } + break; + case 0xb0: + SiS_Pr->SiS_SysFlags |= SF_Is652; + break; + default: + SiS_Pr->SiS_SysFlags |= SF_IsM650; + break; + } + } + } + + if(SiS_Pr->ChipType >= SIS_760 && SiS_Pr->ChipType <= SIS_761) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x30) { + SiS_Pr->SiS_SysFlags |= SF_760LFB; + } + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0xf0) { + SiS_Pr->SiS_SysFlags |= SF_760UMA; + } + } +} + +/*********************************************/ +/* HELPER: Init PCI & Engines */ +/*********************************************/ + +static void +SiSInitPCIetc(struct SiS_Private *SiS_Pr) +{ + switch(SiS_Pr->ChipType) { +#ifdef CONFIG_FB_SIS_300 + case SIS_300: + case SIS_540: + case SIS_630: + case SIS_730: + /* Set - PCI LINEAR ADDRESSING ENABLE (0x80) + * - RELOCATED VGA IO ENABLED (0x20) + * - MMIO ENABLED (0x01) + * Leave other bits untouched. + */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x20,0xa1); + /* - Enable 2D (0x40) + * - Enable 3D (0x02) + * - Enable 3D Vertex command fetch (0x10) ? + * - Enable 3D command parser (0x08) ? + */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x5A); + break; +#endif +#ifdef CONFIG_FB_SIS_315 + case SIS_315H: + case SIS_315: + case SIS_315PRO: + case SIS_650: + case SIS_740: + case SIS_330: + case SIS_661: + case SIS_741: + case SIS_660: + case SIS_760: + case SIS_761: + case SIS_340: + case XGI_40: + /* See above */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x20,0xa1); + /* - Enable 3D G/L transformation engine (0x80) + * - Enable 2D (0x40) + * - Enable 3D vertex command fetch (0x10) + * - Enable 3D command parser (0x08) + * - Enable 3D (0x02) + */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0xDA); + break; + case XGI_20: + case SIS_550: + /* See above */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x20,0xa1); + /* No 3D engine ! */ + /* - Enable 2D (0x40) + * - disable 3D + */ + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0x60,0x40); + break; +#endif + default: + break; + } +} + +/*********************************************/ +/* HELPER: SetLVDSetc */ +/*********************************************/ + +static +void +SiSSetLVDSetc(struct SiS_Private *SiS_Pr) +{ + unsigned short temp; + + SiS_Pr->SiS_IF_DEF_LVDS = 0; + SiS_Pr->SiS_IF_DEF_TRUMPION = 0; + SiS_Pr->SiS_IF_DEF_CH70xx = 0; + SiS_Pr->SiS_IF_DEF_CONEX = 0; + + SiS_Pr->SiS_ChrontelInit = 0; + + if(SiS_Pr->ChipType == XGI_20) return; + + /* Check for SiS30x first */ + temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + if((temp == 1) || (temp == 2)) return; + + switch(SiS_Pr->ChipType) { +#ifdef CONFIG_FB_SIS_300 + case SIS_540: + case SIS_630: + case SIS_730: + temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x37) & 0x0e) >> 1; + if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_TRUMPION = 1; + if((temp == 4) || (temp == 5)) { + /* Save power status (and error check) - UNUSED */ + SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e); + SiS_Pr->SiS_IF_DEF_CH70xx = 1; + } + break; +#endif +#ifdef CONFIG_FB_SIS_315 + case SIS_550: + case SIS_650: + case SIS_740: + case SIS_330: + temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x37) & 0x0e) >> 1; + if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; + break; + case SIS_661: + case SIS_741: + case SIS_660: + case SIS_760: + case SIS_761: + case SIS_340: + case XGI_20: + case XGI_40: + temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & 0xe0) >> 5; + if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; + if(temp == 4) SiS_Pr->SiS_IF_DEF_CONEX = 1; /* Not yet supported */ + break; +#endif + default: + break; + } +} + +/*********************************************/ +/* HELPER: Enable DSTN/FSTN */ +/*********************************************/ + +void +SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable) +{ + SiS_Pr->SiS_IF_DEF_DSTN = enable ? 1 : 0; +} + +void +SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable) +{ + SiS_Pr->SiS_IF_DEF_FSTN = enable ? 1 : 0; +} + +/*********************************************/ +/* HELPER: Get modeflag */ +/*********************************************/ + +unsigned short +SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) +{ + if(SiS_Pr->UseCustomMode) { + return SiS_Pr->CModeFlag; + } else if(ModeNo <= 0x13) { + return SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + return SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } +} + +/*********************************************/ +/* HELPER: Determine ROM usage */ +/*********************************************/ + +bool +SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romversoffs, romvmaj = 1, romvmin = 0; + + if(SiS_Pr->ChipType >= XGI_20) { + /* XGI ROMs don't qualify */ + return false; + } else if(SiS_Pr->ChipType >= SIS_761) { + /* I very much assume 761, 340 and newer will use new layout */ + return true; + } else if(SiS_Pr->ChipType >= SIS_661) { + if((ROMAddr[0x1a] == 'N') && + (ROMAddr[0x1b] == 'e') && + (ROMAddr[0x1c] == 'w') && + (ROMAddr[0x1d] == 'V')) { + return true; + } + romversoffs = ROMAddr[0x16] | (ROMAddr[0x17] << 8); + if(romversoffs) { + if((ROMAddr[romversoffs+1] == '.') || (ROMAddr[romversoffs+4] == '.')) { + romvmaj = ROMAddr[romversoffs] - '0'; + romvmin = ((ROMAddr[romversoffs+2] -'0') * 10) + (ROMAddr[romversoffs+3] - '0'); + } + } + if((romvmaj != 0) || (romvmin >= 92)) { + return true; + } + } else if(IS_SIS650740) { + if((ROMAddr[0x1a] == 'N') && + (ROMAddr[0x1b] == 'e') && + (ROMAddr[0x1c] == 'w') && + (ROMAddr[0x1d] == 'V')) { + return true; + } + } + return false; +} + +static void +SiSDetermineROMUsage(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr = 0; + + SiS_Pr->SiS_UseROM = false; + SiS_Pr->SiS_ROMNew = false; + SiS_Pr->SiS_PWDOffset = 0; + + if(SiS_Pr->ChipType >= XGI_20) return; + + if((ROMAddr) && (SiS_Pr->UseROM)) { + if(SiS_Pr->ChipType == SIS_300) { + /* 300: We check if the code starts below 0x220 by + * checking the jmp instruction at the beginning + * of the BIOS image. + */ + if((ROMAddr[3] == 0xe9) && ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a) + SiS_Pr->SiS_UseROM = true; + } else if(SiS_Pr->ChipType < SIS_315H) { + /* Sony's VAIO BIOS 1.09 follows the standard, so perhaps + * the others do as well + */ + SiS_Pr->SiS_UseROM = true; + } else { + /* 315/330 series stick to the standard(s) */ + SiS_Pr->SiS_UseROM = true; + if((SiS_Pr->SiS_ROMNew = SiSDetermineROMLayout661(SiS_Pr))) { + SiS_Pr->SiS_EMIOffset = 14; + SiS_Pr->SiS_PWDOffset = 17; + SiS_Pr->SiS661LCD2TableSize = 36; + /* Find out about LCD data table entry size */ + if((romptr = SISGETROMW(0x0102))) { + if(ROMAddr[romptr + (32 * 16)] == 0xff) + SiS_Pr->SiS661LCD2TableSize = 32; + else if(ROMAddr[romptr + (34 * 16)] == 0xff) + SiS_Pr->SiS661LCD2TableSize = 34; + else if(ROMAddr[romptr + (36 * 16)] == 0xff) /* 0.94, 2.05.00+ */ + SiS_Pr->SiS661LCD2TableSize = 36; + else if( (ROMAddr[romptr + (38 * 16)] == 0xff) || /* 2.00.00 - 2.02.00 */ + (ROMAddr[0x6F] & 0x01) ) { /* 2.03.00 - <2.05.00 */ + SiS_Pr->SiS661LCD2TableSize = 38; /* UMC data layout abandoned at 2.05.00 */ + SiS_Pr->SiS_EMIOffset = 16; + SiS_Pr->SiS_PWDOffset = 19; + } + } + } + } + } +} + +/*********************************************/ +/* HELPER: SET SEGMENT REGISTERS */ +/*********************************************/ + +static void +SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) +{ + unsigned short temp; + + value &= 0x00ff; + temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0xf0; + temp |= (value >> 4); + SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp); + temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0xf0; + temp |= (value & 0x0f); + SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp); +} + +static void +SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) +{ + unsigned short temp; + + value &= 0x00ff; + temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0x0f; + temp |= (value & 0xf0); + SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp); + temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0x0f; + temp |= (value << 4); + SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp); +} + +static void +SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) +{ + SiS_SetSegRegLower(SiS_Pr, value); + SiS_SetSegRegUpper(SiS_Pr, value); +} + +static void +SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) +{ + SiS_SetSegmentReg(SiS_Pr, 0); +} + +static void +SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) +{ + unsigned short temp = value >> 8; + + temp &= 0x07; + temp |= (temp << 4); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x1d,temp); + SiS_SetSegmentReg(SiS_Pr, value); +} + +static void +SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) +{ + SiS_SetSegmentRegOver(SiS_Pr, 0); +} + +static void +SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) +{ + if((IS_SIS65x) || (SiS_Pr->ChipType >= SIS_661)) { + SiS_ResetSegmentReg(SiS_Pr); + SiS_ResetSegmentRegOver(SiS_Pr); + } +} + +/*********************************************/ +/* HELPER: GetVBType */ +/*********************************************/ + +static +void +SiS_GetVBType(struct SiS_Private *SiS_Pr) +{ + unsigned short flag = 0, rev = 0, nolcd = 0; + unsigned short p4_0f, p4_25, p4_27; + + SiS_Pr->SiS_VBType = 0; + + if((SiS_Pr->SiS_IF_DEF_LVDS) || (SiS_Pr->SiS_IF_DEF_CONEX)) + return; + + if(SiS_Pr->ChipType == XGI_20) + return; + + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + + if(flag > 3) + return; + + rev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); + + if(flag >= 2) { + SiS_Pr->SiS_VBType = VB_SIS302B; + } else if(flag == 1) { + if(rev >= 0xC0) { + SiS_Pr->SiS_VBType = VB_SIS301C; + } else if(rev >= 0xB0) { + SiS_Pr->SiS_VBType = VB_SIS301B; + /* Check if 30xB DH version (no LCD support, use Panel Link instead) */ + nolcd = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x23); + if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD; + } else { + SiS_Pr->SiS_VBType = VB_SIS301; + } + } + if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) { + if(rev >= 0xE0) { + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39); + if(flag == 0xff) SiS_Pr->SiS_VBType = VB_SIS302LV; + else SiS_Pr->SiS_VBType = VB_SIS301C; /* VB_SIS302ELV; */ + } else if(rev >= 0xD0) { + SiS_Pr->SiS_VBType = VB_SIS301LV; + } + } + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) { + p4_0f = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0f); + p4_25 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x25); + p4_27 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x27); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0x7f); + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x25,0x08); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,0xfd); + if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x08) { + SiS_Pr->SiS_VBType |= VB_UMC; + } + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x27,p4_27); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x25,p4_25); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0f,p4_0f); + } +} + +/*********************************************/ +/* HELPER: Check RAM size */ +/*********************************************/ + +static bool +SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) +{ + unsigned short AdapterMemSize = SiS_Pr->VideoMemorySize / (1024*1024); + unsigned short modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + unsigned short memorysize = ((modeflag & MemoryInfoFlag) >> MemorySizeShift) + 1; + + if(!AdapterMemSize) return true; + + if(AdapterMemSize < memorysize) return false; + return true; +} + +/*********************************************/ +/* HELPER: Get DRAM type */ +/*********************************************/ + +#ifdef CONFIG_FB_SIS_315 +static unsigned char +SiS_Get310DRAMType(struct SiS_Private *SiS_Pr) +{ + unsigned char data; + + if((*SiS_Pr->pSiS_SoftSetting) & SoftDRAMType) { + data = (*SiS_Pr->pSiS_SoftSetting) & 0x03; + } else { + if(SiS_Pr->ChipType >= XGI_20) { + /* Do I need this? SR17 seems to be zero anyway... */ + data = 0; + } else if(SiS_Pr->ChipType >= SIS_340) { + /* TODO */ + data = 0; + } if(SiS_Pr->ChipType >= SIS_661) { + if(SiS_Pr->SiS_ROMNew) { + data = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0xc0) >> 6); + } else { + data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07; + } + } else if(IS_SIS550650740) { + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x07; + } else { /* 315, 330 */ + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x03; + if(SiS_Pr->ChipType == SIS_330) { + if(data > 1) { + switch(SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0x30) { + case 0x00: data = 1; break; + case 0x10: data = 3; break; + case 0x20: data = 3; break; + case 0x30: data = 2; break; + } + } else { + data = 0; + } + } + } + } + + return data; +} + +static unsigned short +SiS_GetMCLK(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index; + + index = SiS_Get310DRAMType(SiS_Pr); + if(SiS_Pr->ChipType >= SIS_661) { + if(SiS_Pr->SiS_ROMNew) { + return((unsigned short)(SISGETROMW((0x90 + (index * 5) + 3)))); + } + return(SiS_Pr->SiS_MCLKData_0[index].CLOCK); + } else if(index >= 4) { + return(SiS_Pr->SiS_MCLKData_1[index - 4].CLOCK); + } else { + return(SiS_Pr->SiS_MCLKData_0[index].CLOCK); + } +} +#endif + +/*********************************************/ +/* HELPER: ClearBuffer */ +/*********************************************/ + +static void +SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + unsigned char SISIOMEMTYPE *memaddr = SiS_Pr->VideoMemoryAddress; + unsigned int memsize = SiS_Pr->VideoMemorySize; + unsigned short SISIOMEMTYPE *pBuffer; + int i; + + if(!memaddr || !memsize) return; + + if(SiS_Pr->SiS_ModeType >= ModeEGA) { + if(ModeNo > 0x13) { + memset_io(memaddr, 0, memsize); + } else { + pBuffer = (unsigned short SISIOMEMTYPE *)memaddr; + for(i = 0; i < 0x4000; i++) writew(0x0000, &pBuffer[i]); + } + } else if(SiS_Pr->SiS_ModeType < ModeCGA) { + pBuffer = (unsigned short SISIOMEMTYPE *)memaddr; + for(i = 0; i < 0x4000; i++) writew(0x0720, &pBuffer[i]); + } else { + memset_io(memaddr, 0, 0x8000); + } +} + +/*********************************************/ +/* HELPER: SearchModeID */ +/*********************************************/ + +bool +SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, + unsigned short *ModeIdIndex) +{ + unsigned char VGAINFO = SiS_Pr->SiS_VGAINFO; + + if((*ModeNo) <= 0x13) { + + if((*ModeNo) <= 0x05) (*ModeNo) |= 0x01; + + for((*ModeIdIndex) = 0; ;(*ModeIdIndex)++) { + if(SiS_Pr->SiS_SModeIDTable[(*ModeIdIndex)].St_ModeID == (*ModeNo)) break; + if(SiS_Pr->SiS_SModeIDTable[(*ModeIdIndex)].St_ModeID == 0xFF) return false; + } + + if((*ModeNo) == 0x07) { + if(VGAINFO & 0x10) (*ModeIdIndex)++; /* 400 lines */ + /* else 350 lines */ + } + if((*ModeNo) <= 0x03) { + if(!(VGAINFO & 0x80)) (*ModeIdIndex)++; + if(VGAINFO & 0x10) (*ModeIdIndex)++; /* 400 lines */ + /* else 350 lines */ + } + /* else 200 lines */ + + } else { + + for((*ModeIdIndex) = 0; ;(*ModeIdIndex)++) { + if(SiS_Pr->SiS_EModeIDTable[(*ModeIdIndex)].Ext_ModeID == (*ModeNo)) break; + if(SiS_Pr->SiS_EModeIDTable[(*ModeIdIndex)].Ext_ModeID == 0xFF) return false; + } + + } + return true; +} + +/*********************************************/ +/* HELPER: GetModePtr */ +/*********************************************/ + +unsigned short +SiS_GetModePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short index; + + if(ModeNo <= 0x13) { + index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex; + } else { + if(SiS_Pr->SiS_ModeType <= ModeEGA) index = 0x1B; + else index = 0x0F; + } + return index; +} + +/*********************************************/ +/* HELPERS: Get some indices */ +/*********************************************/ + +unsigned short +SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide) +{ + if(SiS_Pr->SiS_RefIndex[Index].Ext_InfoFlag & HaveWideTiming) { + if(UseWide == 1) { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRTVCLK_WIDE; + } else { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRTVCLK_NORM; + } + } else { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRTVCLK; + } +} + +unsigned short +SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide) +{ + if(SiS_Pr->SiS_RefIndex[Index].Ext_InfoFlag & HaveWideTiming) { + if(UseWide == 1) { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRT1CRTC_WIDE; + } else { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRT1CRTC_NORM; + } + } else { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRT1CRTC; + } +} + +/*********************************************/ +/* HELPER: LowModeTests */ +/*********************************************/ + +static bool +SiS_DoLowModeTest(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + unsigned short temp, temp1, temp2; + + if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12)) + return true; + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x11); + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80); + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,0x55); + temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,temp1); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x11,temp); + if((SiS_Pr->ChipType >= SIS_315H) || + (SiS_Pr->ChipType == SIS_300)) { + if(temp2 == 0x55) return false; + else return true; + } else { + if(temp2 != 0x55) return true; + else { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); + return false; + } + } +} + +static void +SiS_SetLowModeTest(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + if(SiS_DoLowModeTest(SiS_Pr, ModeNo)) { + SiS_Pr->SiS_SetFlag |= LowModeTests; + } +} + +/*********************************************/ +/* HELPER: OPEN/CLOSE CRT1 CRTC */ +/*********************************************/ + +static void +SiS_OpenCRTC(struct SiS_Private *SiS_Pr) +{ + if(IS_SIS650) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); + if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); + } else if(IS_SIS661741660760) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x61,0xf7); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); + if(!SiS_Pr->SiS_ROMNew) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef); + } + } +} + +static void +SiS_CloseCRTC(struct SiS_Private *SiS_Pr) +{ +#if 0 /* This locks some CRTC registers. We don't want that. */ + unsigned short temp1 = 0, temp2 = 0; + + if(IS_SIS661741660760) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + temp1 = 0xa0; temp2 = 0x08; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x51,0x1f,temp1); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x56,0xe7,temp2); + } +#endif +} + +static void +SiS_HandleCRT1(struct SiS_Private *SiS_Pr) +{ + /* Enable CRT1 gating */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0xbf); +#if 0 + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) { + if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) || + (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0x40); + } + } +#endif +} + +/*********************************************/ +/* HELPER: GetColorDepth */ +/*********************************************/ + +unsigned short +SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) +{ + static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; + unsigned short modeflag; + short index; + + /* Do NOT check UseCustomMode, will skrew up FIFO */ + if(ModeNo == 0xfe) { + modeflag = SiS_Pr->CModeFlag; + } else if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + index = (modeflag & ModeTypeMask) - ModeEGA; + if(index < 0) index = 0; + return ColorDepth[index]; +} + +/*********************************************/ +/* HELPER: GetOffset */ +/*********************************************/ + +unsigned short +SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) +{ + unsigned short xres, temp, colordepth, infoflag; + + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + xres = SiS_Pr->CHDisplay; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag; + xres = SiS_Pr->SiS_RefIndex[RRTI].XRes; + } + + colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex); + + temp = xres / 16; + if(infoflag & InterlaceMode) temp <<= 1; + temp *= colordepth; + if(xres % 16) temp += (colordepth >> 1); + + return temp; +} + +/*********************************************/ +/* SEQ */ +/*********************************************/ + +static void +SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char SRdata; + int i; + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03); + + /* or "display off" */ + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; + + /* determine whether to force x8 dotclock */ + if((SiS_Pr->SiS_VBType & VB_SISVB) || (SiS_Pr->SiS_IF_DEF_LVDS)) { + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) SRdata |= 0x01; + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) SRdata |= 0x01; + + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x01,SRdata); + + for(i = 2; i <= 4; i++) { + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1]; + SiS_SetReg(SiS_Pr->SiS_P3c4,i,SRdata); + } +} + +/*********************************************/ +/* MISC */ +/*********************************************/ + +static void +SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char Miscdata; + + Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC; + + if(SiS_Pr->ChipType < SIS_661) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + Miscdata |= 0x0C; + } + } + } + + SiS_SetRegByte(SiS_Pr->SiS_P3c2,Miscdata); +} + +/*********************************************/ +/* CRTC */ +/*********************************************/ + +static void +SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char CRTCdata; + unsigned short i; + + /* Unlock CRTC */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + for(i = 0; i <= 0x18; i++) { + CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); + } + + if(SiS_Pr->ChipType >= SIS_661) { + SiS_OpenCRTC(SiS_Pr); + for(i = 0x13; i <= 0x14; i++) { + CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); + } + } else if( ( (SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730) ) && + (SiS_Pr->ChipRevision >= 0x30) ) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x18,0xFE); + } + } + } +} + +/*********************************************/ +/* ATT */ +/*********************************************/ + +static void +SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char ARdata; + unsigned short i; + + for(i = 0; i <= 0x13; i++) { + ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; + + if(i == 0x13) { + /* Pixel shift. If screen on LCD or TV is shifted left or right, + * this might be the cause. + */ + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ARdata = 0; + } + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0; + } + } + } + if(SiS_Pr->ChipType >= SIS_661) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0; + } + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->ChipType >= SIS_315H) { + if(IS_SIS550650740660) { + /* 315, 330 don't do this */ + if(SiS_Pr->SiS_VBType & VB_SIS30xB) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0; + } else { + ARdata = 0; + } + } + } else { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0; + } + } + } + SiS_GetRegByte(SiS_Pr->SiS_P3da); /* reset 3da */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,i); /* set index */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,ARdata); /* set data */ + } + + SiS_GetRegByte(SiS_Pr->SiS_P3da); /* reset 3da */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x14); /* set index */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x00); /* set data */ + + SiS_GetRegByte(SiS_Pr->SiS_P3da); + SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x20); /* Enable Attribute */ + SiS_GetRegByte(SiS_Pr->SiS_P3da); +} + +/*********************************************/ +/* GRC */ +/*********************************************/ + +static void +SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char GRdata; + unsigned short i; + + for(i = 0; i <= 0x08; i++) { + GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; + SiS_SetReg(SiS_Pr->SiS_P3ce,i,GRdata); + } + + if(SiS_Pr->SiS_ModeType > ModeVGA) { + /* 256 color disable */ + SiS_SetRegAND(SiS_Pr->SiS_P3ce,0x05,0xBF); + } +} + +/*********************************************/ +/* CLEAR EXTENDED REGISTERS */ +/*********************************************/ + +static void +SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + unsigned short i; + + for(i = 0x0A; i <= 0x0E; i++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,i,0x00); + } + + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE); + if(ModeNo <= 0x13) { + if(ModeNo == 0x06 || ModeNo >= 0x0e) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e,0x20); + } + } + } +} + +/*********************************************/ +/* RESET VCLK */ +/*********************************************/ + +static void +SiS_ResetCRT1VCLK(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->ChipType < SIS_661) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 0) return; + } + } else { + if((SiS_Pr->SiS_IF_DEF_LVDS == 0) && + (!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) ) { + return; + } + } + + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x20); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[1].SR2B); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[1].SR2C); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[0].SR2B); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[0].SR2C); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); +} + +/*********************************************/ +/* SYNC */ +/*********************************************/ + +static void +SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short RRTI) +{ + unsigned short sync; + + if(SiS_Pr->UseCustomMode) { + sync = SiS_Pr->CInfoFlag >> 8; + } else { + sync = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag >> 8; + } + + sync &= 0xC0; + sync |= 0x2f; + SiS_SetRegByte(SiS_Pr->SiS_P3c2,sync); +} + +/*********************************************/ +/* CRTC/2 */ +/*********************************************/ + +static void +SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) +{ + unsigned short temp, i, j, modeflag; + unsigned char *crt1data = NULL; + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + if(SiS_Pr->UseCustomMode) { + + crt1data = &SiS_Pr->CCRT1CRTC[0]; + + } else { + + temp = SiS_GetRefCRT1CRTC(SiS_Pr, RRTI, SiS_Pr->SiS_UseWide); + + /* Alternate for 1600x1200 LCDA */ + if((temp == 0x20) && (SiS_Pr->Alternate1600x1200)) temp = 0x57; + + crt1data = (unsigned char *)&SiS_Pr->SiS_CRT1Table[temp].CR[0]; + + } + + /* unlock cr0-7 */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + for(i = 0, j = 0; i <= 7; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,crt1data[i]); + } + for(j = 0x10; i <= 10; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,crt1data[i]); + } + for(j = 0x15; i <= 12; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,crt1data[i]); + } + for(j = 0x0A; i <= 15; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,j,crt1data[i]); + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,crt1data[16] & 0xE0); + + temp = (crt1data[16] & 0x01) << 5; + if(modeflag & DoubleScanMode) temp |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp); + + if(SiS_Pr->SiS_ModeType > ModeVGA) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F); + } + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType == XGI_20) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x04,crt1data[4] - 1); + if(!(temp = crt1data[5] & 0x1f)) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0c,0xfb); + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x05,0xe0,((temp - 1) & 0x1f)); + temp = (crt1data[16] >> 5) + 3; + if(temp > 7) temp -= 7; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0e,0x1f,(temp << 5)); + } +#endif +} + +/*********************************************/ +/* OFFSET & PITCH */ +/*********************************************/ +/* (partly overruled by SetPitch() in XF86) */ +/*********************************************/ + +static void +SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) +{ + unsigned short temp, DisplayUnit, infoflag; + + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag; + } + + DisplayUnit = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, RRTI); + + temp = (DisplayUnit >> 8) & 0x0f; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,temp); + + SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,DisplayUnit & 0xFF); + + if(infoflag & InterlaceMode) DisplayUnit >>= 1; + + DisplayUnit <<= 5; + temp = (DisplayUnit >> 8) + 1; + if(DisplayUnit & 0xff) temp++; + if(SiS_Pr->ChipType == XGI_20) { + if(ModeNo == 0x4a || ModeNo == 0x49) temp--; + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x10,temp); +} + +/*********************************************/ +/* VCLK */ +/*********************************************/ + +static void +SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) +{ + unsigned short index = 0, clka, clkb; + + if(SiS_Pr->UseCustomMode) { + clka = SiS_Pr->CSR2B; + clkb = SiS_Pr->CSR2C; + } else { + index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RRTI); + if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && + (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + /* Alternate for 1600x1200 LCDA */ + if((index == 0x21) && (SiS_Pr->Alternate1600x1200)) index = 0x72; + clka = SiS_Pr->SiS_VBVCLKData[index].Part4_A; + clkb = SiS_Pr->SiS_VBVCLKData[index].Part4_B; + } else { + clka = SiS_Pr->SiS_VCLKData[index].SR2B; + clkb = SiS_Pr->SiS_VCLKData[index].SR2C; + } + } + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF); + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2b,clka); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,clkb); + + if(SiS_Pr->ChipType >= SIS_315H) { +#ifdef CONFIG_FB_SIS_315 + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01); + if(SiS_Pr->ChipType == XGI_20) { + unsigned short mf = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + if(mf & HalfDCLK) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2b,SiS_GetReg(SiS_Pr->SiS_P3c4,0x2b)); + clkb = SiS_GetReg(SiS_Pr->SiS_P3c4,0x2c); + clkb = (((clkb & 0x1f) << 1) + 1) | (clkb & 0xe0); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,clkb); + } + } +#endif + } else { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); + } +} + +/*********************************************/ +/* FIFO */ +/*********************************************/ + +#ifdef CONFIG_FB_SIS_300 +void +SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1, + unsigned short *idx2) +{ + unsigned short temp1, temp2; + static const unsigned char ThTiming[8] = { + 1, 2, 2, 3, 0, 1, 1, 2 + }; + + temp1 = temp2 = (SiS_GetReg(SiS_Pr->SiS_P3c4,0x18) & 0x62) >> 1; + (*idx2) = (unsigned short)(ThTiming[((temp2 >> 3) | temp1) & 0x07]); + (*idx1) = (unsigned short)(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) >> 6) & 0x03; + (*idx1) |= (unsigned short)(((SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) >> 4) & 0x0c)); + (*idx1) <<= 1; +} + +static unsigned short +SiS_GetFIFOThresholdA300(unsigned short idx1, unsigned short idx2) +{ + static const unsigned char ThLowA[8 * 3] = { + 61, 3,52, 5,68, 7,100,11, + 43, 3,42, 5,54, 7, 78,11, + 34, 3,37, 5,47, 7, 67,11 + }; + + return (unsigned short)((ThLowA[idx1 + 1] * idx2) + ThLowA[idx1]); +} + +unsigned short +SiS_GetFIFOThresholdB300(unsigned short idx1, unsigned short idx2) +{ + static const unsigned char ThLowB[8 * 3] = { + 81, 4,72, 6,88, 8,120,12, + 55, 4,54, 6,66, 8, 90,12, + 42, 4,45, 6,55, 8, 75,12 + }; + + return (unsigned short)((ThLowB[idx1 + 1] * idx2) + ThLowB[idx1]); +} + +static unsigned short +SiS_DoCalcDelay(struct SiS_Private *SiS_Pr, unsigned short MCLK, unsigned short VCLK, + unsigned short colordepth, unsigned short key) +{ + unsigned short idx1, idx2; + unsigned int longtemp = VCLK * colordepth; + + SiS_GetFIFOThresholdIndex300(SiS_Pr, &idx1, &idx2); + + if(key == 0) { + longtemp *= SiS_GetFIFOThresholdA300(idx1, idx2); + } else { + longtemp *= SiS_GetFIFOThresholdB300(idx1, idx2); + } + idx1 = longtemp % (MCLK * 16); + longtemp /= (MCLK * 16); + if(idx1) longtemp++; + return (unsigned short)longtemp; +} + +static unsigned short +SiS_CalcDelay(struct SiS_Private *SiS_Pr, unsigned short VCLK, + unsigned short colordepth, unsigned short MCLK) +{ + unsigned short temp1, temp2; + + temp2 = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0); + temp1 = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1); + if(temp1 < 4) temp1 = 4; + temp1 -= 4; + if(temp2 < temp1) temp2 = temp1; + return temp2; +} + +static void +SiS_SetCRT1FIFO_300(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short RefreshRateTableIndex) +{ + unsigned short ThresholdLow = 0; + unsigned short temp, index, VCLK, MCLK, colorth; + static const unsigned short colortharray[6] = { 1, 1, 2, 2, 3, 4 }; + + if(ModeNo > 0x13) { + + /* Get VCLK */ + if(SiS_Pr->UseCustomMode) { + VCLK = SiS_Pr->CSRClock; + } else { + index = SiS_GetRefCRTVCLK(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWide); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; + } + + /* Get half colordepth */ + colorth = colortharray[(SiS_Pr->SiS_ModeType - ModeEGA)]; + + /* Get MCLK */ + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A) & 0x07; + MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; + + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xc3; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,temp); + + do { + ThresholdLow = SiS_CalcDelay(SiS_Pr, VCLK, colorth, MCLK) + 1; + if(ThresholdLow < 0x13) break; + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc); + ThresholdLow = 0x13; + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) >> 6; + if(!temp) break; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,((temp - 1) << 6)); + } while(0); + + } else ThresholdLow = 2; + + /* Write CRT/CPU threshold low, CRT/Engine threshold high */ + temp = (ThresholdLow << 4) | 0x0f; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,temp); + + temp = (ThresholdLow & 0x10) << 1; + if(ModeNo > 0x13) temp |= 0x40; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp); + + /* What is this? */ + SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09); + + /* Write CRT/CPU threshold high */ + temp = ThresholdLow + 3; + if(temp > 0x0f) temp = 0x0f; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x09,temp); +} + +unsigned short +SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index) +{ + static const unsigned char LatencyFactor[] = { + 97, 88, 86, 79, 77, 0, /* 64 bit BQ=2 */ + 0, 87, 85, 78, 76, 54, /* 64 bit BQ=1 */ + 97, 88, 86, 79, 77, 0, /* 128 bit BQ=2 */ + 0, 79, 77, 70, 68, 48, /* 128 bit BQ=1 */ + 80, 72, 69, 63, 61, 0, /* 64 bit BQ=2 */ + 0, 70, 68, 61, 59, 37, /* 64 bit BQ=1 */ + 86, 77, 75, 68, 66, 0, /* 128 bit BQ=2 */ + 0, 68, 66, 59, 57, 37 /* 128 bit BQ=1 */ + }; + static const unsigned char LatencyFactor730[] = { + 69, 63, 61, + 86, 79, 77, + 103, 96, 94, + 120,113,111, + 137,130,128 + }; + + if(SiS_Pr->ChipType == SIS_730) { + return (unsigned short)LatencyFactor730[index]; + } else { + return (unsigned short)LatencyFactor[index]; + } +} + +static unsigned short +SiS_CalcDelay2(struct SiS_Private *SiS_Pr, unsigned char key) +{ + unsigned short index; + + if(SiS_Pr->ChipType == SIS_730) { + index = ((key & 0x0f) * 3) + ((key & 0xc0) >> 6); + } else { + index = (key & 0xe0) >> 5; + if(key & 0x10) index += 6; + if(!(key & 0x01)) index += 24; + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x80) index += 12; + } + return SiS_GetLatencyFactor630(SiS_Pr, index); +} + +static void +SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short RefreshRateTableIndex) +{ + unsigned short ThresholdLow = 0; + unsigned short i, data, VCLK, MCLK16, colorth = 0; + unsigned int templ, datal; + const unsigned char *queuedata = NULL; + static const unsigned char FQBQData[21] = { + 0x01,0x21,0x41,0x61,0x81, + 0x31,0x51,0x71,0x91,0xb1, + 0x00,0x20,0x40,0x60,0x80, + 0x30,0x50,0x70,0x90,0xb0, + 0xff + }; + static const unsigned char FQBQData730[16] = { + 0x34,0x74,0xb4, + 0x23,0x63,0xa3, + 0x12,0x52,0x92, + 0x01,0x41,0x81, + 0x00,0x40,0x80, + 0xff + }; + static const unsigned short colortharray[6] = { + 1, 1, 2, 2, 3, 4 + }; + + i = 0; + + if(ModeNo > 0x13) { + + /* Get VCLK */ + if(SiS_Pr->UseCustomMode) { + VCLK = SiS_Pr->CSRClock; + } else { + data = SiS_GetRefCRTVCLK(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWide); + VCLK = SiS_Pr->SiS_VCLKData[data].CLOCK; + } + + /* Get MCLK * 16 */ + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A) & 0x07; + MCLK16 = SiS_Pr->SiS_MCLKData_0[data].CLOCK * 16; + + /* Get half colordepth */ + colorth = colortharray[(SiS_Pr->SiS_ModeType - ModeEGA)]; + + if(SiS_Pr->ChipType == SIS_730) { + queuedata = &FQBQData730[0]; + } else { + queuedata = &FQBQData[0]; + } + + do { + templ = SiS_CalcDelay2(SiS_Pr, queuedata[i]) * VCLK * colorth; + + datal = templ % MCLK16; + templ = (templ / MCLK16) + 1; + if(datal) templ++; + + if(templ > 0x13) { + if(queuedata[i + 1] == 0xFF) { + ThresholdLow = 0x13; + break; + } + i++; + } else { + ThresholdLow = templ; + break; + } + } while(queuedata[i] != 0xFF); + + } else { + + if(SiS_Pr->ChipType != SIS_730) i = 9; + ThresholdLow = 0x02; + + } + + /* Write CRT/CPU threshold low, CRT/Engine threshold high */ + data = ((ThresholdLow & 0x0f) << 4) | 0x0f; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,data); + + data = (ThresholdLow & 0x10) << 1; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data); + + /* What is this? */ + SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09); + + /* Write CRT/CPU threshold high (gap = 3) */ + data = ThresholdLow + 3; + if(data > 0x0f) data = 0x0f; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data); + + /* Write foreground and background queue */ + templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50); + + if(SiS_Pr->ChipType == SIS_730) { + + templ &= 0xfffff9ff; + templ |= ((queuedata[i] & 0xc0) << 3); + + } else { + + templ &= 0xf0ffffff; + if( (ModeNo <= 0x13) && + (SiS_Pr->ChipType == SIS_630) && + (SiS_Pr->ChipRevision >= 0x30) ) { + templ |= 0x0b000000; + } else { + templ |= ((queuedata[i] & 0xf0) << 20); + } + + } + + sisfb_write_nbridge_pci_dword(SiS_Pr, 0x50, templ); + templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xA0); + + /* GUI grant timer (PCI config 0xA3) */ + if(SiS_Pr->ChipType == SIS_730) { + + templ &= 0x00ffffff; + datal = queuedata[i] << 8; + templ |= (((datal & 0x0f00) | ((datal & 0x3000) >> 8)) << 20); + + } else { + + templ &= 0xf0ffffff; + templ |= ((queuedata[i] & 0x0f) << 24); + + } + + sisfb_write_nbridge_pci_dword(SiS_Pr, 0xA0, templ); +} +#endif /* CONFIG_FB_SIS_300 */ + +#ifdef CONFIG_FB_SIS_315 +static void +SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short modeflag; + + /* disable auto-threshold */ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE); + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0); + if(ModeNo > 0x13) { + if(SiS_Pr->ChipType >= XGI_20) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); + } else if(SiS_Pr->ChipType >= SIS_661) { + if(!(modeflag & HalfDCLK)) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); + } + } else { + if((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); + } + } + } +} +#endif + +/*********************************************/ +/* MODE REGISTERS */ +/*********************************************/ + +static void +SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short RefreshRateTableIndex, unsigned short ModeIdIndex) +{ + unsigned short data = 0, VCLK = 0, index = 0; + + if(ModeNo > 0x13) { + if(SiS_Pr->UseCustomMode) { + VCLK = SiS_Pr->CSRClock; + } else { + index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; + } + } + + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef CONFIG_FB_SIS_300 + if(VCLK > 150) data |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data); + + data = 0x00; + if(VCLK >= 150) data |= 0x08; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data); +#endif + } else if(SiS_Pr->ChipType < XGI_20) { +#ifdef CONFIG_FB_SIS_315 + if(VCLK >= 166) data |= 0x0c; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data); + + if(VCLK >= 166) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7); + } +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + if(VCLK >= 200) data |= 0x0c; + if(SiS_Pr->ChipType == XGI_20) data &= ~0x04; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data); + if(SiS_Pr->ChipType != XGI_20) { + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xe7; + if(VCLK < 200) data |= 0x10; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x1f,data); + } +#endif + } + + /* DAC speed */ + if(SiS_Pr->ChipType >= SIS_661) { + + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xE8,0x10); + + } else { + + data = 0x03; + if(VCLK >= 260) data = 0x00; + else if(VCLK >= 160) data = 0x01; + else if(VCLK >= 135) data = 0x02; + + if(SiS_Pr->ChipType == SIS_540) { + /* Was == 203 or < 234 which made no sense */ + if (VCLK < 234) data = 0x02; + } + + if(SiS_Pr->ChipType < SIS_315H) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data); + } else { + if(SiS_Pr->ChipType > SIS_315PRO) { + if(ModeNo > 0x13) data &= 0xfc; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data); + } + + } +} + +static void +SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) +{ + unsigned short data, infoflag = 0, modeflag, resindex; +#ifdef CONFIG_FB_SIS_315 + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short data2, data3; +#endif + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + resindex = SiS_GetResInfo(SiS_Pr, ModeNo, ModeIdIndex); + if(ModeNo > 0x13) { + infoflag = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag; + } + } + + /* Disable DPMS */ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F); + + data = 0; + if(ModeNo > 0x13) { + if(SiS_Pr->SiS_ModeType > ModeEGA) { + data |= 0x02; + data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); + } + if(infoflag & InterlaceMode) data |= 0x20; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data); + + if(SiS_Pr->ChipType != SIS_300) { + data = 0; + if(infoflag & InterlaceMode) { + /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ + int hrs = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x04) | + ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x0b) & 0xc0) << 2)) - 3; + int hto = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x00) | + ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x0b) & 0x03) << 8)) + 5; + data = hrs - (hto >> 1) + 3; + } + SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,data); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,((data >> 8) & 0x03)); + } + + if(modeflag & HalfDCLK) { + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08); + } + + data = 0; + if(modeflag & LineCompareOff) data = 0x08; + if(SiS_Pr->ChipType == SIS_300) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xF7,data); + } else { + if(SiS_Pr->ChipType >= XGI_20) data |= 0x20; + if(SiS_Pr->SiS_ModeType == ModeEGA) { + if(ModeNo > 0x13) { + data |= 0x40; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data); + } + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb); + } + + if(SiS_Pr->ChipType == SIS_315PRO) { + + data = SiS_Pr->SiS_SR15[(2 * 4) + SiS_Get310DRAMType(SiS_Pr)]; + if(SiS_Pr->SiS_ModeType == ModeText) { + data &= 0xc7; + } else { + data2 = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, RRTI) >> 1; + if(infoflag & InterlaceMode) data2 >>= 1; + data3 = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex) >> 1; + if(data3) data2 /= data3; + if(data2 >= 0x50) { + data &= 0x0f; + data |= 0x50; + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); + + } else if((SiS_Pr->ChipType == SIS_330) || (SiS_Pr->SiS_SysFlags & SF_760LFB)) { + + data = SiS_Get310DRAMType(SiS_Pr); + if(SiS_Pr->ChipType == SIS_330) { + data = SiS_Pr->SiS_SR15[(2 * 4) + data]; + } else { + if(SiS_Pr->SiS_ROMNew) data = ROMAddr[0xf6]; + else if(SiS_Pr->SiS_UseROM) data = ROMAddr[0x100 + data]; + else data = 0xba; + } + if(SiS_Pr->SiS_ModeType <= ModeEGA) { + data &= 0xc7; + } else { + if(SiS_Pr->UseCustomMode) { + data2 = SiS_Pr->CSRClock; + } else { + data2 = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RRTI); + data2 = SiS_Pr->SiS_VCLKData[data2].CLOCK; + } + + data3 = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex) >> 1; + if(data3) data2 *= data3; + + data2 = ((unsigned int)(SiS_GetMCLK(SiS_Pr) * 1024)) / data2; + + if(SiS_Pr->ChipType == SIS_330) { + if(SiS_Pr->SiS_ModeType != Mode16Bpp) { + if (data2 >= 0x19c) data = 0xba; + else if(data2 >= 0x140) data = 0x7a; + else if(data2 >= 0x101) data = 0x3a; + else if(data2 >= 0xf5) data = 0x32; + else if(data2 >= 0xe2) data = 0x2a; + else if(data2 >= 0xc4) data = 0x22; + else if(data2 >= 0xac) data = 0x1a; + else if(data2 >= 0x9e) data = 0x12; + else if(data2 >= 0x8e) data = 0x0a; + else data = 0x02; + } else { + if(data2 >= 0x127) data = 0xba; + else data = 0x7a; + } + } else { /* 76x+LFB */ + if (data2 >= 0x190) data = 0xba; + else if(data2 >= 0xff) data = 0x7a; + else if(data2 >= 0xd3) data = 0x3a; + else if(data2 >= 0xa9) data = 0x1a; + else if(data2 >= 0x93) data = 0x0a; + else data = 0x02; + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); + + } + /* XGI: Nothing. */ + /* TODO: Check SiS340 */ +#endif + + data = 0x60; + if(SiS_Pr->SiS_ModeType != ModeText) { + data ^= 0x60; + if(SiS_Pr->SiS_ModeType != ModeEGA) { + data ^= 0xA0; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data); + + SiS_SetVCLKState(SiS_Pr, ModeNo, RRTI, ModeIdIndex); + +#ifdef CONFIG_FB_SIS_315 + if(((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) || + (SiS_Pr->ChipType == XGI_40)) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x2c); + } else { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x6c); + } + } else if(SiS_Pr->ChipType == XGI_20) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x33); + } else { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x73); + } + SiS_SetReg(SiS_Pr->SiS_P3d4,0x51,0x02); + } +#endif +} + +#ifdef CONFIG_FB_SIS_315 +static void +SiS_SetupDualChip(struct SiS_Private *SiS_Pr) +{ +#if 0 + /* TODO: Find out about IOAddress2 */ + SISIOADDRESS P2_3c2 = SiS_Pr->IOAddress2 + 0x12; + SISIOADDRESS P2_3c4 = SiS_Pr->IOAddress2 + 0x14; + SISIOADDRESS P2_3ce = SiS_Pr->IOAddress2 + 0x1e; + int i; + + if((SiS_Pr->ChipRevision != 0) || + (!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x04))) + return; + + for(i = 0; i <= 4; i++) { /* SR00 - SR04 */ + SiS_SetReg(P2_3c4,i,SiS_GetReg(SiS_Pr->SiS_P3c4,i)); + } + for(i = 0; i <= 8; i++) { /* GR00 - GR08 */ + SiS_SetReg(P2_3ce,i,SiS_GetReg(SiS_Pr->SiS_P3ce,i)); + } + SiS_SetReg(P2_3c4,0x05,0x86); + SiS_SetReg(P2_3c4,0x06,SiS_GetReg(SiS_Pr->SiS_P3c4,0x06)); /* SR06 */ + SiS_SetReg(P2_3c4,0x21,SiS_GetReg(SiS_Pr->SiS_P3c4,0x21)); /* SR21 */ + SiS_SetRegByte(P2_3c2,SiS_GetRegByte(SiS_Pr->SiS_P3cc)); /* MISC */ + SiS_SetReg(P2_3c4,0x05,0x00); +#endif +} +#endif + +/*********************************************/ +/* LOAD DAC */ +/*********************************************/ + +static void +SiS_WriteDAC(struct SiS_Private *SiS_Pr, SISIOADDRESS DACData, unsigned short shiftflag, + unsigned short dl, unsigned short ah, unsigned short al, unsigned short dh) +{ + unsigned short d1, d2, d3; + + switch(dl) { + case 0: d1 = dh; d2 = ah; d3 = al; break; + case 1: d1 = ah; d2 = al; d3 = dh; break; + default: d1 = al; d2 = dh; d3 = ah; + } + SiS_SetRegByte(DACData, (d1 << shiftflag)); + SiS_SetRegByte(DACData, (d2 << shiftflag)); + SiS_SetRegByte(DACData, (d3 << shiftflag)); +} + +void +SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short data, data2, time, i, j, k, m, n, o; + unsigned short si, di, bx, sf; + SISIOADDRESS DACAddr, DACData; + const unsigned char *table = NULL; + + data = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex) & DACInfoFlag; + + j = time = 64; + if(data == 0x00) table = SiS_MDA_DAC; + else if(data == 0x08) table = SiS_CGA_DAC; + else if(data == 0x10) table = SiS_EGA_DAC; + else if(data == 0x18) { + j = 16; + time = 256; + table = SiS_VGA_DAC; + } + + if( ( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && /* 301B-DH LCD */ + (SiS_Pr->SiS_VBType & VB_NoLCD) ) || + (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) || /* LCDA */ + (!(SiS_Pr->SiS_SetFlag & ProgrammingCRT2)) ) { /* Programming CRT1 */ + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); + DACAddr = SiS_Pr->SiS_P3c8; + DACData = SiS_Pr->SiS_P3c9; + sf = 0; + } else { + DACAddr = SiS_Pr->SiS_Part5Port; + DACData = SiS_Pr->SiS_Part5Port + 1; + sf = 2; + } + + SiS_SetRegByte(DACAddr,0x00); + + for(i = 0; i < j; i++) { + data = table[i]; + for(k = 0; k < 3; k++) { + data2 = 0; + if(data & 0x01) data2 += 0x2A; + if(data & 0x02) data2 += 0x15; + SiS_SetRegByte(DACData, (data2 << sf)); + data >>= 2; + } + } + + if(time == 256) { + for(i = 16; i < 32; i++) { + data = table[i] << sf; + for(k = 0; k < 3; k++) SiS_SetRegByte(DACData, data); + } + si = 32; + for(m = 0; m < 9; m++) { + di = si; + bx = si + 4; + for(n = 0; n < 3; n++) { + for(o = 0; o < 5; o++) { + SiS_WriteDAC(SiS_Pr, DACData, sf, n, table[di], table[bx], table[si]); + si++; + } + si -= 2; + for(o = 0; o < 3; o++) { + SiS_WriteDAC(SiS_Pr, DACData, sf, n, table[di], table[si], table[bx]); + si--; + } + } /* for n < 3 */ + si += 5; + } /* for m < 9 */ + } +} + +/*********************************************/ +/* SET CRT1 REGISTER GROUP */ +/*********************************************/ + +static void +SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short StandTableIndex, RefreshRateTableIndex; + + SiS_Pr->SiS_CRT1Mode = ModeNo; + + StandTableIndex = SiS_GetModePtr(SiS_Pr, ModeNo, ModeIdIndex); + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2)) { + SiS_DisableBridge(SiS_Pr); + } + } + + SiS_ResetSegmentRegisters(SiS_Pr); + + SiS_SetSeqRegs(SiS_Pr, StandTableIndex); + SiS_SetMiscRegs(SiS_Pr, StandTableIndex); + SiS_SetCRTCRegs(SiS_Pr, StandTableIndex); + SiS_SetATTRegs(SiS_Pr, StandTableIndex); + SiS_SetGRCRegs(SiS_Pr, StandTableIndex); + SiS_ClearExt1Regs(SiS_Pr, ModeNo); + SiS_ResetCRT1VCLK(SiS_Pr); + + SiS_Pr->SiS_SelectCRT2Rate = 0; + SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); + + if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + } + + RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex); + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_Pr->SiS_SetFlag &= ~ProgrammingCRT2; + } + + if(RefreshRateTableIndex != 0xFFFF) { + SiS_SetCRT1Sync(SiS_Pr, RefreshRateTableIndex); + SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + SiS_SetCRT1VCLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + + switch(SiS_Pr->ChipType) { +#ifdef CONFIG_FB_SIS_300 + case SIS_300: + SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo, RefreshRateTableIndex); + break; + case SIS_540: + case SIS_630: + case SIS_730: + SiS_SetCRT1FIFO_630(SiS_Pr, ModeNo, RefreshRateTableIndex); + break; +#endif + default: +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType == XGI_20) { + unsigned char sr2b = 0, sr2c = 0; + switch(ModeNo) { + case 0x00: + case 0x01: sr2b = 0x4e; sr2c = 0xe9; break; + case 0x04: + case 0x05: + case 0x0d: sr2b = 0x1b; sr2c = 0xe3; break; + } + if(sr2b) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2b,sr2b); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,sr2c); + SiS_SetRegByte(SiS_Pr->SiS_P3c2,(SiS_GetRegByte(SiS_Pr->SiS_P3cc) | 0x0c)); + } + } + SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex); +#endif + break; + } + + SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType == XGI_40) { + SiS_SetupDualChip(SiS_Pr); + } +#endif + + SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex); + + if(SiS_Pr->SiS_flag_clearbuffer) { + SiS_ClearBuffer(SiS_Pr, ModeNo); + } + + if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) { + SiS_WaitRetrace1(SiS_Pr); + SiS_DisplayOn(SiS_Pr); + } +} + +/*********************************************/ +/* HELPER: VIDEO BRIDGE PROG CLK */ +/*********************************************/ + +static void +SiS_InitVB(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + + SiS_Pr->Init_P4_0E = 0; + if(SiS_Pr->SiS_ROMNew) { + SiS_Pr->Init_P4_0E = ROMAddr[0x82]; + } else if(SiS_Pr->ChipType >= XGI_40) { + if(SiS_Pr->SiS_XGIROM) { + SiS_Pr->Init_P4_0E = ROMAddr[0x80]; + } + } +} + +static void +SiS_ResetVB(struct SiS_Private *SiS_Pr) +{ +#ifdef CONFIG_FB_SIS_315 + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp; + + /* VB programming clock */ + if(SiS_Pr->SiS_UseROM) { + if(SiS_Pr->ChipType < SIS_330) { + temp = ROMAddr[VB310Data_1_2_Offset] | 0x40; + if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); + } else if(SiS_Pr->ChipType >= SIS_661 && SiS_Pr->ChipType < XGI_20) { + temp = ROMAddr[0x7e] | 0x40; + if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); + } + } else if(SiS_Pr->ChipType >= XGI_40) { + temp = 0x40; + if(SiS_Pr->SiS_XGIROM) temp |= ROMAddr[0x7e]; + /* Can we do this on any chipset? */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); + } +#endif +} + +/*********************************************/ +/* HELPER: SET VIDEO/CAPTURE REGISTERS */ +/*********************************************/ + +static void +SiS_StrangeStuff(struct SiS_Private *SiS_Pr) +{ + /* SiS65x and XGI set up some sort of "lock mode" for text + * which locks CRT2 in some way to CRT1 timing. Disable + * this here. + */ +#ifdef CONFIG_FB_SIS_315 + if((IS_SIS651) || (IS_SISM650) || + SiS_Pr->ChipType == SIS_340 || + SiS_Pr->ChipType == XGI_40) { + SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x3f, 0x00); /* Fiddle with capture regs */ + SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x00, 0x00); + SiS_SetReg(SiS_Pr->SiS_VidPlay, 0x00, 0x86); /* (BIOS does NOT unlock) */ + SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x30, 0xfe); /* Fiddle with video regs */ + SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x3f, 0xef); + } + /* !!! This does not support modes < 0x13 !!! */ +#endif +} + +/*********************************************/ +/* HELPER: SET AGP TIMING FOR SiS760 */ +/*********************************************/ + +static void +SiS_Handle760(struct SiS_Private *SiS_Pr) +{ +#ifdef CONFIG_FB_SIS_315 + unsigned int somebase; + unsigned char temp1, temp2, temp3; + + if( (SiS_Pr->ChipType != SIS_760) || + ((SiS_GetReg(SiS_Pr->SiS_P3d4, 0x5c) & 0xf8) != 0x80) || + (!(SiS_Pr->SiS_SysFlags & SF_760LFB)) || + (!(SiS_Pr->SiS_SysFlags & SF_760UMA)) ) + return; + + somebase = sisfb_read_mio_pci_word(SiS_Pr, 0x74); + somebase &= 0xffff; + + if(somebase == 0) return; + + temp3 = SiS_GetRegByte((somebase + 0x85)) & 0xb7; + + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) { + temp1 = 0x21; + temp2 = 0x03; + temp3 |= 0x08; + } else { + temp1 = 0x25; + temp2 = 0x0b; + } + + sisfb_write_nbridge_pci_byte(SiS_Pr, 0x7e, temp1); + sisfb_write_nbridge_pci_byte(SiS_Pr, 0x8d, temp2); + + SiS_SetRegByte((somebase + 0x85), temp3); +#endif +} + +/*********************************************/ +/* SiSSetMode() */ +/*********************************************/ + +bool +SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + SISIOADDRESS BaseAddr = SiS_Pr->IOAddress; + unsigned short RealModeNo, ModeIdIndex; + unsigned char backupreg = 0; + unsigned short KeepLockReg; + + SiS_Pr->UseCustomMode = false; + SiS_Pr->CRT1UsesCustomMode = false; + + SiS_Pr->SiS_flag_clearbuffer = 0; + + if(SiS_Pr->UseCustomMode) { + ModeNo = 0xfe; + } else { + if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1; + ModeNo &= 0x7f; + } + + /* Don't use FSTN mode for CRT1 */ + RealModeNo = ModeNo; + if(ModeNo == 0x5b) ModeNo = 0x56; + + SiSInitPtr(SiS_Pr); + SiSRegInit(SiS_Pr, BaseAddr); + SiS_GetSysFlags(SiS_Pr); + + SiS_Pr->SiS_VGAINFO = 0x11; + + KeepLockReg = SiS_GetReg(SiS_Pr->SiS_P3c4,0x05); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); + + SiSInitPCIetc(SiS_Pr); + SiSSetLVDSetc(SiS_Pr); + SiSDetermineROMUsage(SiS_Pr); + + SiS_UnLockCRT2(SiS_Pr); + + if(!SiS_Pr->UseCustomMode) { + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false; + } else { + ModeIdIndex = 0; + } + + SiS_GetVBType(SiS_Pr); + + /* Init/restore some VB registers */ + SiS_InitVB(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_ResetVB(SiS_Pr); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10); + SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c); + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + } else { + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + } + } + + /* Get VB information (connectors, connected devices) */ + SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, (SiS_Pr->UseCustomMode) ? 0 : 1); + SiS_SetYPbPr(SiS_Pr); + SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex); + SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex); + SiS_SetLowModeTest(SiS_Pr, ModeNo); + + /* Check memory size (kernel framebuffer driver only) */ + if(!SiS_CheckMemorySize(SiS_Pr, ModeNo, ModeIdIndex)) { + return false; + } + + SiS_OpenCRTC(SiS_Pr); + + if(SiS_Pr->UseCustomMode) { + SiS_Pr->CRT1UsesCustomMode = true; + SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock; + SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag; + } else { + SiS_Pr->CRT1UsesCustomMode = false; + } + + /* Set mode on CRT1 */ + if( (SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) || + (!(SiS_Pr->SiS_VBInfo & SwitchCRT2)) ) { + SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex); + } + + /* Set mode on CRT2 */ + if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA)) { + if( (SiS_Pr->SiS_VBType & VB_SISVB) || + (SiS_Pr->SiS_IF_DEF_LVDS == 1) || + (SiS_Pr->SiS_IF_DEF_CH70xx != 0) || + (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) { + SiS_SetCRT2Group(SiS_Pr, RealModeNo); + } + } + + SiS_HandleCRT1(SiS_Pr); + + SiS_StrangeStuff(SiS_Pr); + + SiS_DisplayOn(SiS_Pr); + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(!(SiS_IsDualEdge(SiS_Pr))) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); + } + } + } +#endif + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->ChipType >= SIS_315H) { +#ifdef CONFIG_FB_SIS_315 + if(!SiS_Pr->SiS_ROMNew) { + if(SiS_IsVAMode(SiS_Pr)) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); + } else { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE); + } + } + + SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg); + + if((IS_SIS650) && (SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0xfc)) { + if((ModeNo == 0x03) || (ModeNo == 0x10)) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x80); + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x56,0x08); + } + } + + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); + } +#endif + } else if((SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730)) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); + } + } + + SiS_CloseCRTC(SiS_Pr); + + SiS_Handle760(SiS_Pr); + + /* We never lock registers in XF86 */ + if(KeepLockReg != 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00); + + return true; +} + +#ifndef GETBITSTR +#define GENBITSMASK(mask) GENMASK(1?mask,0?mask) +#define GETBITS(var,mask) (((var) & GENBITSMASK(mask)) >> (0?mask)) +#define GETBITSTR(val,from,to) ((GETBITS(val,from)) << (0?to)) +#endif + +void +SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth) +{ + int x = 1; /* Fix sync */ + + SiS_Pr->CCRT1CRTC[0] = ((SiS_Pr->CHTotal >> 3) - 5) & 0xff; /* CR0 */ + SiS_Pr->CCRT1CRTC[1] = (SiS_Pr->CHDisplay >> 3) - 1; /* CR1 */ + SiS_Pr->CCRT1CRTC[2] = (SiS_Pr->CHBlankStart >> 3) - 1; /* CR2 */ + SiS_Pr->CCRT1CRTC[3] = (((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80; /* CR3 */ + SiS_Pr->CCRT1CRTC[4] = (SiS_Pr->CHSyncStart >> 3) + 3; /* CR4 */ + SiS_Pr->CCRT1CRTC[5] = ((((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) | /* CR5 */ + (((SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F); + + SiS_Pr->CCRT1CRTC[6] = (SiS_Pr->CVTotal - 2) & 0xFF; /* CR6 */ + SiS_Pr->CCRT1CRTC[7] = (((SiS_Pr->CVTotal - 2) & 0x100) >> 8) /* CR7 */ + | (((SiS_Pr->CVDisplay - 1) & 0x100) >> 7) + | (((SiS_Pr->CVSyncStart - x) & 0x100) >> 6) + | (((SiS_Pr->CVBlankStart- 1) & 0x100) >> 5) + | 0x10 + | (((SiS_Pr->CVTotal - 2) & 0x200) >> 4) + | (((SiS_Pr->CVDisplay - 1) & 0x200) >> 3) + | (((SiS_Pr->CVSyncStart - x) & 0x200) >> 2); + + SiS_Pr->CCRT1CRTC[16] = ((((SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5); /* CR9 */ + + if(depth != 8) { + if(SiS_Pr->CHDisplay >= 1600) SiS_Pr->CCRT1CRTC[16] |= 0x60; /* SRE */ + else if(SiS_Pr->CHDisplay >= 640) SiS_Pr->CCRT1CRTC[16] |= 0x40; + } + + SiS_Pr->CCRT1CRTC[8] = (SiS_Pr->CVSyncStart - x) & 0xFF; /* CR10 */ + SiS_Pr->CCRT1CRTC[9] = ((SiS_Pr->CVSyncEnd - x) & 0x0F) | 0x80; /* CR11 */ + SiS_Pr->CCRT1CRTC[10] = (SiS_Pr->CVDisplay - 1) & 0xFF; /* CR12 */ + SiS_Pr->CCRT1CRTC[11] = (SiS_Pr->CVBlankStart - 1) & 0xFF; /* CR15 */ + SiS_Pr->CCRT1CRTC[12] = (SiS_Pr->CVBlankEnd - 1) & 0xFF; /* CR16 */ + + SiS_Pr->CCRT1CRTC[13] = /* SRA */ + GETBITSTR((SiS_Pr->CVTotal -2), 10:10, 0:0) | + GETBITSTR((SiS_Pr->CVDisplay -1), 10:10, 1:1) | + GETBITSTR((SiS_Pr->CVBlankStart-1), 10:10, 2:2) | + GETBITSTR((SiS_Pr->CVSyncStart -x), 10:10, 3:3) | + GETBITSTR((SiS_Pr->CVBlankEnd -1), 8:8, 4:4) | + GETBITSTR((SiS_Pr->CVSyncEnd ), 4:4, 5:5) ; + + SiS_Pr->CCRT1CRTC[14] = /* SRB */ + GETBITSTR((SiS_Pr->CHTotal >> 3) - 5, 9:8, 1:0) | + GETBITSTR((SiS_Pr->CHDisplay >> 3) - 1, 9:8, 3:2) | + GETBITSTR((SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) | + GETBITSTR((SiS_Pr->CHSyncStart >> 3) + 3, 9:8, 7:6) ; + + + SiS_Pr->CCRT1CRTC[15] = /* SRC */ + GETBITSTR((SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) | + GETBITSTR((SiS_Pr->CHSyncEnd >> 3) + 3, 5:5, 2:2) ; +} + +void +SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) +{ + unsigned short modeflag, tempax, tempbx = 0, remaining = 0; + unsigned short VGAHDE = SiS_Pr->SiS_VGAHDE; + int i, j; + + /* 1:1 data: use data set by setcrt1crtc() */ + if(SiS_Pr->SiS_LCDInfo & LCDPass11) return; + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + if(modeflag & HalfDCLK) VGAHDE >>= 1; + + SiS_Pr->CHDisplay = VGAHDE; + SiS_Pr->CHBlankStart = VGAHDE; + + SiS_Pr->CVDisplay = SiS_Pr->SiS_VGAVDE; + SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE; + + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef CONFIG_FB_SIS_300 + tempbx = SiS_Pr->SiS_VGAHT; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempbx = SiS_Pr->PanelHT; + } + if(modeflag & HalfDCLK) tempbx >>= 1; + remaining = tempbx % 8; +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + /* OK for LCDA, LVDS */ + tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes; + tempax = SiS_Pr->SiS_VGAHDE; /* not /2 ! */ + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->PanelXRes; + } + tempbx += tempax; + if(modeflag & HalfDCLK) tempbx -= VGAHDE; +#endif + } + SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx; + + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->SiS_VGAHDE == SiS_Pr->PanelXRes) { + SiS_Pr->CHSyncStart = SiS_Pr->SiS_VGAHDE + ((SiS_Pr->PanelHRS + 1) & ~1); + SiS_Pr->CHSyncEnd = SiS_Pr->CHSyncStart + SiS_Pr->PanelHRE; + if(modeflag & HalfDCLK) { + SiS_Pr->CHSyncStart >>= 1; + SiS_Pr->CHSyncEnd >>= 1; + } + } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) >> 1; + tempbx = (SiS_Pr->PanelHRS + 1) & ~1; + if(modeflag & HalfDCLK) { + tempax >>= 1; + tempbx >>= 1; + } + SiS_Pr->CHSyncStart = (VGAHDE + tempax + tempbx + 7) & ~7; + tempax = SiS_Pr->PanelHRE + 7; + if(modeflag & HalfDCLK) tempax >>= 1; + SiS_Pr->CHSyncEnd = (SiS_Pr->CHSyncStart + tempax) & ~7; + } else { + SiS_Pr->CHSyncStart = SiS_Pr->SiS_VGAHDE; + if(modeflag & HalfDCLK) { + SiS_Pr->CHSyncStart >>= 1; + tempax = ((SiS_Pr->CHTotal - SiS_Pr->CHSyncStart) / 3) << 1; + SiS_Pr->CHSyncEnd = SiS_Pr->CHSyncStart + tempax; + } else { + SiS_Pr->CHSyncEnd = (SiS_Pr->CHSyncStart + (SiS_Pr->CHTotal / 10) + 7) & ~7; + SiS_Pr->CHSyncStart += 8; + } + } +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + tempax = VGAHDE; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempbx = SiS_Pr->PanelXRes; + if(modeflag & HalfDCLK) tempbx >>= 1; + tempax += ((tempbx - tempax) >> 1); + } + tempax += SiS_Pr->PanelHRS; + SiS_Pr->CHSyncStart = tempax; + tempax += SiS_Pr->PanelHRE; + SiS_Pr->CHSyncEnd = tempax; +#endif + } + + tempbx = SiS_Pr->PanelVT - SiS_Pr->PanelYRes; + tempax = SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->PanelYRes; + } else if(SiS_Pr->ChipType < SIS_315H) { +#ifdef CONFIG_FB_SIS_300 + /* Stupid hack for 640x400/320x200 */ + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if((tempax + tempbx) == 438) tempbx += 16; + } else if((SiS_Pr->SiS_LCDResInfo == Panel_800x600) || + (SiS_Pr->SiS_LCDResInfo == Panel_1024x600)) { + tempax = 0; + tempbx = SiS_Pr->SiS_VGAVT; + } +#endif + } + SiS_Pr->CVTotal = SiS_Pr->CVBlankEnd = tempbx + tempax; + + tempax = SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax += (SiS_Pr->PanelYRes - tempax) >> 1; + } + tempax += SiS_Pr->PanelVRS; + SiS_Pr->CVSyncStart = tempax; + tempax += SiS_Pr->PanelVRE; + SiS_Pr->CVSyncEnd = tempax; + if(SiS_Pr->ChipType < SIS_315H) { + SiS_Pr->CVSyncStart--; + SiS_Pr->CVSyncEnd--; + } + + SiS_CalcCRRegisters(SiS_Pr, 8); + SiS_Pr->CCRT1CRTC[15] &= ~0xF8; + SiS_Pr->CCRT1CRTC[15] |= (remaining << 4); + SiS_Pr->CCRT1CRTC[16] &= ~0xE0; + + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + for(i = 0, j = 0; i <= 7; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j = 0x10; i <= 10; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j = 0x15; i <= 12; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j = 0x0A; i <= 15; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]); + } + + tempax = SiS_Pr->CCRT1CRTC[16] & 0xE0; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1F,tempax); + + tempax = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5; + if(modeflag & DoubleScanMode) tempax |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax); + +} + +void +SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, + int xres, int yres, + struct fb_var_screeninfo *var, bool writeres +) +{ + unsigned short HRE, HBE, HRS, HBS, HDE, HT; + unsigned short VRE, VBE, VRS, VBS, VDE, VT; + unsigned char sr_data, cr_data, cr_data2; + int A, B, C, D, E, F, temp; + + sr_data = crdata[14]; + + /* Horizontal total */ + HT = crdata[0] | ((unsigned short)(sr_data & 0x03) << 8); + A = HT + 5; + + /* Horizontal display enable end */ + HDE = crdata[1] | ((unsigned short)(sr_data & 0x0C) << 6); + E = HDE + 1; + + /* Horizontal retrace (=sync) start */ + HRS = crdata[4] | ((unsigned short)(sr_data & 0xC0) << 2); + F = HRS - E - 3; + + /* Horizontal blank start */ + HBS = crdata[2] | ((unsigned short)(sr_data & 0x30) << 4); + + sr_data = crdata[15]; + cr_data = crdata[5]; + + /* Horizontal blank end */ + HBE = (crdata[3] & 0x1f) | + ((unsigned short)(cr_data & 0x80) >> 2) | + ((unsigned short)(sr_data & 0x03) << 6); + + /* Horizontal retrace (=sync) end */ + HRE = (cr_data & 0x1f) | ((sr_data & 0x04) << 3); + + temp = HBE - ((E - 1) & 255); + B = (temp > 0) ? temp : (temp + 256); + + temp = HRE - ((E + F + 3) & 63); + C = (temp > 0) ? temp : (temp + 64); + + D = B - F - C; + + if(writeres) var->xres = xres = E * 8; + var->left_margin = D * 8; + var->right_margin = F * 8; + var->hsync_len = C * 8; + + /* Vertical */ + sr_data = crdata[13]; + cr_data = crdata[7]; + + /* Vertical total */ + VT = crdata[6] | + ((unsigned short)(cr_data & 0x01) << 8) | + ((unsigned short)(cr_data & 0x20) << 4) | + ((unsigned short)(sr_data & 0x01) << 10); + A = VT + 2; + + /* Vertical display enable end */ + VDE = crdata[10] | + ((unsigned short)(cr_data & 0x02) << 7) | + ((unsigned short)(cr_data & 0x40) << 3) | + ((unsigned short)(sr_data & 0x02) << 9); + E = VDE + 1; + + /* Vertical retrace (=sync) start */ + VRS = crdata[8] | + ((unsigned short)(cr_data & 0x04) << 6) | + ((unsigned short)(cr_data & 0x80) << 2) | + ((unsigned short)(sr_data & 0x08) << 7); + F = VRS + 1 - E; + + cr_data2 = (crdata[16] & 0x01) << 5; + + /* Vertical blank start */ + VBS = crdata[11] | + ((unsigned short)(cr_data & 0x08) << 5) | + ((unsigned short)(cr_data2 & 0x20) << 4) | + ((unsigned short)(sr_data & 0x04) << 8); + + /* Vertical blank end */ + VBE = crdata[12] | ((unsigned short)(sr_data & 0x10) << 4); + temp = VBE - ((E - 1) & 511); + B = (temp > 0) ? temp : (temp + 512); + + /* Vertical retrace (=sync) end */ + VRE = (crdata[9] & 0x0f) | ((sr_data & 0x20) >> 1); + temp = VRE - ((E + F - 1) & 31); + C = (temp > 0) ? temp : (temp + 32); + + D = B - F - C; + + if(writeres) var->yres = yres = E; + var->upper_margin = D; + var->lower_margin = F; + var->vsync_len = C; + + if((xres == 320) && ((yres == 200) || (yres == 240))) { + /* Terrible hack, but correct CRTC data for + * these modes only produces a black screen... + * (HRE is 0, leading into a too large C and + * a negative D. The CRT controller does not + * seem to like correcting HRE to 50) + */ + var->left_margin = (400 - 376); + var->right_margin = (328 - 320); + var->hsync_len = (376 - 328); + + } + +} + + + + diff --git a/drivers/video/fbdev/sis/init.h b/drivers/video/fbdev/sis/init.h new file mode 100644 index 0000000..85d6738 --- /dev/null +++ b/drivers/video/fbdev/sis/init.h @@ -0,0 +1,1541 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Data and prototypes for init.c + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _INIT_H_ +#define _INIT_H_ + +#include "initdef.h" + +#include "vgatypes.h" +#include "vstruct.h" +#ifdef SIS_CP +#undef SIS_CP +#endif +#include <linux/types.h> +#include <asm/io.h> +#include <linux/fb.h> +#include "sis.h" +#include <video/sisfb.h> + +/* Mode numbers */ +static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; +static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; +static const unsigned short ModeIndex_320x240_FSTN[] = {0x5a, 0x5b, 0x00, 0x00}; /* FSTN */ +static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; +static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; +static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; +static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; +static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; +static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; +static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; +static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; +static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; +static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; +static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; +static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; /* 315 series only */ +static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; /* 315 series only */ +static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; +static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; +static const unsigned short ModeIndex_1024x600[] = {0x20, 0x21, 0x00, 0x22}; /* 300 series only */ +static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; +static const unsigned short ModeIndex_1280x960[] = {0x7c, 0x7d, 0x00, 0x7e}; +static const unsigned short ModeIndex_1152x768[] = {0x23, 0x24, 0x00, 0x25}; /* 300 series only */ +static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; +static const unsigned short ModeIndex_300_1280x768[] = {0x55, 0x5a, 0x00, 0x5b}; +static const unsigned short ModeIndex_310_1280x768[] = {0x23, 0x24, 0x00, 0x25}; +static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; +static const unsigned short ModeIndex_1280x800[] = {0x14, 0x15, 0x00, 0x16}; +static const unsigned short ModeIndex_1280x854[] = {0x1a, 0x1b, 0x00, 0x1c}; +static const unsigned short ModeIndex_1360x768[] = {0x48, 0x4b, 0x00, 0x4e}; +static const unsigned short ModeIndex_300_1360x1024[]= {0x67, 0x6f, 0x00, 0x72}; /* 300 series, BARCO only */ +static const unsigned short ModeIndex_1400x1050[] = {0x26, 0x27, 0x00, 0x28}; /* 315 series only */ +static const unsigned short ModeIndex_1680x1050[] = {0x17, 0x18, 0x00, 0x19}; /* 315 series only */ +static const unsigned short ModeIndex_1600x1200[] = {0x3c, 0x3d, 0x00, 0x66}; +static const unsigned short ModeIndex_1920x1080[] = {0x2c, 0x2d, 0x00, 0x73}; /* 315 series only */ +static const unsigned short ModeIndex_1920x1440[] = {0x68, 0x69, 0x00, 0x6b}; +static const unsigned short ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00}; +static const unsigned short ModeIndex_310_2048x1536[]= {0x6c, 0x6d, 0x00, 0x6e}; + +static const unsigned char SiS_MDA_DAC[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F +}; + +static const unsigned char SiS_CGA_DAC[] = +{ + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +}; + +static const unsigned char SiS_EGA_DAC[] = +{ + 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, + 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, + 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, + 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, + 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, + 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, + 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +}; + +static const unsigned char SiS_VGA_DAC[] = +{ + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, + 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, + 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, + 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, + 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, + 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, + 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, + 0x0B,0x0C,0x0D,0x0F,0x10 +}; + +static const struct SiS_St SiS_SModeIDTable[] = +{ + {0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00,0x40}, + {0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00,0x40}, + {0x01,0x1010,0x17,0x02,0x02,0x00,0x01,0x01,0x40}, + {0x03,0x8208,0x03,0x00,0x00,0x00,0x01,0x02,0x40}, + {0x03,0x0210,0x16,0x01,0x01,0x00,0x01,0x02,0x40}, + {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40}, + {0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x04,0x40}, + {0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x05,0x40}, + {0x07,0x0000,0x07,0x03,0x03,0x00,0x01,0x03,0x40}, + {0x07,0x0000,0x19,0x02,0x02,0x00,0x01,0x03,0x40}, + {0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x04,0x40}, + {0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x05,0x40}, + {0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x05,0x40}, + {0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x05,0x40}, + {0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x05,0x40}, + {0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x05,0x40}, + {0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x04,0x40}, + {0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x05,0x40}, + {0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x05,0x40}, + {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +}; + +static const struct SiS_StResInfo_S SiS_StResInfo[]= +{ + { 640,400}, + { 640,350}, + { 720,400}, + { 720,350}, + { 640,480} +}; + +static const struct SiS_ModeResInfo_S SiS_ModeResInfo[] = +{ + { 320, 200, 8, 8}, /* 0x00 */ + { 320, 240, 8, 8}, /* 0x01 */ + { 320, 400, 8, 8}, /* 0x02 */ + { 400, 300, 8, 8}, /* 0x03 */ + { 512, 384, 8, 8}, /* 0x04 */ + { 640, 400, 8,16}, /* 0x05 */ + { 640, 480, 8,16}, /* 0x06 */ + { 800, 600, 8,16}, /* 0x07 */ + { 1024, 768, 8,16}, /* 0x08 */ + { 1280,1024, 8,16}, /* 0x09 */ + { 1600,1200, 8,16}, /* 0x0a */ + { 1920,1440, 8,16}, /* 0x0b */ + { 2048,1536, 8,16}, /* 0x0c */ + { 720, 480, 8,16}, /* 0x0d */ + { 720, 576, 8,16}, /* 0x0e */ + { 1280, 960, 8,16}, /* 0x0f */ + { 800, 480, 8,16}, /* 0x10 */ + { 1024, 576, 8,16}, /* 0x11 */ + { 1280, 720, 8,16}, /* 0x12 */ + { 856, 480, 8,16}, /* 0x13 */ + { 1280, 768, 8,16}, /* 0x14 */ + { 1400,1050, 8,16}, /* 0x15 */ + { 1152, 864, 8,16}, /* 0x16 */ + { 848, 480, 8,16}, /* 0x17 */ + { 1360, 768, 8,16}, /* 0x18 */ + { 1024, 600, 8,16}, /* 0x19 */ + { 1152, 768, 8,16}, /* 0x1a */ + { 768, 576, 8,16}, /* 0x1b */ + { 1360,1024, 8,16}, /* 0x1c */ + { 1680,1050, 8,16}, /* 0x1d */ + { 1280, 800, 8,16}, /* 0x1e */ + { 1920,1080, 8,16}, /* 0x1f */ + { 960, 540, 8,16}, /* 0x20 */ + { 960, 600, 8,16}, /* 0x21 */ + { 1280, 854, 8,16} /* 0x22 */ +}; + +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) +static const struct SiS_StandTable_S SiS_StandTable[]= +{ +/* 0x00: MD_0_200 */ + { + 0x28,0x18,0x08,0x0800, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x01: MD_1_200 */ + { + 0x28,0x18,0x08,0x0800, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x02: MD_2_200 */ + { + 0x50,0x18,0x08,0x1000, + {0x01,0x03,0x00,0x02}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x03: MD_3_200 - mode 0x03 - 0 */ + { + 0x50,0x18,0x08,0x1000, + {0x01,0x03,0x00,0x02}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x04: MD_4 */ + { + 0x28,0x18,0x08,0x4000, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 0x2c is 2b for 300 */ + 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2, + 0xff}, + {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x03,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00, + 0xff} + }, +/* 0x05: MD_5 */ + { + 0x28,0x18,0x08,0x4000, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 0x2c is 2b for 300 */ + 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2, + 0xff}, + {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x03,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00, + 0xff} + }, +/* 0x06: MD_6 */ + { + 0x50,0x18,0x08,0x4000, + {0x01,0x01,0x00,0x06}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 for 300 */ + 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2, + 0xff}, + {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17, + 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, + 0x01,0x00,0x01,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00, + 0xff} + }, +/* 0x07: MD_7 */ + { + 0x50,0x18,0x0e,0x1000, + {0x00,0x03,0x00,0x03}, + 0xa6, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3, + 0xff}, + {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x0e,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00, + 0xff} + }, +/* 0x08: MDA_DAC */ + { + 0x00,0x00,0x00,0x0000, + {0x00,0x00,0x00,0x15}, + 0x15, + {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00, + 0x00}, + {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15}, + {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f} + }, +/* 0x09: CGA_DAC */ + { + 0x00,0x10,0x04,0x0114, + {0x11,0x09,0x15,0x00}, + 0x10, + {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a, + 0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a, + 0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10, + 0x04}, + {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04, + 0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e, + 0x3e,0x2b,0x3b,0x2f}, + {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f, + 0x3f} + }, +/* 0x0a: EGA_DAC */ + { + 0x00,0x10,0x04,0x0114, + {0x11,0x05,0x15,0x20}, + 0x30, + {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18, + 0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38, + 0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12, + 0x06}, + {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26, + 0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e, + 0x1e,0x0b,0x1b,0x0f}, + {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f, + 0x3f} + }, +/* 0x0b: VGA_DAC */ + { + 0x00,0x10,0x04,0x0114, + {0x11,0x09,0x15,0x2a}, + 0x3a, + {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05, + 0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20, + 0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10, + 0x1f}, + {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d, + 0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15, + 0x1c,0x0e,0x11,0x15}, + {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00, + 0x04} + }, +/* 0x0c */ + { + 0x08,0x0c,0x10,0x0a08, + {0x0c,0x0e,0x10,0x0b}, + 0x0c, + {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00, + 0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00, + 0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00, + 0x06}, + {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08, + 0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00, + 0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00} + }, +/* 0x0d: MD_D */ + { + 0x28,0x18,0x08,0x2000, + {0x09,0x0f,0x00,0x06}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 2c is 2b for 300 */ + 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* 0x0e: MD_E */ + { + 0x50,0x18,0x08,0x4000, + {0x01,0x0f,0x00,0x06}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 for 300 */ + 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* 0x0f: ExtVGATable - modes > 0x13 */ + { + 0x00,0x00,0x00,0x0000, + {0x01,0x0f,0x00,0x0e}, + 0x23, + {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x01,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, + 0xff} + }, +/* 0x10: ROM_SAVEPTR - totally different for 300 */ + { + 0x9f,0x3b,0x00,0x00c0, + {0x00,0x00,0x00,0x00}, + 0x00, + {0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x3f, + 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x1a,0x00,0xac,0x3e,0x00,0xc0, + 0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00} + }, +/* 0x11: MD_F */ + { + 0x50,0x18,0x0e,0x8000, + {0x01,0x0f,0x00,0x06}, + 0xa2, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 on 300 */ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3, /* 82,84 is 83,85 on 300 */ + 0xff}, + {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00, + 0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00, + 0x0b,0x00,0x05,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05, + 0xff} + }, +/* 0x12: MD_10 */ + { + 0x50,0x18,0x0e,0x8000, + {0x01,0x0f,0x00,0x06}, + 0xa3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 on 300 */ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3, /* 82,84 is 83,85 on 300 */ + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* 0x13: MD_0_350 */ + { + 0x28,0x18,0x0e,0x0800, + {0x09,0x03,0x00,0x02}, + 0xa3, + {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f, /* b1 is a0 on 300 */ + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x14: MD_1_350 */ + { + 0x28,0x18,0x0e,0x0800, + {0x09,0x03,0x00,0x02}, + 0xa3, + {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x15: MD_2_350 */ + { + 0x50,0x18,0x0e,0x1000, + {0x01,0x03,0x00,0x02}, + 0xa3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x16: MD_3_350 - mode 0x03 - 1 */ + { + 0x50,0x18,0x0e,0x1000, + {0x01,0x03,0x00,0x02}, + 0xa3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x17: MD_0_1_400 */ + { + 0x28,0x18,0x10,0x0800, + {0x08,0x03,0x00,0x02}, + 0x67, + {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f, /* b1 is a0 on 300 */ + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x0c,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x18: MD_2_3_400 - mode 0x03 - 2 */ + { + 0x50,0x18,0x10,0x1000, + {0x00,0x03,0x00,0x02}, + 0x67, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x0c,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* 0x19: MD_7_400 */ + { + 0x50,0x18,0x10,0x1000, + {0x00,0x03,0x00,0x02}, + 0x66, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x0e,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00, + 0xff} + }, +/* 0x1a: MD_11 */ + { + 0x50,0x1d,0x10,0xa000, + {0x01,0x0f,0x00,0x06}, + 0xe3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, /* 55,81 is 54,80 on 300 */ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xc3, /* e9,8b is ea,8c on 300 */ + 0xff}, + {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01, + 0xff} + }, +/* 0x1b: ExtEGATable - Modes <= 0x02 */ + { + 0x50,0x1d,0x10,0xa000, + {0x01,0x0f,0x00,0x06}, + 0xe3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, /* 55,81 is 54,80 on 300 */ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3, /* e9,8b is ea,8c on 300 */ + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* 0x1c: MD_13 */ + { + 0x28,0x18,0x08,0x2000, + {0x01,0x0f,0x00,0x0e}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, /* 55,81 is 54,80 on 300 */ + 0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x41,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, + 0xff} + } +}; +#endif + +/**************************************************************/ +/* SIS VIDEO BRIDGE ----------------------------------------- */ +/**************************************************************/ + +static const unsigned char SiS_SoftSetting = 0x30; /* RAM setting */ + +static const unsigned char SiS_OutputSelect = 0x40; + +static const unsigned char SiS_NTSCTiming[] = { + 0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c, + 0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b, + 0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17, + 0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02, + 0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50, + 0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00 +}; + +static const unsigned char SiS_PALTiming[] = { + 0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70, + 0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b, + 0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17, + 0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02, + 0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63, + 0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00 +}; + +static const unsigned char SiS_HiTVExtTiming[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64, + 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, + 0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13, + 0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40, + 0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d, + 0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00 +}; + +static const unsigned char SiS_HiTVSt1Timing[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65, + 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, + 0x65,0x90,0x7b,0xa8,0x03,0xf0,0x87,0x03, + 0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10, + 0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86, + 0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00 +}; + +static const unsigned char SiS_HiTVSt2Timing[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64, + 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, + 0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13, + 0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40, + 0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d, + 0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00 +}; + +#if 0 +static const unsigned char SiS_HiTVTextTiming[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65, + 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, + 0x65,0x90,0xe7,0xbc,0x03,0x0c,0x97,0x03, + 0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20, + 0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96, + 0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00 +}; +#endif + +static const unsigned char SiS_HiTVGroup3Data[] = { + 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f, + 0x05,0x21,0xb2,0xb2,0x55,0x77,0x2a,0xa6, + 0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20, + 0x8c,0x6e,0x60,0x2e,0x58,0x48,0x72,0x44, + 0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80, + 0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9, + 0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4c,0xa8,0x01 +}; + +static const unsigned char SiS_HiTVGroup3Simu[] = { + 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x95, + 0xdb,0x20,0xb8,0xb8,0x55,0x47,0x2a,0xa6, + 0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20, + 0x8c,0x6e,0x60,0x15,0x26,0xd3,0xe4,0x11, + 0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80, + 0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4, + 0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4c,0xa8,0x01 +}; + +#if 0 +static const unsigned char SiS_HiTVGroup3Text[] = { + 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7, + 0xf5,0x20,0xce,0xce,0x55,0x47,0x2a,0xa6, + 0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20, + 0x8c,0x6e,0x60,0x18,0x2c,0x0c,0x20,0x22, + 0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80, + 0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca, + 0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4c,0xa8,0x01 +}; +#endif + +static const struct SiS_TVData SiS_StPALData[] = +{ + { 1, 1, 864, 525,1270, 400, 100, 0, 760, 0,0xf4,0xff,0x1c,0x22}, + { 1, 1, 864, 525,1270, 350, 100, 0, 760, 0,0xf4,0xff,0x1c,0x22}, + { 1, 1, 864, 525,1270, 400, 0, 0, 720, 0,0xf1,0x04,0x1f,0x18}, + { 1, 1, 864, 525,1270, 350, 0, 0, 720, 0,0xf4,0x0b,0x1c,0x0a}, + { 1, 1, 864, 525,1270, 480, 50, 0, 760, 0,0xf4,0xff,0x1c,0x22}, + { 1, 1, 864, 525,1270, 600, 50, 0, 0,0x300,0xf4,0xff,0x1c,0x22} +}; + +static const struct SiS_TVData SiS_ExtPALData[] = +{ + { 27, 10, 848, 448,1270, 530, 50, 0, 50, 0,0xf4,0xff,0x1c,0x22}, /* 640x400, 320x200 */ + { 108, 35, 848, 398,1270, 530, 50, 0, 50, 0,0xf4,0xff,0x1c,0x22}, + { 12, 5, 954, 448,1270, 530, 50, 0, 50, 0,0xf1,0x04,0x1f,0x18}, + { 9, 4, 960, 463,1644, 438, 50, 0, 50, 0,0xf4,0x0b,0x1c,0x0a}, + { 9, 4, 848, 528,1270, 530, 0, 0, 50, 0,0xf5,0xfb,0x1b,0x2a}, /* 640x480, 320x240 */ + { 36, 25,1060, 648,1270, 530, 438, 0, 438, 0,0xeb,0x05,0x25,0x16}, /* 800x600, 400x300 */ + { 3, 2,1080, 619,1270, 540, 438, 0, 438, 0,0xf3,0x00,0x1d,0x20}, /* 720x576 */ + { 1, 1,1170, 821,1270, 520, 686, 0, 686, 0,0xF3,0x00,0x1D,0x20}, /* 1024x768 */ + { 1, 1,1170, 821,1270, 520, 686, 0, 686, 0,0xF3,0x00,0x1D,0x20}, /* 1024x768 (for NTSC equ) */ + { 9, 4, 848, 528,1270, 530, 0, 0, 50, 0,0xf5,0xfb,0x1b,0x2a} /* 720x480 */ +}; + +static const struct SiS_TVData SiS_StNTSCData[] = +{ + { 1, 1, 858, 525,1270, 400, 50, 0, 760, 0,0xf1,0x04,0x1f,0x18}, + { 1, 1, 858, 525,1270, 350, 50, 0, 640, 0,0xf1,0x04,0x1f,0x18}, + { 1, 1, 858, 525,1270, 400, 0, 0, 720, 0,0xf1,0x04,0x1f,0x18}, + { 1, 1, 858, 525,1270, 350, 0, 0, 720, 0,0xf4,0x0b,0x1c,0x0a}, + { 1, 1, 858, 525,1270, 480, 0, 0, 760, 0,0xf1,0x04,0x1f,0x18} +}; + +static const struct SiS_TVData SiS_ExtNTSCData[] = +{ + { 143, 65, 858, 443,1270, 440, 171, 0, 171, 0,0xf1,0x04,0x1f,0x18}, /* 640x400, 320x200 */ + { 88, 35, 858, 393,1270, 440, 171, 0, 171, 0,0xf1,0x04,0x1f,0x18}, + { 143, 70, 924, 443,1270, 440, 92, 0, 92, 0,0xf1,0x04,0x1f,0x18}, + { 143, 70, 924, 393,1270, 440, 92, 0, 92, 0,0xf4,0x0b,0x1c,0x0a}, + { 143, 76, 836, 523,1270, 440, 224, 0, 0, 0,0xf1,0x05,0x1f,0x16}, /* 640x480, 320x240 */ + { 143, 120,1056, 643,1270, 440, 0, 1, 0, 0,0xf4,0x10,0x1c,0x00}, /* 800x600, 400x300 */ + { 143, 76, 836, 523,1270, 440, 0, 1, 0, 0,0xee,0x0c,0x22,0x08}, /* 720x480 - BETTER (from 300 series) */ + { 1, 1,1100, 811,1412, 440, 0, 1, 0, 0,0xee,0x0c,0x22,0x08}, /* 1024x768 (525i) CORRECTED */ +#if 0 /* flimmert und ist unten abgeschnitten (NTSCHT, NTSC clock) */ + { 65, 64,1056, 791,1270, 480, 455, 0, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 + { 1, 1,1100, 811,1412, 440, 0, 1, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 + { 1, 1,1120, 821,1516, 420, 0, 1, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 + { 1, 1, 938, 821,1516, 420, 0, 1, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 /* zoom hin, unten abgeschnitten (NTSC2HT, NTSC1024 clock) */ + { 1, 1,1072, 791,1270, 480, 455, 0, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 1 /* zu weit links (squeezed) (NTSC2HT, NTSC1024 clock) */ + { 1, 1,1100, 846,1270, 440, 455, 0, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 /* zu weit links, rechts abgeschnitten (NTSC2HT, NTSC1024 clock) */ + { 1, 1,1100, 846,1412, 440, 455, 0, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +}; + +static const struct SiS_TVData SiS_StHiTVData[] = /* Slave + TVSimu */ +{ + { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x150, 1, 0, 0, 0, 0, 0, 0} +}; + +static const struct SiS_TVData SiS_St2HiTVData[] = /* Slave */ +{ + { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0, 0, 0, 0, 0}, + { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0, 0, 0, 0, 0}, + { 5, 2, 0x348,0x233,0x670,0x3c0,0x08d, 1, 0, 0, 0, 0, 0, 0}, + { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x17c, 1, 0, 0, 0, 0, 0, 0} +}; + +static const struct SiS_TVData SiS_ExtHiTVData[] = +{ /* all ok */ + { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 5, 1, 0x348,0x233,0x670,0x3c0,0x166, 1, 0, 0, 0, 0, 0, 0}, /* 640x480 */ + { 16, 5, 0x41a,0x2ab,0x670,0x3c0,0x143, 1, 0, 0, 0, 0, 0, 0}, /* 800x600 */ + { 25, 12, 0x4ec,0x353,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, /* 1024x768 */ + { 5, 4, 0x627,0x464,0x670,0x3c0,0x128, 0, 0, 0, 0, 0, 0, 0}, /* 1280x1024 */ + { 4, 1, 0x41a,0x233,0x60c,0x3c0,0x143, 1, 0, 0, 0, 0, 0, 0}, /* 800x480 */ + { 5, 2, 0x578,0x293,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, /* 1024x576 */ + { 8, 5, 0x6d6,0x323,0x670,0x3c0,0x128, 0, 0, 0, 0, 0, 0, 0}, /* 1280x720 */ + { 8, 3, 0x4ec,0x353,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, /* 960x600 */ +}; + +static const struct SiS_TVData SiS_St525pData[] = +{ + { 1, 1, 0x6b4,0x20d,0x4f6,0x190, 50, 0, 0x2f8, 0, 0, 0, 0, 0}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x15e, 50, 0, 0x280, 0, 0, 0, 0, 0}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x190, 50, 0, 0x2f8, 0, 0, 0, 0, 0}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x15e, 50, 0, 0x280, 0, 0, 0, 0, 0}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x1e0, 0, 0, 0x2f8, 0, 0, 0, 0, 0} +}; + +static const struct SiS_TVData SiS_St750pData[] = +{ + { 1, 1, 0x672,0x2ee,0x500,0x190, 50, 0, 0x2f8, 0, 0, 0, 0, 0}, + { 1, 1, 0x672,0x2ee,0x500,0x15e, 50, 0, 0x280, 0, 0, 0, 0, 0}, + { 1, 1, 0x672,0x2ee,0x500,0x190, 0, 0, 0x2d0, 0, 0, 0, 0, 0}, + { 1, 1, 0x672,0x2ee,0x500,0x15e, 0, 0, 0x2d0, 0, 0, 0, 0, 0}, + { 1, 1, 0x672,0x2ee,0x500,0x1e0, 0, 0, 0x2f8, 0, 0, 0, 0, 0} +}; + +static const struct SiS_TVData SiS_Ext750pData[] = +{ /* all ok */ + { 3, 1, 935, 470, 1130, 680, 50, 0, 0, 0, 0, 0, 0, 0}, /* 320x200/640x400 */ + { 24, 7, 935, 420, 1130, 680, 50, 0, 0, 0, 0, 0, 0, 0}, + { 3, 1, 935, 470, 1130, 680, 50, 0, 0, 0, 0, 0, 0, 0}, + { 24, 7, 935, 420, 1130, 680, 50, 0, 0, 0, 0, 0, 0, 0}, + { 2, 1, 1100, 590, 1130, 640, 50, 0, 0, 0, 0, 0, 0, 0}, /* 640x480 */ + { 3, 2, 1210, 690, 1130, 660, 50, 0, 0, 0, 0, 0, 0, 0}, /* 800x600 OK */ + { 2, 1, 1100, 562, 1130, 640, 0, 1, 0, 0, 0, 0, 0, 0}, /* 720x480 OK */ + { 1, 1, 1375, 878, 1130, 640, 638, 0, 0, 0, 0, 0, 0, 0}, /* 1024x768 OK */ + { 5, 3, 1100, 675, 1130, 640, 0, 1, 0, 0, 0, 0, 0, 0}, /* 720/768x576 OK */ + { 25, 24, 1496, 755, 1120, 680, 50, 0, 0, 0, 0, 0, 0, 0} /* 1280x720 OK */ +}; + +static const struct SiS_LCDData SiS_LCD1280x720Data[] = /* 2.03.00 */ +{ + { 44, 15, 864, 430, 1408, 806 }, /* 640x400 */ + { 128, 35, 792, 385, 1408, 806 }, + { 44, 15, 864, 430, 1408, 806 }, + { 128, 35, 792, 385, 1408, 806 }, + { 22, 9, 864, 516, 1408, 806 }, /* 640x480 */ + { 8, 5, 1056, 655, 1408, 806 }, /* 800x600 */ + { 0, 0, 0, 0, 0, 0 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 806, 1408, 806 } /* 1280x720 */ +}; + +/* About 1280x768: For TMDS, Panel_1280x768 will only be set if + * the panel is a Fujitsu 7911 (VL-17WDX8) (with clock 81, 1688x802) + * Other TMDS panels of this resolution will be treated as custom. + * For LVDS, we know another type (_2). + * (Note: 1280x768_3 is now special for SiS301/NetVista + */ + +static const struct SiS_LCDData SiS_StLCD1280x768_2Data[] = /* 2.03.00 */ +{ + { 64, 21, 858, 434, 1408, 806 }, /* 640x400 */ + { 32, 9, 858, 372, 1408, 806 }, + { 64, 21, 858, 434, 1408, 806 }, + { 32, 9, 858, 372, 1408, 806 }, + { 143, 68, 1024, 527, 1408, 806 }, /* 640x480 */ + { 64, 51, 1364, 663, 1408, 806 }, /* 800x600 */ + { 88, 81, 1296, 806, 1408, 806 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 806, 1408, 806 }, /* 1280x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 16, 15, 1600, 750, 1600, 806 } /* 1280x720 - from Ext */ +}; + +static const struct SiS_LCDData SiS_ExtLCD1280x768_2Data[] = /* 2.03.00 */ +{ + { 16, 5, 960, 410, 1600, 806 }, /* 640x400 */ + { 64, 21, 1152, 364, 1600, 806 }, + { 16, 5, 960, 410, 1600, 806 }, + { 64, 21, 1152, 364, 1600, 806 }, + { 32, 13, 1040, 493, 1600, 806 }, /* 640x480 */ + { 16, 9, 1152, 618, 1600, 806 }, /* 800x600 */ + { 25, 21, 1344, 796, 1600, 806 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1600, 806, 1600, 806 }, /* 1280x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 16, 15, 1600, 750, 1600, 806 } /* 1280x720 */ +}; + +#if 0 /* Not used; _3 now reserved for NetVista (SiS301) */ +static const struct SiS_LCDData SiS_LCD1280x768_3Data[] = +{ + { 64, 25, 1056, 422, 1664, 798 }, /* 640x400 */ + { 128, 39, 884, 396, 1408, 806 }, /* ,640 */ + { 64, 25, 1056, 422, 1664, 798 }, /* 640x400 */ + { 128, 39, 884, 396, 1408, 806 }, /* ,640 */ + { 32, 15, 1056, 513, 1408, 806 }, /* ,664 */ /* 640x480 */ + { 176, 125, 1280, 640, 1408, 806 }, /* ,768 */ /* 800x600 */ + { 64, 61, 1342, 806, 1408, 806 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 806, 1408, 806 }, /* 1280x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 16, 15, 1600, 750, 1600, 806 } /* 1280x720 from above */ +}; +#endif + +static const struct SiS_LCDData SiS_LCD1280x800Data[] = /* 0.93.12a (TMDS) */ +{ + { 128, 51, 1122, 412, 1408, 816 }, /* 640x400 */ + { 128, 49, 1232, 361, 1408, 816 }, + { 128, 51, 1122, 412, 1408, 816 }, + { 128, 49, 1232, 361, 1408, 816 }, + { 8, 3, 880, 491, 1408, 816 }, /* 640x480 */ + { 11, 6, 1024, 612, 1408, 816 }, /* 800x600 */ + { 22, 21, 1400, 784, 1408, 816 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 1, 1, 1408, 816, 1408, 816 }, /* 1280x800 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x768 (patch index) */ + { 0, 0, 0, 0, 0, 0 } /* 1280x720 */ +}; + +static const struct SiS_LCDData SiS_LCD1280x800_2Data[] = /* 2.03.00 (LVDS) */ +{ + { 97, 42, 1344, 409, 1552, 812 }, /* 640x400 */ + { 97, 35, 1280, 358, 1552, 812 }, + { 97, 42, 1344, 409, 1552, 812 }, + { 97, 35, 1280, 358, 1552, 812 }, + { 97, 39, 1040, 488, 1552, 812 }, /* 640x480 */ + { 194, 105, 1120, 608, 1552, 812 }, /* 800x600 */ + { 97, 84, 1400, 780, 1552, 812 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 1, 1, 1552, 812, 1552, 812 }, /* 1280x800 */ + { 97, 96, 1600, 780, 1552, 812 }, /* 1280x768 - patch index */ + { 97, 90, 1600, 730, 1552, 812 } /* 1280x720 */ +}; + +#if 0 +static const struct SiS_LCDData SiS_LCD1280x800_3Data[] = /* 2.02.05a (LVDS); m250 */ +{ + { 128, 51, 1122, 412, 1408, 816 }, /* 640x400 */ + { 128, 49, 1232, 361, 1408, 816 }, + { 128, 51, 1122, 412, 1408, 816 }, + { 128, 49, 1232, 361, 1408, 816 }, + { 8, 3, 880, 491, 1408, 816 }, /* 640x480 */ + { 11, 6, 1024, 612, 1408, 816 }, /* 800x600 */ + { 22, 21, 1400, 784, 1408, 816 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 1, 1, 1408, 816, 1408, 816 }, /* 1280x800 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x768 - patch index */ + { 0, 0, 0, 0, 0, 0 } /* 1280x720 */ +}; +#endif + +static const struct SiS_LCDData SiS_LCD1280x854Data[] = /* 2.21.00CS (LVDS) */ +{ + { 56, 15, 936, 410, 1664, 861 }, /* 640x400 */ + { 64, 25, 1586, 355, 1664, 861 }, + { 56, 15, 936, 410, 1664, 861 }, + { 64, 25, 1586, 355, 1664, 861 }, + { 91, 45, 1464, 485, 1664, 861 }, /* 640x480 */ + { 182, 75, 976, 605, 1664, 861 }, /* 800x600 */ + { 91, 66, 1342, 774, 1664, 861 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 26, 25, 1708, 807, 1664, 861 }, /* 1280x800 */ + { 13, 12, 1708, 774, 1664, 861 }, /* 1280x768 - patch index */ + { 52, 45, 1708, 725, 1664, 861 }, /* 1280x720 */ + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1664, 861, 1664, 861 } /* 1280x854 */ +}; + +static const struct SiS_LCDData SiS_LCD1280x960Data[] = +{ + { 9, 2, 800, 500, 1800, 1000 }, + { 9, 2, 800, 500, 1800, 1000 }, + { 4, 1, 900, 500, 1800, 1000 }, + { 4, 1, 900, 500, 1800, 1000 }, + { 9, 2, 800, 500, 1800, 1000 }, + { 30, 11, 1056, 625, 1800, 1000 }, + { 5, 3, 1350, 800, 1800, 1000 }, + { 1, 1, 1576, 1050, 1576, 1050 }, + { 1, 1, 1800, 1000, 1800, 1000 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +static const struct SiS_LCDData SiS_StLCD1400x1050Data[] = +{ + { 211, 100, 2100, 408, 1688, 1066 }, + { 211, 64, 1536, 358, 1688, 1066 }, + { 211, 100, 2100, 408, 1688, 1066 }, + { 211, 64, 1536, 358, 1688, 1066 }, + { 211, 48, 840, 488, 1688, 1066 }, + { 211, 72, 1008, 609, 1688, 1066 }, + { 211, 128, 1400, 776, 1688, 1066 }, + { 211, 205, 1680, 1041, 1688, 1066 }, + { 1, 1, 1688, 1066, 1688, 1066 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +static const struct SiS_LCDData SiS_ExtLCD1400x1050Data[] = +{ +/* { 211, 60, 1260, 410, 1688, 1066 }, 640x400 (6330) */ + { 211, 100, 2100, 408, 1688, 1066 }, /* 640x400 (6325) WORKS */ + { 211, 64, 1536, 358, 1688, 1066 }, + { 211, 100, 2100, 408, 1688, 1066 }, + { 211, 64, 1536, 358, 1688, 1066 }, +/* { 211, 80, 1400, 490, 1688, 1066 }, 640x480 (6330) */ + { 211, 48, 840, 488, 1688, 1066 }, /* 640x480 (6325) WORKS */ +/* { 211, 117, 1638, 613, 1688, 1066 }, 800x600 (6330) */ + { 211, 72, 1008, 609, 1688, 1066 }, /* 800x600 (6325) WORKS */ + { 211, 128, 1400, 776, 1688, 1066 }, /* 1024x768 */ + { 211, 205, 1680, 1041, 1688, 1066 }, /* 1280x1024 - not used (always unscaled) */ + { 1, 1, 1688, 1066, 1688, 1066 }, /* 1400x1050 */ + { 0, 0, 0, 0, 0, 0 }, /* kludge */ + { 211, 120, 1400, 730, 1688, 1066 }, /* 1280x720 */ + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +static const struct SiS_LCDData SiS_LCD1680x1050Data[] = +{ + { 95, 24, 1260, 410, 1900, 1066 }, /* 0 640x400 */ + { 10, 3, 1710, 362, 1900, 1066 }, + { 95, 24, 1260, 410, 1900, 1066 }, + { 10, 3, 1710, 362, 1900, 1066 }, + { 95, 32, 1400, 490, 1900, 1066 }, /* 4 640x480 */ + { 95, 42, 1470, 610, 1900, 1066 }, /* 5 800x600 */ + { 95, 64, 1750, 784, 1900, 1066 }, /* 6 1024x768 */ + { 95, 94, 1900, 1055, 1900, 1066 }, /* 7 1280x1024 */ + { 41, 31, 1900, 806, 1900, 1066 }, /* 8 1280x768 */ + { 95, 69, 1800, 817, 1900, 1066 }, /* 9 1280x800 patch index */ + { 13, 9, 1900, 739, 1900, 1066 }, /* 10 1280x720 */ + { 95, 94, 1880, 1066, 1900, 1066 }, /* 11 1400x1050 patch index */ + { 1, 1, 1900, 1066, 1900, 1066 }, /* 12 1680x1050 */ + { 0, 0, 0, 0, 0, 0 } +}; + +static const struct SiS_LCDData SiS_StLCD1600x1200Data[] = +{ + {27, 4, 800, 500, 2160, 1250 }, + {27, 4, 800, 500, 2160, 1250 }, + { 6, 1, 900, 500, 2160, 1250 }, + { 6, 1, 900, 500, 2160, 1250 }, + {27, 1, 800, 500, 2160, 1250 }, + { 4, 1,1080, 625, 2160, 1250 }, + { 5, 2,1350, 800, 2160, 1250 }, + {135,88,1600,1100, 2160, 1250 }, + {72, 49,1680,1092, 2160, 1250 }, + { 1, 1,2160,1250, 2160, 1250 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +static const struct SiS_LCDData SiS_ExtLCD1600x1200Data[] = +{ + {72,11, 990, 422, 2160, 1250 }, /* 640x400 (6330) WORKS */ +/* {27, 4, 800, 500, 2160, 1250 }, 640x400 (6235) */ + {27, 4, 800, 500, 2160, 1250 }, + { 6, 1, 900, 500, 2160, 1250 }, + { 6, 1, 900, 500, 2160, 1250 }, + {45, 8, 960, 505, 2160, 1250 }, /* 640x480 (6330) WORKS */ +/* {27, 1, 800, 500, 2160, 1250 }, 640x480 (6325) */ + { 4, 1,1080, 625, 2160, 1250 }, + { 5, 2,1350, 800, 2160, 1250 }, + {27,16,1500,1064, 2160, 1250 }, /* 1280x1024 */ + {72,49,1680,1092, 2160, 1250 }, /* 1400x1050 (6330, was not supported on 6325) */ + { 1, 1,2160,1250, 2160, 1250 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +static const struct SiS_LCDData SiS_NoScaleData[] = +{ + { 1, 1, 800, 449, 800, 449 }, /* 0x00: 320x200, 640x400 */ + { 1, 1, 800, 449, 800, 449 }, + { 1, 1, 900, 449, 900, 449 }, + { 1, 1, 900, 449, 900, 449 }, + { 1, 1, 800, 525, 800, 525 }, /* 0x04: 320x240, 640x480 */ + { 1, 1,1056, 628,1056, 628 }, /* 0x05: 400x300, 800x600 */ + { 1, 1,1344, 806,1344, 806 }, /* 0x06: 512x384, 1024x768 */ + { 1, 1,1688,1066,1688,1066 }, /* 0x07: 1280x1024 */ + { 1, 1,1688, 802,1688, 802 }, /* 0x08: 1280x768: Fujitsu, TMDS only */ + { 1, 1,2160,1250,2160,1250 }, /* 0x09: 1600x1200 */ + { 1, 1,1800,1000,1800,1000 }, /* 0x0a: 1280x960 */ + { 1, 1,1688,1066,1688,1066 }, /* 0x0b: 1400x1050 */ + { 1, 1,1650, 750,1650, 750 }, /* 0x0c: 1280x720 (TMDS, projector) */ + { 1, 1,1552, 812,1552, 812 }, /* 0x0d: 1280x800_2 (LVDS) (was: 1408,816/ 1656,841) */ + { 1, 1,1900,1066,1900,1066 }, /* 0x0e: 1680x1050 (LVDS) */ + { 1, 1,1660, 806,1660, 806 }, /* 0x0f: 1280x768_2 (LVDS) */ + { 1, 1,1664, 798,1664, 798 }, /* 0x10: 1280x768_3 (NetVista SiS 301) - TODO */ + { 1, 1,1688, 802,1688, 802 }, /* 0x11: 1280x768 (TMDS Fujitsu) */ + { 1, 1,1408, 806,1408, 806 }, /* 0x12: 1280x720 (LVDS) */ + { 1, 1, 896, 497, 896, 497 }, /* 0x13: 720x480 */ + { 1, 1, 912, 597, 912, 597 }, /* 0x14: 720x576 */ + { 1, 1, 912, 597, 912, 597 }, /* 0x15: 768x576 */ + { 1, 1,1056, 497,1056, 497 }, /* 0x16: 848x480 */ + { 1, 1,1064, 497,1064, 497 }, /* 0x17: 856x480 */ + { 1, 1,1056, 497,1056, 497 }, /* 0x18: 800x480 */ + { 1, 1,1328, 739,1328, 739 }, /* 0x19: 1024x576 */ + { 1, 1,1680, 892,1680, 892 }, /* 0x1a: 1152x864 */ + { 1, 1,1808, 808,1808, 808 }, /* 0x1b: 1360x768 */ + { 1, 1,1104, 563,1104, 563 }, /* 0x1c: 960x540 */ + { 1, 1,1120, 618,1120, 618 }, /* 0x1d: 960x600 */ + { 1, 1,1408, 816,1408, 816 }, /* 0x1f: 1280x800 (TMDS special) */ + { 1, 1,1760,1235,1760,1235 }, /* 0x20: 1600x1200 for LCDA */ + { 1, 1,2048,1320,2048,1320 }, /* 0x21: 1600x1200 for non-SiS LVDS */ + { 1, 1,1664, 861,1664, 861 } /* 0x22: 1280x854 */ +}; + +/**************************************************************/ +/* LVDS ----------------------------------------------------- */ +/**************************************************************/ + +/* FSTN/DSTN 320x240, 2 variants */ +static const struct SiS_LVDSData SiS_LVDS320x240Data_1[]= +{ + { 848, 433, 400, 525}, + { 848, 389, 400, 525}, + { 848, 433, 400, 525}, + { 848, 389, 400, 525}, + { 848, 518, 400, 525}, + {1056, 628, 400, 525}, + { 400, 525, 400, 525} /* xSTN */ +}; + +static const struct SiS_LVDSData SiS_LVDS320x240Data_2[]= +{ + { 800, 445, 800, 525}, + { 800, 395, 800, 525}, + { 800, 445, 800, 525}, + { 800, 395, 800, 525}, + { 800, 525, 800, 525}, + {1056, 628,1056, 628}, + { 480, 525, 480, 525} /* xSTN */ +}; + +static const struct SiS_LVDSData SiS_LVDS640x480Data_1[]= +{ + { 800, 445, 800, 525}, /* 800, 449, 800, 449 */ + { 800, 395, 800, 525}, + { 800, 445, 800, 525}, + { 800, 395, 800, 525}, + { 800, 525, 800, 525} +}; + +static const struct SiS_LVDSData SiS_LVDS800x600Data_1[]= +{ + { 848, 433,1060, 629}, + { 848, 389,1060, 629}, + { 848, 433,1060, 629}, + { 848, 389,1060, 629}, + { 848, 518,1060, 629}, + {1056, 628,1056, 628} +}; + +static const struct SiS_LVDSData SiS_LVDS1024x600Data_1[] = +{ + { 840, 604,1344, 800}, + { 840, 560,1344, 800}, + { 840, 604,1344, 800}, + { 840, 560,1344, 800}, + { 840, 689,1344, 800}, + {1050, 800,1344, 800}, + {1344, 800,1344, 800} +}; + +static const struct SiS_LVDSData SiS_LVDS1024x768Data_1[]= +{ + { 840, 438,1344, 806}, + { 840, 409,1344, 806}, + { 840, 438,1344, 806}, + { 840, 409,1344, 806}, + { 840, 518,1344, 806}, /* 640x480 */ + {1050, 638,1344, 806}, /* 800x600 */ + {1344, 806,1344, 806}, /* 1024x768 */ +}; + +static const struct SiS_LVDSData SiS_CHTVUNTSCData[]= +{ + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 840, 600, 840, 600}, + { 784, 600, 784, 600}, + {1064, 750,1064, 750}, + {1160, 945,1160, 945} +}; + +static const struct SiS_LVDSData SiS_CHTVONTSCData[]= +{ + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 840, 525, 840, 525}, + { 784, 525, 784, 525}, + {1040, 700,1040, 700}, + {1160, 840,1160, 840} +}; + +/* CRT1 CRTC data for slave modes */ + +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_1[] = +{ + {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00 }}, + {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00 }}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01 }}, + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00 }} +}; + +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_2[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, +#if 0 + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +#endif + {{0x5f,0x4f,0x83,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xe8,0x0c,0x00,0x00,0x05, + 0x00}}, +}; + +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_2_H[] = +{ + {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +}; + +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_3[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +}; + +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_3_H[] = +{ + {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f, + 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x54,0x9f,0xc4,0x1f, + 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, + 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, + 0x00}}, + {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e, + 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +}; + +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1640x480_1[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}} +}; + +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1640x480_1_H[] = +{ + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00, + 0x00}}, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x83,0x85,0x63,0xba,0x00,0x00,0x00, + 0x00}}, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00, + 0x00}}, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x83,0x85,0x63,0xba,0x00,0x00,0x00, + 0x00}}, + {{0x2d,0x28,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} +}; + +bool SiSInitPtr(struct SiS_Private *SiS_Pr); +unsigned short SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, bool FSTN, + unsigned short CustomT, int LCDwith, int LCDheight, + unsigned int VBFlags2); +unsigned short SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, unsigned int VBFlags2); +unsigned short SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, unsigned int VBFlags2); + +void SiS_DisplayOn(struct SiS_Private *SiS_Pr); +void SiS_DisplayOff(struct SiS_Private *SiS_Pr); +void SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); +void SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable); +void SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable); +unsigned short SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +bool SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr); + +bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, + unsigned short *ModeIdIndex); +unsigned short SiS_GetModePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +unsigned short SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); +unsigned short SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); +unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr,unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI); +#ifdef CONFIG_FB_SIS_300 +void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1, + unsigned short *idx2); +unsigned short SiS_GetFIFOThresholdB300(unsigned short idx1, unsigned short idx2); +unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index); +#endif +void SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); +bool SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth); +void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres, + int yres, struct fb_var_screeninfo *var, bool writeres); + +/* From init301.c: */ +extern void SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, int chkcrt2mode); +extern void SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_SetYPbPr(struct SiS_Private *SiS_Pr); +extern void SiS_SetTVMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_UnLockCRT2(struct SiS_Private *SiS_Pr); +extern void SiS_DisableBridge(struct SiS_Private *); +extern bool SiS_SetCRT2Group(struct SiS_Private *, unsigned short); +extern unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_WaitRetrace1(struct SiS_Private *SiS_Pr); +extern unsigned short SiS_GetResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempax); +extern unsigned short SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI); +extern bool SiS_IsVAMode(struct SiS_Private *); +extern bool SiS_IsDualEdge(struct SiS_Private *); + +#ifdef CONFIG_FB_SIS_300 +extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg); +extern void sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, + unsigned int val); +#endif +#ifdef CONFIG_FB_SIS_315 +extern void sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, + unsigned char val); +extern unsigned int sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg); +#endif + +#endif + diff --git a/drivers/video/fbdev/sis/init301.c b/drivers/video/fbdev/sis/init301.c new file mode 100644 index 0000000..a89e3ca --- /dev/null +++ b/drivers/video/fbdev/sis/init301.c @@ -0,0 +1,11071 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Mode initializing code (CRT2 section) + * for SiS 300/305/540/630/730, + * SiS 315/550/[M]650/651/[M]661[FGM]X/[M]74x[GX]/330/[M]76x[GX], + * XGI V3XT/V5/V8, Z7 + * (Universal module for Linux kernel framebuffer and X.org/XFree86 4.x) + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + * Formerly based on non-functional code-fragements for 300 series by SiS, Inc. + * Used by permission. + * + */ + +#if 1 +#define SET_EMI /* 302LV/ELV: Set EMI values */ +#endif + +#if 1 +#define SET_PWD /* 301/302LV: Set PWD */ +#endif + +#define COMPAL_HACK /* Needed for Compal 1400x1050 (EMI) */ +#define COMPAQ_HACK /* Needed for Inventec/Compaq 1280x1024 (EMI) */ +#define ASUS_HACK /* Needed for Asus A2H 1024x768 (EMI) */ + +#include "init301.h" + +#ifdef CONFIG_FB_SIS_300 +#include "oem300.h" +#endif + +#ifdef CONFIG_FB_SIS_315 +#include "oem310.h" +#endif + +#define SiS_I2CDELAY 1000 +#define SiS_I2CDELAYSHORT 150 + +static unsigned short SiS_GetBIOSLCDResInfo(struct SiS_Private *SiS_Pr); +static void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); + +/*********************************************/ +/* HELPER: Lock/Unlock CRT2 */ +/*********************************************/ + +void +SiS_UnLockCRT2(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType == XGI_20) + return; + else if(SiS_Pr->ChipType >= SIS_315H) + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01); + else + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01); +} + +static +void +SiS_LockCRT2(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType == XGI_20) + return; + else if(SiS_Pr->ChipType >= SIS_315H) + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE); + else + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE); +} + +/*********************************************/ +/* HELPER: Write SR11 */ +/*********************************************/ + +static void +SiS_SetRegSR11ANDOR(struct SiS_Private *SiS_Pr, unsigned short DataAND, unsigned short DataOR) +{ + if(SiS_Pr->ChipType >= SIS_661) { + DataAND &= 0x0f; + DataOR &= 0x0f; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,DataAND,DataOR); +} + +/*********************************************/ +/* HELPER: Get Pointer to LCD structure */ +/*********************************************/ + +#ifdef CONFIG_FB_SIS_315 +static unsigned char * +GetLCDStructPtr661(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned char *myptr = NULL; + unsigned short romindex = 0, reg = 0, idx = 0; + + /* Use the BIOS tables only for LVDS panels; TMDS is unreliable + * due to the variaty of panels the BIOS doesn't know about. + * Exception: If the BIOS has better knowledge (such as in case + * of machines with a 301C and a panel that does not support DDC) + * use the BIOS data as well. + */ + + if((SiS_Pr->SiS_ROMNew) && + ((SiS_Pr->SiS_VBType & VB_SISLVDS) || (!SiS_Pr->PanelSelfDetected))) { + + if(SiS_Pr->ChipType < SIS_661) reg = 0x3c; + else reg = 0x7d; + + idx = (SiS_GetReg(SiS_Pr->SiS_P3d4,reg) & 0x1f) * 26; + + if(idx < (8*26)) { + myptr = (unsigned char *)&SiS_LCDStruct661[idx]; + } + romindex = SISGETROMW(0x100); + if(romindex) { + romindex += idx; + myptr = &ROMAddr[romindex]; + } + } + return myptr; +} + +static unsigned short +GetLCDStructPtr661_2(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr = 0; + + /* Use the BIOS tables only for LVDS panels; TMDS is unreliable + * due to the variaty of panels the BIOS doesn't know about. + * Exception: If the BIOS has better knowledge (such as in case + * of machines with a 301C and a panel that does not support DDC) + * use the BIOS data as well. + */ + + if((SiS_Pr->SiS_ROMNew) && + ((SiS_Pr->SiS_VBType & VB_SISLVDS) || (!SiS_Pr->PanelSelfDetected))) { + romptr = SISGETROMW(0x102); + romptr += ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) * SiS_Pr->SiS661LCD2TableSize); + } + + return romptr; +} +#endif + +/*********************************************/ +/* Adjust Rate for CRT2 */ +/*********************************************/ + +static bool +SiS_AdjustCRT2Rate(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RRTI, unsigned short *i) +{ + unsigned short checkmask=0, modeid, infoflag; + + modeid = SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + + checkmask |= SupportRAMDAC2; + if(SiS_Pr->ChipType >= SIS_315H) { + checkmask |= SupportRAMDAC2_135; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + checkmask |= SupportRAMDAC2_162; + if(SiS_Pr->SiS_VBType & VB_SISRAMDAC202) { + checkmask |= SupportRAMDAC2_202; + } + } + } + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + + checkmask |= SupportLCD; + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(modeid == 0x2e) checkmask |= Support64048060Hz; + } + } + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + + checkmask |= SupportHiVision; + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750|SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) { + + checkmask |= SupportTV; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + checkmask |= SupportTV1024; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + checkmask |= SupportYPbPr750p; + } + } + } + + } + + } else { /* LVDS */ + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + checkmask |= SupportCHTV; + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + checkmask |= SupportLCD; + } + + } + + /* Look backwards in table for matching CRT2 mode */ + for(; SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID == modeid; (*i)--) { + infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; + if(infoflag & checkmask) return true; + if((*i) == 0) break; + } + + /* Look through the whole mode-section of the table from the beginning + * for a matching CRT2 mode if no mode was found yet. + */ + for((*i) = 0; ; (*i)++) { + if(SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID != modeid) break; + infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; + if(infoflag & checkmask) return true; + } + return false; +} + +/*********************************************/ +/* Get rate index */ +/*********************************************/ + +unsigned short +SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short RRTI,i,backup_i; + unsigned short modeflag,index,temp,backupindex; + static const unsigned short LCDRefreshIndex[] = { + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00 + }; + + /* Do NOT check for UseCustomMode here, will skrew up FIFO */ + if(ModeNo == 0xfe) return 0; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(modeflag & HalfDCLK) return 0; + } + } + + if(ModeNo < 0x14) return 0xFFFF; + + index = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x33) >> SiS_Pr->SiS_SelectCRT2Rate) & 0x0F; + backupindex = index; + + if(index > 0) index--; + + if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_VBType & VB_NoLCD) index = 0; + else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index = backupindex = 0; + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) { + temp = LCDRefreshIndex[SiS_GetBIOSLCDResInfo(SiS_Pr)]; + if(index > temp) index = temp; + } + } + } else { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) index = 0; + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) index = 0; + } + } + } + + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + ModeNo = SiS_Pr->SiS_RefIndex[RRTI].ModeID; + + if(SiS_Pr->ChipType >= SIS_315H) { + if(!(SiS_Pr->SiS_VBInfo & DriverMode)) { + if( (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x105) || + (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x107) ) { + if(backupindex <= 1) RRTI++; + } + } + } + + i = 0; + do { + if(SiS_Pr->SiS_RefIndex[RRTI + i].ModeID != ModeNo) break; + temp = SiS_Pr->SiS_RefIndex[RRTI + i].Ext_InfoFlag; + temp &= ModeTypeMask; + if(temp < SiS_Pr->SiS_ModeType) break; + i++; + index--; + } while(index != 0xFFFF); + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + temp = SiS_Pr->SiS_RefIndex[RRTI + i - 1].Ext_InfoFlag; + if(temp & InterlaceMode) i++; + } + } + + i--; + + if((SiS_Pr->SiS_SetFlag & ProgrammingCRT2) && (!(SiS_Pr->SiS_VBInfo & DisableCRT2Display))) { + backup_i = i; + if(!(SiS_AdjustCRT2Rate(SiS_Pr, ModeNo, ModeIdIndex, RRTI, &i))) { + i = backup_i; + } + } + + return (RRTI + i); +} + +/*********************************************/ +/* STORE CRT2 INFO in CR34 */ +/*********************************************/ + +static void +SiS_SaveCRT2Info(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + unsigned short temp1, temp2; + + /* Store CRT1 ModeNo in CR34 */ + SiS_SetReg(SiS_Pr->SiS_P3d4,0x34,ModeNo); + temp1 = (SiS_Pr->SiS_VBInfo & SetInSlaveMode) >> 8; + temp2 = ~(SetInSlaveMode >> 8); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x31,temp2,temp1); +} + +/*********************************************/ +/* HELPER: GET SOME DATA FROM BIOS ROM */ +/*********************************************/ + +#ifdef CONFIG_FB_SIS_300 +static bool +SiS_CR36BIOSWord23b(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp,temp1; + + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); + temp1 = SISGETROMW(0x23b); + if(temp1 & temp) return true; + } + } + return false; +} + +static bool +SiS_CR36BIOSWord23d(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp,temp1; + + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); + temp1 = SISGETROMW(0x23d); + if(temp1 & temp) return true; + } + } + return false; +} +#endif + +/*********************************************/ +/* HELPER: DELAY FUNCTIONS */ +/*********************************************/ + +void +SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime) +{ + while (delaytime-- > 0) + SiS_GetReg(SiS_Pr->SiS_P3c4, 0x05); +} + +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) +static void +SiS_GenericDelay(struct SiS_Private *SiS_Pr, unsigned short delay) +{ + SiS_DDC2Delay(SiS_Pr, delay * 36); +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static void +SiS_LongDelay(struct SiS_Private *SiS_Pr, unsigned short delay) +{ + while(delay--) { + SiS_GenericDelay(SiS_Pr, 6623); + } +} +#endif + +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) +static void +SiS_ShortDelay(struct SiS_Private *SiS_Pr, unsigned short delay) +{ + while(delay--) { + SiS_GenericDelay(SiS_Pr, 66); + } +} +#endif + +static void +SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime) +{ +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short PanelID, DelayIndex, Delay=0; +#endif + + if(SiS_Pr->ChipType < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 + + PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBType & VB_SIS301) PanelID &= 0xf7; + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x18) & 0x10)) PanelID = 0x12; + } + DelayIndex = PanelID >> 4; + if((DelayTime >= 2) && ((PanelID & 0x0f) == 1)) { + Delay = 3; + } else { + if(DelayTime >= 2) DelayTime -= 2; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x40) { + if(!(DelayTime & 0x01)) Delay = (unsigned short)ROMAddr[0x225]; + else Delay = (unsigned short)ROMAddr[0x226]; + } + } + } + SiS_ShortDelay(SiS_Pr, Delay); + +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 + + if((SiS_Pr->ChipType >= SIS_661) || + (SiS_Pr->ChipType <= SIS_315PRO) || + (SiS_Pr->ChipType == SIS_330) || + (SiS_Pr->SiS_ROMNew)) { + + if(!(DelayTime & 0x01)) { + SiS_DDC2Delay(SiS_Pr, 0x1000); + } else { + SiS_DDC2Delay(SiS_Pr, 0x4000); + } + + } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* || + (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || + (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) { /* 315 series, LVDS; Special */ + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + if(SiS_Pr->SiS_CustomT == CUT_CLEVO1400) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1b) & 0x10)) PanelID = 0x12; + } + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { + DelayIndex = PanelID & 0x0f; + } else { + DelayIndex = PanelID >> 4; + } + if((DelayTime >= 2) && ((PanelID & 0x0f) == 1)) { + Delay = 3; + } else { + if(DelayTime >= 2) DelayTime -= 2; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[1]; + } + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + if(ROMAddr[0x13c] & 0x40) { + if(!(DelayTime & 0x01)) { + Delay = (unsigned short)ROMAddr[0x17e]; + } else { + Delay = (unsigned short)ROMAddr[0x17f]; + } + } + } + } + SiS_ShortDelay(SiS_Pr, Delay); + } + + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { /* 315 series, all bridges */ + + DelayIndex = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; + } + Delay <<= 8; + SiS_DDC2Delay(SiS_Pr, Delay); + + } + +#endif /* CONFIG_FB_SIS_315 */ + + } +} + +#ifdef CONFIG_FB_SIS_315 +static void +SiS_PanelDelayLoop(struct SiS_Private *SiS_Pr, unsigned short DelayTime, unsigned short DelayLoop) +{ + int i; + for(i = 0; i < DelayLoop; i++) { + SiS_PanelDelay(SiS_Pr, DelayTime); + } +} +#endif + +/*********************************************/ +/* HELPER: WAIT-FOR-RETRACE FUNCTIONS */ +/*********************************************/ + +void +SiS_WaitRetrace1(struct SiS_Private *SiS_Pr) +{ + unsigned short watchdog; + + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return; + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80)) return; + + watchdog = 65535; + while((SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08) && --watchdog); + watchdog = 65535; + while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog); +} + +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) +static void +SiS_WaitRetrace2(struct SiS_Private *SiS_Pr, unsigned short reg) +{ + unsigned short watchdog; + + watchdog = 65535; + while((SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02) && --watchdog); + watchdog = 65535; + while((!(SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02)) && --watchdog); +} +#endif + +static void +SiS_WaitVBRetrace(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return; + } + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x80)) { + SiS_WaitRetrace1(SiS_Pr); + } else { + SiS_WaitRetrace2(SiS_Pr, 0x25); + } +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) { + SiS_WaitRetrace1(SiS_Pr); + } else { + SiS_WaitRetrace2(SiS_Pr, 0x30); + } +#endif + } +} + +static void +SiS_VBWait(struct SiS_Private *SiS_Pr) +{ + unsigned short tempal,temp,i,j; + + temp = 0; + for(i = 0; i < 3; i++) { + for(j = 0; j < 100; j++) { + tempal = SiS_GetRegByte(SiS_Pr->SiS_P3da); + if(temp & 0x01) { + if((tempal & 0x08)) continue; + else break; + } else { + if(!(tempal & 0x08)) continue; + else break; + } + } + temp ^= 0x01; + } +} + +static void +SiS_VBLongWait(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_VBWait(SiS_Pr); + } else { + SiS_WaitRetrace1(SiS_Pr); + } +} + +/*********************************************/ +/* HELPER: MISC */ +/*********************************************/ + +#ifdef CONFIG_FB_SIS_300 +static bool +SiS_Is301B(struct SiS_Private *SiS_Pr) +{ + if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return true; + return false; +} +#endif + +static bool +SiS_CRT2IsLCD(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType == SIS_730) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x20) return true; + } + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0x20) return true; + return false; +} + +bool +SiS_IsDualEdge(struct SiS_Private *SiS_Pr) +{ +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType >= SIS_315H) { + if((SiS_Pr->ChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableDualEdge) return true; + } + } +#endif + return false; +} + +bool +SiS_IsVAMode(struct SiS_Private *SiS_Pr) +{ +#ifdef CONFIG_FB_SIS_315 + unsigned short flag; + + if(SiS_Pr->ChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if((flag & EnableDualEdge) && (flag & SetToLCDA)) return true; + } +#endif + return false; +} + +#ifdef CONFIG_FB_SIS_315 +static bool +SiS_IsVAorLCD(struct SiS_Private *SiS_Pr) +{ + if(SiS_IsVAMode(SiS_Pr)) return true; + if(SiS_CRT2IsLCD(SiS_Pr)) return true; + return false; +} +#endif + +static bool +SiS_IsDualLink(struct SiS_Private *SiS_Pr) +{ +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType >= SIS_315H) { + if((SiS_CRT2IsLCD(SiS_Pr)) || + (SiS_IsVAMode(SiS_Pr))) { + if(SiS_Pr->SiS_LCDInfo & LCDDualLink) return true; + } + } +#endif + return false; +} + +#ifdef CONFIG_FB_SIS_315 +static bool +SiS_TVEnabled(struct SiS_Private *SiS_Pr) +{ + if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return true; + if(SiS_Pr->SiS_VBType & VB_SISYPBPR) { + if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return true; + } + return false; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static bool +SiS_LCDAEnabled(struct SiS_Private *SiS_Pr) +{ + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) return true; + return false; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static bool +SiS_WeHaveBacklightCtrl(struct SiS_Private *SiS_Pr) +{ + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0x10) return true; + } + return false; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static bool +SiS_IsNotM650orLater(struct SiS_Private *SiS_Pr) +{ + unsigned short flag; + + if(SiS_Pr->ChipType == SIS_650) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0; + /* Check for revision != A0 only */ + if((flag == 0xe0) || (flag == 0xc0) || + (flag == 0xb0) || (flag == 0x90)) return false; + } else if(SiS_Pr->ChipType >= SIS_661) return false; + return true; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static bool +SiS_IsYPbPr(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType >= SIS_315H) { + /* YPrPb = 0x08 */ + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableCHYPbPr) return true; + } + return false; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static bool +SiS_IsChScart(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType >= SIS_315H) { + /* Scart = 0x04 */ + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableCHScart) return true; + } + return false; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static bool +SiS_IsTVOrYPbPrOrScart(struct SiS_Private *SiS_Pr) +{ + unsigned short flag; + + if(SiS_Pr->ChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToTV) return true; + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableCHYPbPr) return true; /* = YPrPb = 0x08 */ + if(flag & EnableCHScart) return true; /* = Scart = 0x04 - TW */ + } else { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToTV) return true; + } + return false; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +static bool +SiS_IsLCDOrLCDA(struct SiS_Private *SiS_Pr) +{ + unsigned short flag; + + if(SiS_Pr->ChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToLCD) return true; + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & SetToLCDA) return true; + } else { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToLCD) return true; + } + return false; +} +#endif + +static bool +SiS_HaveBridge(struct SiS_Private *SiS_Pr) +{ + unsigned short flag; + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + return true; + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + if((flag == 1) || (flag == 2)) return true; + } + return false; +} + +static bool +SiS_BridgeIsEnabled(struct SiS_Private *SiS_Pr) +{ + unsigned short flag; + + if(SiS_HaveBridge(SiS_Pr)) { + flag = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + if(SiS_Pr->ChipType < SIS_315H) { + flag &= 0xa0; + if((flag == 0x80) || (flag == 0x20)) return true; + } else { + flag &= 0x50; + if((flag == 0x40) || (flag == 0x10)) return true; + } + } + return false; +} + +static bool +SiS_BridgeInSlavemode(struct SiS_Private *SiS_Pr) +{ + unsigned short flag1; + + flag1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31); + if(flag1 & (SetInSlaveMode >> 8)) return true; + return false; +} + +/*********************************************/ +/* GET VIDEO BRIDGE CONFIG INFO */ +/*********************************************/ + +/* Setup general purpose IO for Chrontel communication */ +#ifdef CONFIG_FB_SIS_300 +void +SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo) +{ + unsigned int acpibase; + unsigned short temp; + + if(!(SiS_Pr->SiS_ChSW)) return; + + acpibase = sisfb_read_lpc_pci_dword(SiS_Pr, 0x74); + acpibase &= 0xFFFF; + if(!acpibase) return; + temp = SiS_GetRegShort((acpibase + 0x3c)); /* ACPI register 0x3c: GP Event 1 I/O mode select */ + temp &= 0xFEFF; + SiS_SetRegShort((acpibase + 0x3c), temp); + temp = SiS_GetRegShort((acpibase + 0x3c)); + temp = SiS_GetRegShort((acpibase + 0x3a)); /* ACPI register 0x3a: GP Pin Level (low/high) */ + temp &= 0xFEFF; + if(!(myvbinfo & SetCRT2ToTV)) temp |= 0x0100; + SiS_SetRegShort((acpibase + 0x3a), temp); + temp = SiS_GetRegShort((acpibase + 0x3a)); +} +#endif + +void +SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, int checkcrt2mode) +{ + unsigned short tempax, tempbx, temp; + unsigned short modeflag, resinfo = 0; + + SiS_Pr->SiS_SetFlag = 0; + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + SiS_Pr->SiS_ModeType = modeflag & ModeTypeMask; + + if((ModeNo > 0x13) && (!SiS_Pr->UseCustomMode)) { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + tempbx = 0; + + if(SiS_HaveBridge(SiS_Pr)) { + + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + tempbx |= temp; + tempax = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) << 8; + tempax &= (DriverMode | LoadDACFlag | SetNotSimuMode | SetPALTV); + tempbx |= tempax; + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISLCDA) { + if(ModeNo == 0x03) { + /* Mode 0x03 is never in driver mode */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x31,0xbf); + } + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8))) { + /* Reset LCDA setting if not driver mode */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); + } + if(IS_SIS650) { + if(SiS_Pr->SiS_UseLCDA) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xF0) { + if((ModeNo <= 0x13) || (!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8)))) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x38,(EnableDualEdge | SetToLCDA)); + } + } + } + } + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if((temp & (EnableDualEdge | SetToLCDA)) == (EnableDualEdge | SetToLCDA)) { + tempbx |= SetCRT2ToLCDA; + } + } + + if(SiS_Pr->ChipType >= SIS_661) { /* New CR layout */ + tempbx &= ~(SetCRT2ToYPbPr525750 | SetCRT2ToHiVision); + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & 0x04) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; + if(temp == 0x60) tempbx |= SetCRT2ToHiVision; + else if(SiS_Pr->SiS_VBType & VB_SISYPBPR) { + tempbx |= SetCRT2ToYPbPr525750; + } + } + } + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(temp & SetToLCDA) { + tempbx |= SetCRT2ToLCDA; + } + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(temp & EnableCHYPbPr) { + tempbx |= SetCRT2ToCHYPbPr; + } + } + } + } + +#endif /* CONFIG_FB_SIS_315 */ + + if(!(SiS_Pr->SiS_VBType & VB_SISVGA2)) { + tempbx &= ~(SetCRT2ToRAMDAC); + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = SetCRT2ToSVIDEO | + SetCRT2ToAVIDEO | + SetCRT2ToSCART | + SetCRT2ToLCDA | + SetCRT2ToLCD | + SetCRT2ToRAMDAC | + SetCRT2ToHiVision | + SetCRT2ToYPbPr525750; + } else { + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + temp = SetCRT2ToAVIDEO | + SetCRT2ToSVIDEO | + SetCRT2ToSCART | + SetCRT2ToLCDA | + SetCRT2ToLCD | + SetCRT2ToCHYPbPr; + } else { + temp = SetCRT2ToLCDA | + SetCRT2ToLCD; + } + } else { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + temp = SetCRT2ToTV | SetCRT2ToLCD; + } else { + temp = SetCRT2ToLCD; + } + } + } + + if(!(tempbx & temp)) { + tempax = DisableCRT2Display; + tempbx = 0; + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + unsigned short clearmask = ( DriverMode | + DisableCRT2Display | + LoadDACFlag | + SetNotSimuMode | + SetInSlaveMode | + SetPALTV | + SwitchCRT2 | + SetSimuScanMode ); + + if(tempbx & SetCRT2ToLCDA) tempbx &= (clearmask | SetCRT2ToLCDA); + if(tempbx & SetCRT2ToRAMDAC) tempbx &= (clearmask | SetCRT2ToRAMDAC); + if(tempbx & SetCRT2ToLCD) tempbx &= (clearmask | SetCRT2ToLCD); + if(tempbx & SetCRT2ToSCART) tempbx &= (clearmask | SetCRT2ToSCART); + if(tempbx & SetCRT2ToHiVision) tempbx &= (clearmask | SetCRT2ToHiVision); + if(tempbx & SetCRT2ToYPbPr525750) tempbx &= (clearmask | SetCRT2ToYPbPr525750); + + } else { + + if(SiS_Pr->ChipType >= SIS_315H) { + if(tempbx & SetCRT2ToLCDA) { + tempbx &= (0xFF00|SwitchCRT2|SetSimuScanMode); + } + } + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(tempbx & SetCRT2ToTV) { + tempbx &= (0xFF00|SetCRT2ToTV|SwitchCRT2|SetSimuScanMode); + } + } + if(tempbx & SetCRT2ToLCD) { + tempbx &= (0xFF00|SetCRT2ToLCD|SwitchCRT2|SetSimuScanMode); + } + if(SiS_Pr->ChipType >= SIS_315H) { + if(tempbx & SetCRT2ToLCDA) { + tempbx |= SetCRT2ToLCD; + } + } + + } + + if(tempax & DisableCRT2Display) { + if(!(tempbx & (SwitchCRT2 | SetSimuScanMode))) { + tempbx = SetSimuScanMode | DisableCRT2Display; + } + } + + if(!(tempbx & DriverMode)) tempbx |= SetSimuScanMode; + + /* LVDS/CHRONTEL (LCD/TV) and 301BDH (LCD) can only be slave in 8bpp modes */ + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) || + ((SiS_Pr->SiS_VBType & VB_NoLCD) && (tempbx & SetCRT2ToLCD)) ) { + modeflag &= (~CRT2Mode); + } + } + + if(!(tempbx & SetSimuScanMode)) { + if(tempbx & SwitchCRT2) { + if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) { + if(resinfo != SIS_RI_1600x1200) { + tempbx |= SetSimuScanMode; + } + } + } else { + if(SiS_BridgeIsEnabled(SiS_Pr)) { + if(!(tempbx & DriverMode)) { + if(SiS_BridgeInSlavemode(SiS_Pr)) { + tempbx |= SetSimuScanMode; + } + } + } + } + } + + if(!(tempbx & DisableCRT2Display)) { + if(tempbx & DriverMode) { + if(tempbx & SetSimuScanMode) { + if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) { + if(resinfo != SIS_RI_1600x1200) { + tempbx |= SetInSlaveMode; + } + } + } + } else { + tempbx |= SetInSlaveMode; + } + } + + } + + SiS_Pr->SiS_VBInfo = tempbx; + +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->ChipType == SIS_630) { + SiS_SetChrontelGPIO(SiS_Pr, SiS_Pr->SiS_VBInfo); + } +#endif + +#if 0 + printk(KERN_DEBUG "sisfb: (init301: VBInfo= 0x%04x, SetFlag=0x%04x)\n", + SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag); +#endif +} + +/*********************************************/ +/* DETERMINE YPbPr MODE */ +/*********************************************/ + +void +SiS_SetYPbPr(struct SiS_Private *SiS_Pr) +{ + + unsigned char temp; + + /* Note: This variable is only used on 30xLV systems. + * CR38 has a different meaning on LVDS/CH7019 systems. + * On 661 and later, these bits moved to CR35. + * + * On 301, 301B, only HiVision 1080i is supported. + * On 30xLV, 301C, only YPbPr 1080i is supported. + */ + + SiS_Pr->SiS_YPbPr = 0; + if(SiS_Pr->ChipType >= SIS_661) return; + + if(SiS_Pr->SiS_VBType) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_YPbPr = YPbPrHiVision; + } + } + + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISYPBPR) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(temp & 0x08) { + switch((temp >> 4)) { + case 0x00: SiS_Pr->SiS_YPbPr = YPbPr525i; break; + case 0x01: SiS_Pr->SiS_YPbPr = YPbPr525p; break; + case 0x02: SiS_Pr->SiS_YPbPr = YPbPr750p; break; + case 0x03: SiS_Pr->SiS_YPbPr = YPbPrHiVision; break; + } + } + } + } + +} + +/*********************************************/ +/* DETERMINE TVMode flag */ +/*********************************************/ + +void +SiS_SetTVMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp, temp1, resinfo = 0, romindex = 0; + unsigned char OutputSelect = *SiS_Pr->pSiS_OutputSelect; + + SiS_Pr->SiS_TVMode = 0; + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return; + if(SiS_Pr->UseCustomMode) return; + + if(ModeNo > 0x13) { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + if(SiS_Pr->ChipType < SIS_661) { + + if(SiS_Pr->SiS_VBInfo & SetPALTV) SiS_Pr->SiS_TVMode |= TVSetPAL; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = 0; + if((SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730)) { + temp = 0x35; + romindex = 0xfe; + } else if(SiS_Pr->ChipType >= SIS_315H) { + temp = 0x38; + if(SiS_Pr->ChipType < XGI_20) { + romindex = 0xf3; + if(SiS_Pr->ChipType >= SIS_330) romindex = 0x11b; + } + } + if(temp) { + if(romindex && SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { + OutputSelect = ROMAddr[romindex]; + if(!(OutputSelect & EnablePALMN)) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,temp,0x3F); + } + } + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,temp); + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + if(temp1 & EnablePALM) { /* 0x40 */ + SiS_Pr->SiS_TVMode |= TVSetPALM; + SiS_Pr->SiS_TVMode &= ~TVSetPAL; + } else if(temp1 & EnablePALN) { /* 0x80 */ + SiS_Pr->SiS_TVMode |= TVSetPALN; + } + } else { + if(temp1 & EnableNTSCJ) { /* 0x40 */ + SiS_Pr->SiS_TVMode |= TVSetNTSCJ; + } + } + } + /* Translate HiVision/YPbPr to our new flags */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->SiS_YPbPr == YPbPr750p) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; + else if(SiS_Pr->SiS_YPbPr == YPbPr525p) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; + else if(SiS_Pr->SiS_YPbPr == YPbPrHiVision) SiS_Pr->SiS_TVMode |= TVSetHiVision; + else SiS_Pr->SiS_TVMode |= TVSetYPbPr525i; + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p | TVSetYPbPr525i)) { + SiS_Pr->SiS_VBInfo &= ~SetCRT2ToHiVision; + SiS_Pr->SiS_VBInfo |= SetCRT2ToYPbPr525750; + } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) { + SiS_Pr->SiS_TVMode |= TVSetPAL; + } + } + } else if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_CHOverScan) { + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + if((temp & TVOverScan) || (SiS_Pr->SiS_CHOverScan == 1)) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x79); + if((temp & 0x80) || (SiS_Pr->SiS_CHOverScan == 1)) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } + if(SiS_Pr->SiS_CHSOverScan) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + if(temp & EnablePALM) SiS_Pr->SiS_TVMode |= TVSetPALM; + else if(temp & EnablePALN) SiS_Pr->SiS_TVMode |= TVSetPALN; + } else { + if(temp & EnableNTSCJ) { + SiS_Pr->SiS_TVMode |= TVSetNTSCJ; + } + } + } + } + + } else { /* 661 and later */ + + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + if(temp1 & 0x01) { + SiS_Pr->SiS_TVMode |= TVSetPAL; + if(temp1 & 0x08) { + SiS_Pr->SiS_TVMode |= TVSetPALN; + } else if(temp1 & 0x04) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_Pr->SiS_TVMode &= ~TVSetPAL; + } + SiS_Pr->SiS_TVMode |= TVSetPALM; + } + } else { + if(temp1 & 0x02) { + SiS_Pr->SiS_TVMode |= TVSetNTSCJ; + } + } + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_Pr->SiS_CHOverScan) { + if((temp1 & 0x10) || (SiS_Pr->SiS_CHOverScan == 1)) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } + } + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + temp1 &= 0xe0; + if(temp1 == 0x00) SiS_Pr->SiS_TVMode |= TVSetYPbPr525i; + else if(temp1 == 0x20) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; + else if(temp1 == 0x40) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_TVMode |= (TVSetHiVision | TVSetPAL); + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750 | SetCRT2ToHiVision)) { + if(resinfo == SIS_RI_800x480 || resinfo == SIS_RI_1024x576 || resinfo == SIS_RI_1280x720) { + SiS_Pr->SiS_TVMode |= TVAspect169; + } else { + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x39); + if(temp1 & 0x02) { + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetHiVision)) { + SiS_Pr->SiS_TVMode |= TVAspect169; + } else { + SiS_Pr->SiS_TVMode |= TVAspect43LB; + } + } else { + SiS_Pr->SiS_TVMode |= TVAspect43; + } + } + } + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) SiS_Pr->SiS_TVMode |= TVSetPAL; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_TVMode |= TVSetPAL; + SiS_Pr->SiS_TVMode &= ~(TVSetPALM | TVSetPALN | TVSetNTSCJ); + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525i | TVSetYPbPr525p | TVSetYPbPr750p)) { + SiS_Pr->SiS_TVMode &= ~(TVSetPAL | TVSetNTSCJ | TVSetPALM | TVSetPALN); + } + } + + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + SiS_Pr->SiS_TVMode |= TVSetTVSimuMode; + } + } + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + if(resinfo == SIS_RI_1024x768) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { + SiS_Pr->SiS_TVMode |= TVSet525p1024; + } else if(!(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr750p))) { + SiS_Pr->SiS_TVMode |= TVSetNTSC1024; + } + } + } + + SiS_Pr->SiS_TVMode |= TVRPLLDIV2XO; + if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) && + (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; + } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) { + SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; + } else if(!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; + } + } + + } + + SiS_Pr->SiS_VBInfo &= ~SetPALTV; +} + +/*********************************************/ +/* GET LCD INFO */ +/*********************************************/ + +static unsigned short +SiS_GetBIOSLCDResInfo(struct SiS_Private *SiS_Pr) +{ + unsigned short temp = SiS_Pr->SiS_LCDResInfo; + /* Translate my LCDResInfo to BIOS value */ + switch(temp) { + case Panel_1280x768_2: temp = Panel_1280x768; break; + case Panel_1280x800_2: temp = Panel_1280x800; break; + case Panel_1280x854: temp = Panel661_1280x854; break; + } + return temp; +} + +static void +SiS_GetLCDInfoBIOS(struct SiS_Private *SiS_Pr) +{ +#ifdef CONFIG_FB_SIS_315 + unsigned char *ROMAddr; + unsigned short temp; + + if((ROMAddr = GetLCDStructPtr661(SiS_Pr))) { + if((temp = SISGETROMW(6)) != SiS_Pr->PanelHT) { + SiS_Pr->SiS_NeedRomModeData = true; + SiS_Pr->PanelHT = temp; + } + if((temp = SISGETROMW(8)) != SiS_Pr->PanelVT) { + SiS_Pr->SiS_NeedRomModeData = true; + SiS_Pr->PanelVT = temp; + } + SiS_Pr->PanelHRS = SISGETROMW(10); + SiS_Pr->PanelHRE = SISGETROMW(12); + SiS_Pr->PanelVRS = SISGETROMW(14); + SiS_Pr->PanelVRE = SISGETROMW(16); + SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315; + SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].CLOCK = + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].CLOCK = (unsigned short)((unsigned char)ROMAddr[18]); + SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2B = + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_A = ROMAddr[19]; + SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2C = + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_B = ROMAddr[20]; + + } +#endif +} + +static void +SiS_CheckScaling(struct SiS_Private *SiS_Pr, unsigned short resinfo, + const unsigned char *nonscalingmodes) +{ + int i = 0; + while(nonscalingmodes[i] != 0xff) { + if(nonscalingmodes[i++] == resinfo) { + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) || + (SiS_Pr->UsePanelScaler == -1)) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + } +} + +void +SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short temp,modeflag,resinfo=0,modexres=0,modeyres=0; + bool panelcanscale = false; +#ifdef CONFIG_FB_SIS_300 + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + static const unsigned char SiS300SeriesLCDRes[] = + { 0, 1, 2, 3, 7, 4, 5, 8, + 0, 0, 10, 0, 0, 0, 0, 15 }; +#endif +#ifdef CONFIG_FB_SIS_315 + unsigned char *myptr = NULL; +#endif + + SiS_Pr->SiS_LCDResInfo = 0; + SiS_Pr->SiS_LCDTypeInfo = 0; + SiS_Pr->SiS_LCDInfo = 0; + SiS_Pr->PanelHRS = 999; /* HSync start */ + SiS_Pr->PanelHRE = 999; /* HSync end */ + SiS_Pr->PanelVRS = 999; /* VSync start */ + SiS_Pr->PanelVRE = 999; /* VSync end */ + SiS_Pr->SiS_NeedRomModeData = false; + + /* Alternative 1600x1200@60 timing for 1600x1200 LCDA */ + SiS_Pr->Alternate1600x1200 = false; + + if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) return; + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + if((ModeNo > 0x13) && (!SiS_Pr->UseCustomMode)) { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + modexres = SiS_Pr->SiS_ModeResInfo[resinfo].HTotal; + modeyres = SiS_Pr->SiS_ModeResInfo[resinfo].VTotal; + } + + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + + /* For broken BIOSes: Assume 1024x768 */ + if(temp == 0) temp = 0x02; + + if((SiS_Pr->ChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + SiS_Pr->SiS_LCDTypeInfo = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x7c) >> 2; + } else if((SiS_Pr->ChipType < SIS_315H) || (SiS_Pr->ChipType >= SIS_661)) { + SiS_Pr->SiS_LCDTypeInfo = temp >> 4; + } else { + SiS_Pr->SiS_LCDTypeInfo = (temp & 0x0F) - 1; + } + temp &= 0x0f; +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->ChipType < SIS_315H) { + /* Very old BIOSes only know 7 sizes (NetVista 2179, 1.01g) */ + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(temp < 0x0f) temp &= 0x07; + } + /* Translate 300 series LCDRes to 315 series for unified usage */ + temp = SiS300SeriesLCDRes[temp]; + } +#endif + + /* Translate to our internal types */ +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType == SIS_550) { + if (temp == Panel310_1152x768) temp = Panel_320x240_2; /* Verified working */ + else if(temp == Panel310_320x240_2) temp = Panel_320x240_2; + else if(temp == Panel310_320x240_3) temp = Panel_320x240_3; + } else if(SiS_Pr->ChipType >= SIS_661) { + if(temp == Panel661_1280x854) temp = Panel_1280x854; + } +#endif + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { /* SiS LVDS */ + if(temp == Panel310_1280x768) { + temp = Panel_1280x768_2; + } + if(SiS_Pr->SiS_ROMNew) { + if(temp == Panel661_1280x800) { + temp = Panel_1280x800_2; + } + } + } + + SiS_Pr->SiS_LCDResInfo = temp; + +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + SiS_Pr->SiS_LCDResInfo = Panel_Barco1366; + } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { + SiS_Pr->SiS_LCDResInfo = Panel_848x480; + } else if(SiS_Pr->SiS_CustomT == CUT_PANEL856) { + SiS_Pr->SiS_LCDResInfo = Panel_856x480; + } + } +#endif + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301) + SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMin301; + } else { + if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMinLVDS) + SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS; + } + + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); + SiS_Pr->SiS_LCDInfo = temp & ~0x000e; + /* Need temp below! */ + + /* These must/can't scale no matter what */ + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_320x240_1: + case Panel_320x240_2: + case Panel_320x240_3: + case Panel_1280x960: + SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; + break; + case Panel_640x480: + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + + panelcanscale = (bool)(SiS_Pr->SiS_LCDInfo & DontExpandLCD); + + if(!SiS_Pr->UsePanelScaler) SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; + else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + + /* Dual link, Pass 1:1 BIOS default, etc. */ +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType >= SIS_661) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11; + } + if(SiS_Pr->SiS_VBType & VB_SISDUALLINK) { + if(SiS_Pr->SiS_ROMNew) { + if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } else if((myptr = GetLCDStructPtr661(SiS_Pr))) { + if(myptr[2] & 0x01) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + } + } else if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x01) SiS_Pr->SiS_LCDInfo |= LCDPass11; + } + if((SiS_Pr->SiS_ROMNew) && (!(SiS_Pr->PanelSelfDetected))) { + SiS_Pr->SiS_LCDInfo &= ~(LCDRGB18Bit); + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + if(temp & 0x01) SiS_Pr->SiS_LCDInfo |= LCDRGB18Bit; + if(SiS_Pr->SiS_VBType & VB_SISDUALLINK) { + if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + } else if(!(SiS_Pr->SiS_ROMNew)) { + if(SiS_Pr->SiS_VBType & VB_SISDUALLINK) { + if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) && + (SiS_Pr->SiS_LCDResInfo == Panel_1024x768)) { + SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || + (SiS_Pr->SiS_LCDResInfo == Panel_1680x1050)) { + SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + } + } + } +#endif + + /* Pass 1:1 */ + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) { + /* Always center screen on LVDS (if scaling is disabled) */ + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + /* Always center screen on SiS LVDS (if scaling is disabled) */ + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } else { + /* By default, pass 1:1 on SiS TMDS (if scaling is supported) */ + if(panelcanscale) SiS_Pr->SiS_LCDInfo |= LCDPass11; + if(SiS_Pr->CenterScreen == 1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } + } + + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_320x240_1: + case Panel_320x240_2: + case Panel_320x240_3: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelVRS = 24; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx300 = VCLK28; + SiS_Pr->PanelVCLKIdx315 = VCLK28; + break; + case Panel_640x480: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx300 = VCLK28; + SiS_Pr->PanelVCLKIdx315 = VCLK28; + break; + case Panel_800x600: SiS_Pr->PanelXRes = 800; SiS_Pr->PanelYRes = 600; + SiS_Pr->PanelHT = 1056; SiS_Pr->PanelVT = 628; + SiS_Pr->PanelHRS = 40; SiS_Pr->PanelHRE = 128; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 4; + SiS_Pr->PanelVCLKIdx300 = VCLK40; + SiS_Pr->PanelVCLKIdx315 = VCLK40; + break; + case Panel_1024x600: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 600; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 800; + SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; + SiS_Pr->PanelVRS = 2 /* 88 */ ; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK65_315; + break; + case Panel_1024x768: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + if(SiS_Pr->ChipType < SIS_315H) { + SiS_Pr->PanelHRS = 23; + SiS_Pr->PanelVRE = 5; + } + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK65_315; + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1152x768: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + if(SiS_Pr->ChipType < SIS_315H) { + SiS_Pr->PanelHRS = 23; + SiS_Pr->PanelVRE = 5; + } + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK65_315; + break; + case Panel_1152x864: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 864; + break; + case Panel_1280x720: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 720; + SiS_Pr->PanelHT = 1650; SiS_Pr->PanelVT = 750; + SiS_Pr->PanelHRS = 110; SiS_Pr->PanelHRE = 40; + SiS_Pr->PanelVRS = 5; SiS_Pr->PanelVRE = 5; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x720; + /* Data above for TMDS (projector); get from BIOS for LVDS */ + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1280x768: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + SiS_Pr->PanelHT = 1408; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelVCLKIdx300 = VCLK81_300; /* ? */ + SiS_Pr->PanelVCLKIdx315 = VCLK81_315; /* ? */ + } else { + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 802; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRS = 112; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx300 = VCLK81_300; + SiS_Pr->PanelVCLKIdx315 = VCLK81_315; + } + break; + case Panel_1280x768_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1660; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x768_2; + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1280x800: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 800; + SiS_Pr->PanelHT = 1408; SiS_Pr->PanelVT = 816; + SiS_Pr->PanelHRS = 21; SiS_Pr->PanelHRE = 24; + SiS_Pr->PanelVRS = 4; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x800_315; + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1280x800_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 800; + SiS_Pr->PanelHT = 1552; SiS_Pr->PanelVT = 812; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 4; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x800_315_2; + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1280x854: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 854; + SiS_Pr->PanelHT = 1664; SiS_Pr->PanelVT = 861; + SiS_Pr->PanelHRS = 16; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x854; + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1280x960: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 960; + SiS_Pr->PanelHT = 1800; SiS_Pr->PanelVT = 1000; + SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300; + SiS_Pr->PanelVCLKIdx315 = VCLK108_3_315; + if(resinfo == SIS_RI_1280x1024) { + SiS_Pr->PanelVCLKIdx300 = VCLK100_300; + SiS_Pr->PanelVCLKIdx315 = VCLK100_315; + } + break; + case Panel_1280x1024: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 1024; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300; + SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1400x1050: SiS_Pr->PanelXRes = 1400; SiS_Pr->PanelYRes = 1050; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1600x1200: SiS_Pr->PanelXRes = 1600; SiS_Pr->PanelYRes = 1200; + SiS_Pr->PanelHT = 2160; SiS_Pr->PanelVT = 1250; + SiS_Pr->PanelHRS = 64; SiS_Pr->PanelHRE = 192; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK162_315; + if(SiS_Pr->SiS_VBType & VB_SISTMDSLCDA) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_Pr->PanelHT = 1760; SiS_Pr->PanelVT = 1235; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 32; + SiS_Pr->PanelVRS = 2; SiS_Pr->PanelVRE = 4; + SiS_Pr->PanelVCLKIdx315 = VCLK130_315; + SiS_Pr->Alternate1600x1200 = true; + } + } else if(SiS_Pr->SiS_IF_DEF_LVDS) { + SiS_Pr->PanelHT = 2048; SiS_Pr->PanelVT = 1320; + SiS_Pr->PanelHRS = SiS_Pr->PanelHRE = 999; + SiS_Pr->PanelVRS = SiS_Pr->PanelVRE = 999; + } + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1680x1050: SiS_Pr->PanelXRes = 1680; SiS_Pr->PanelYRes = 1050; + SiS_Pr->PanelHT = 1900; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 26; SiS_Pr->PanelHRE = 76; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx315 = VCLK121_315; + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_Barco1366: SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + break; + case Panel_848x480: SiS_Pr->PanelXRes = 848; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelHT = 1088; SiS_Pr->PanelVT = 525; + break; + case Panel_856x480: SiS_Pr->PanelXRes = 856; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelHT = 1088; SiS_Pr->PanelVT = 525; + break; + case Panel_Custom: SiS_Pr->PanelXRes = SiS_Pr->CP_MaxX; + SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY; + SiS_Pr->PanelHT = SiS_Pr->CHTotal; + SiS_Pr->PanelVT = SiS_Pr->CVTotal; + if(SiS_Pr->CP_PreferredIndex != -1) { + SiS_Pr->PanelXRes = SiS_Pr->CP_HDisplay[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelYRes = SiS_Pr->CP_VDisplay[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHT = SiS_Pr->CP_HTotal[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelVT = SiS_Pr->CP_VTotal[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHRS = SiS_Pr->CP_HSyncStart[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHRE = SiS_Pr->CP_HSyncEnd[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelVRS = SiS_Pr->CP_VSyncStart[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelVRE = SiS_Pr->CP_VSyncEnd[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHRS -= SiS_Pr->PanelXRes; + SiS_Pr->PanelHRE -= SiS_Pr->PanelHRS; + SiS_Pr->PanelVRS -= SiS_Pr->PanelYRes; + SiS_Pr->PanelVRE -= SiS_Pr->PanelVRS; + if(SiS_Pr->CP_PrefClock) { + int idx; + SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315; + SiS_Pr->PanelVCLKIdx300 = VCLK_CUSTOM_300; + if(SiS_Pr->ChipType < SIS_315H) idx = VCLK_CUSTOM_300; + else idx = VCLK_CUSTOM_315; + SiS_Pr->SiS_VCLKData[idx].CLOCK = + SiS_Pr->SiS_VBVCLKData[idx].CLOCK = SiS_Pr->CP_PrefClock; + SiS_Pr->SiS_VCLKData[idx].SR2B = + SiS_Pr->SiS_VBVCLKData[idx].Part4_A = SiS_Pr->CP_PrefSR2B; + SiS_Pr->SiS_VCLKData[idx].SR2C = + SiS_Pr->SiS_VBVCLKData[idx].Part4_B = SiS_Pr->CP_PrefSR2C; + } + } + break; + default: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + break; + } + + /* Special cases */ + if( (SiS_Pr->SiS_IF_DEF_FSTN) || + (SiS_Pr->SiS_IF_DEF_DSTN) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + (SiS_Pr->SiS_CustomT == CUT_PANEL856) ) { + SiS_Pr->PanelHRS = 999; + SiS_Pr->PanelHRE = 999; + } + + if( (SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + (SiS_Pr->SiS_CustomT == CUT_PANEL856) ) { + SiS_Pr->PanelVRS = 999; + SiS_Pr->PanelVRE = 999; + } + + /* DontExpand overrule */ + if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (modeflag & NoSupportLCDScale)) { + /* No scaling for this mode on any panel (LCD=CRT2)*/ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + + switch(SiS_Pr->SiS_LCDResInfo) { + + case Panel_Custom: + case Panel_1152x864: + case Panel_1280x768: /* TMDS only */ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + break; + + case Panel_800x600: { + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, 0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1024x768: { + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + 0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1280x720: { + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + 0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + if(SiS_Pr->PanelHT == 1650) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + case Panel_1280x768_2: { /* LVDS only */ + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + switch(resinfo) { + case SIS_RI_1280x720: if(SiS_Pr->UsePanelScaler == -1) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + break; + } + case Panel_1280x800: { /* SiS TMDS special (Averatec 6200 series) */ + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1280x720,SIS_RI_1280x768,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1280x800_2: { /* SiS LVDS */ + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + switch(resinfo) { + case SIS_RI_1280x720: + case SIS_RI_1280x768: if(SiS_Pr->UsePanelScaler == -1) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + break; + } + case Panel_1280x854: { /* SiS LVDS */ + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + switch(resinfo) { + case SIS_RI_1280x720: + case SIS_RI_1280x768: + case SIS_RI_1280x800: if(SiS_Pr->UsePanelScaler == -1) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + break; + } + case Panel_1280x960: { + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, + SIS_RI_1280x854,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1280x1024: { + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, + SIS_RI_1280x854,SIS_RI_1280x960,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1400x1050: { + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x768,SIS_RI_1280x800,SIS_RI_1280x854, + SIS_RI_1280x960,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + switch(resinfo) { + case SIS_RI_1280x720: if(SiS_Pr->UsePanelScaler == -1) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + case SIS_RI_1280x1024: SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + break; + } + break; + } + case Panel_1600x1200: { + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, + SIS_RI_1280x854,SIS_RI_1280x960,SIS_RI_1360x768,SIS_RI_1360x1024,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1680x1050: { + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x854,SIS_RI_1280x960,SIS_RI_1360x768, + SIS_RI_1360x1024,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + } + } + +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_CustomT == CUT_PANEL848 || SiS_Pr->SiS_CustomT == CUT_PANEL856) { + SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20; /* neg h/v sync, RGB24(D0 = 0) */ + } + } + + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + if(!(ROMAddr[0x235] & 0x02)) { + SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); + } + } + } + } else if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10))) { + SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); + } + } + } +#endif + + /* Special cases */ + + if(modexres == SiS_Pr->PanelXRes && modeyres == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } + + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11); + } + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: + SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11); + break; + case Panel_1280x800: + /* Don't pass 1:1 by default (TMDS special) */ + if(SiS_Pr->CenterScreen == -1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + break; + case Panel_1280x960: + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + break; + case Panel_Custom: + if((!SiS_Pr->CP_PrefClock) || + (modexres > SiS_Pr->PanelXRes) || (modeyres > SiS_Pr->PanelYRes)) { + SiS_Pr->SiS_LCDInfo |= LCDPass11; + } + break; + } + + if((SiS_Pr->UseCustomMode) || (SiS_Pr->SiS_CustomT == CUT_UNKNOWNLCD)) { + SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11); + } + + /* (In)validate LCDPass11 flag */ + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } + + /* LVDS DDA */ + if(!((SiS_Pr->ChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & SetDOSMode))) { + + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) { + if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) { + if(ModeNo == 0x12) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } + } else if(ModeNo > 0x13) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x600) { + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } + } + } + } + } + } + + if(modeflag & HalfDCLK) { + if(SiS_Pr->SiS_IF_DEF_TRUMPION == 1) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(ModeNo > 0x13) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_800x600) { + if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } + } + } + + } + + /* VESA timing */ + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_VBInfo & SetNotSimuMode) { + SiS_Pr->SiS_SetFlag |= LCDVESATiming; + } + } else { + SiS_Pr->SiS_SetFlag |= LCDVESATiming; + } + +#if 0 + printk(KERN_DEBUG "sisfb: (LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n", + SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo); +#endif +} + +/*********************************************/ +/* GET VCLK */ +/*********************************************/ + +unsigned short +SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short CRT2Index, VCLKIndex = 0, VCLKIndexGEN = 0, VCLKIndexGENCRT = 0; + unsigned short modeflag, resinfo, tempbx; + const unsigned char *CHTVVCLKPtr = NULL; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + VCLKIndexGEN = (SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)) >> 2) & 0x03; + VCLKIndexGENCRT = VCLKIndexGEN; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + VCLKIndexGEN = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + VCLKIndexGENCRT = SiS_GetRefCRTVCLK(SiS_Pr, RefreshRateTableIndex, + (SiS_Pr->SiS_SetFlag & ProgrammingCRT2) ? SiS_Pr->SiS_UseWideCRT2 : SiS_Pr->SiS_UseWide); + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { /* 30x/B/LV */ + + if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { + + CRT2Index >>= 6; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /* LCD */ + + if(SiS_Pr->ChipType < SIS_315H) { + VCLKIndex = SiS_Pr->PanelVCLKIdx300; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + VCLKIndex = VCLKIndexGEN; + } + } else { + VCLKIndex = SiS_Pr->PanelVCLKIdx315; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + switch(resinfo) { + /* Correct those whose IndexGEN doesn't match VBVCLK array */ + case SIS_RI_720x480: VCLKIndex = VCLK_720x480; break; + case SIS_RI_720x576: VCLKIndex = VCLK_720x576; break; + case SIS_RI_768x576: VCLKIndex = VCLK_768x576; break; + case SIS_RI_848x480: VCLKIndex = VCLK_848x480; break; + case SIS_RI_856x480: VCLKIndex = VCLK_856x480; break; + case SIS_RI_800x480: VCLKIndex = VCLK_800x480; break; + case SIS_RI_1024x576: VCLKIndex = VCLK_1024x576; break; + case SIS_RI_1152x864: VCLKIndex = VCLK_1152x864; break; + case SIS_RI_1280x720: VCLKIndex = VCLK_1280x720; break; + case SIS_RI_1360x768: VCLKIndex = VCLK_1360x768; break; + default: VCLKIndex = VCLKIndexGEN; + } + + if(ModeNo <= 0x13) { + if(SiS_Pr->ChipType <= SIS_315PRO) { + if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42; + } else { + if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x00; + } + } + if(SiS_Pr->ChipType <= SIS_315PRO) { + if(VCLKIndex == 0) VCLKIndex = 0x41; + if(VCLKIndex == 1) VCLKIndex = 0x43; + if(VCLKIndex == 4) VCLKIndex = 0x44; + } + } + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* TV */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = HiTVVCLKDIV2; + else VCLKIndex = HiTVVCLK; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) VCLKIndex = HiTVSimuVCLK; + } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) VCLKIndex = YPbPr750pVCLK; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) VCLKIndex = TVVCLKDIV2; + else if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = TVVCLKDIV2; + else VCLKIndex = TVVCLK; + + if(SiS_Pr->ChipType < SIS_315H) VCLKIndex += TVCLKBASE_300; + else VCLKIndex += TVCLKBASE_315; + + } else { /* VGA2 */ + + VCLKIndex = VCLKIndexGENCRT; + if(SiS_Pr->ChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (SiS_Pr->ChipType == SIS_630) && + (SiS_Pr->ChipRevision >= 0x30)) { + if(VCLKIndex == 0x14) VCLKIndex = 0x34; + } + /* Better VGA2 clock for 1280x1024@75 */ + if(VCLKIndex == 0x17) VCLKIndex = 0x45; + } + } + } + + } else { /* If not programming CRT2 */ + + VCLKIndex = VCLKIndexGENCRT; + if(SiS_Pr->ChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (SiS_Pr->ChipType != SIS_630) && + (SiS_Pr->ChipType != SIS_300) ) { + if(VCLKIndex == 0x1b) VCLKIndex = 0x48; + } + } + } + } + + } else { /* LVDS */ + + VCLKIndex = CRT2Index; + + if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { + + if( (SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) { + + VCLKIndex &= 0x1f; + tempbx = 0; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tempbx += 2; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) tempbx = 8; + } + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + tempbx = 4; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { + tempbx = 6; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + } + } + switch(tempbx) { + case 0: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUNTSC; break; + case 1: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKONTSC; break; + case 2: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPAL; break; + case 3: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL; break; + case 4: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPALM; break; + case 5: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALM; break; + case 6: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPALN; break; + case 7: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALN; break; + case 8: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKSOPAL; break; + default: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL; break; + } + VCLKIndex = CHTVVCLKPtr[VCLKIndex]; + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + + if(SiS_Pr->ChipType < SIS_315H) { + VCLKIndex = SiS_Pr->PanelVCLKIdx300; + } else { + VCLKIndex = SiS_Pr->PanelVCLKIdx315; + } + +#ifdef CONFIG_FB_SIS_300 + /* Special Timing: Barco iQ Pro R series */ + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) VCLKIndex = 0x44; + + /* Special Timing: 848x480 and 856x480 parallel lvds panels */ + if(SiS_Pr->SiS_CustomT == CUT_PANEL848 || SiS_Pr->SiS_CustomT == CUT_PANEL856) { + if(SiS_Pr->ChipType < SIS_315H) { + VCLKIndex = VCLK34_300; + /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */ + } else { + VCLKIndex = VCLK34_315; + /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */ + } + } +#endif + + } else { + + VCLKIndex = VCLKIndexGENCRT; + if(SiS_Pr->ChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (SiS_Pr->ChipType == SIS_630) && + (SiS_Pr->ChipRevision >= 0x30) ) { + if(VCLKIndex == 0x14) VCLKIndex = 0x2e; + } + } + } + } + + } else { /* if not programming CRT2 */ + + VCLKIndex = VCLKIndexGENCRT; + if(SiS_Pr->ChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (SiS_Pr->ChipType != SIS_630) && + (SiS_Pr->ChipType != SIS_300) ) { + if(VCLKIndex == 0x1b) VCLKIndex = 0x48; + } +#if 0 + if(SiS_Pr->ChipType == SIS_730) { + if(VCLKIndex == 0x0b) VCLKIndex = 0x40; /* 1024x768-70 */ + if(VCLKIndex == 0x0d) VCLKIndex = 0x41; /* 1024x768-75 */ + } +#endif + } + } + + } + + } + + return VCLKIndex; +} + +/*********************************************/ +/* SET CRT2 MODE TYPE REGISTERS */ +/*********************************************/ + +static void +SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short i, j, modeflag, tempah=0; + short tempcl; +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) + unsigned short tempbl; +#endif +#ifdef CONFIG_FB_SIS_315 + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short tempah2, tempbl2; +#endif + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xAF,0x40); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2E,0xF7); + + } else { + + for(i=0,j=4; i<3; i++,j++) SiS_SetReg(SiS_Pr->SiS_Part1Port,j,0); + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0x7F); + } + + tempcl = SiS_Pr->SiS_ModeType; + + if(SiS_Pr->ChipType < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 /* ---- 300 series ---- */ + + /* For 301BDH: (with LCD via LVDS) */ + if(SiS_Pr->SiS_VBType & VB_NoLCD) { + tempbl = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32); + tempbl &= 0xef; + tempbl |= 0x02; + if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) || (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempbl |= 0x10; + tempbl &= 0xfd; + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,tempbl); + } + + if(ModeNo > 0x13) { + tempcl -= ModeVGA; + if(tempcl >= 0) { + tempah = ((0x10 >> tempcl) | 0x80); + } + } else tempah = 0x80; + + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0xA0; + +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 /* ------- 315/330 series ------ */ + + if(ModeNo > 0x13) { + tempcl -= ModeVGA; + if(tempcl >= 0) { + tempah = (0x08 >> tempcl); + if (tempah == 0) tempah = 1; + tempah |= 0x40; + } + } else tempah = 0x40; + + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0x50; + +#endif /* CONFIG_FB_SIS_315 */ + + } + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; + + if(SiS_Pr->ChipType < SIS_315H) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah); + } else { +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah); + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(IS_SIS740) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah); + } + } +#endif + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + tempah = 0x01; + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + tempah |= 0x02; + } + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempah ^= 0x05; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + tempah ^= 0x01; + } + } + + if(SiS_Pr->ChipType < SIS_315H) { + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; + + tempah = (tempah << 5) & 0xFF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,tempah); + tempah = (tempah >> 5) & 0xFF; + + } else { + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0x08; + else if(!(SiS_IsDualEdge(SiS_Pr))) tempah |= 0x08; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2E,0xF0,tempah); + tempah &= ~0x08; + + } + + if((SiS_Pr->SiS_ModeType == ModeVGA) && (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) { + tempah |= 0x10; + } + + tempah |= 0x80; + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->PanelXRes < 1280 && SiS_Pr->PanelYRes < 960) tempah &= ~0x80; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(!(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p))) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + tempah |= 0x20; + } + } + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0D,0x40,tempah); + + tempah = 0x80; + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->PanelXRes < 1280 && SiS_Pr->PanelYRes < 960) tempah = 0; + } + + if(SiS_IsDualLink(SiS_Pr)) tempah |= 0x40; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) { + tempah |= 0x40; + } + } + + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0C,tempah); + + } else { /* LVDS */ + + if(SiS_Pr->ChipType >= SIS_315H) { + +#ifdef CONFIG_FB_SIS_315 + /* LVDS can only be slave in 8bpp modes */ + tempah = 0x80; + if((modeflag & CRT2Mode) && (SiS_Pr->SiS_ModeType > ModeVGA)) { + if(SiS_Pr->SiS_VBInfo & DriverMode) { + tempah |= 0x02; + } + } + + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) tempah |= 0x02; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempah ^= 0x01; + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 1; + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2e,0xF0,tempah); +#endif + + } else { + +#ifdef CONFIG_FB_SIS_300 + tempah = 0; + if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) { + tempah |= 0x02; + } + tempah <<= 5; + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,tempah); +#endif + + } + + } + + } /* LCDA */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->ChipType >= SIS_315H) { + +#ifdef CONFIG_FB_SIS_315 + /* unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); */ + + /* The following is nearly unpreditable and varies from machine + * to machine. Especially the 301DH seems to be a real trouble + * maker. Some BIOSes simply set the registers (like in the + * NoLCD-if-statements here), some set them according to the + * LCDA stuff. It is very likely that some machines are not + * treated correctly in the following, very case-orientated + * code. What do I do then...? + */ + + /* 740 variants match for 30xB, 301B-DH, 30xLV */ + + if(!(IS_SIS740)) { + tempah = 0x04; /* For all bridges */ + tempbl = 0xfb; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempah = 0x00; + if(SiS_IsDualEdge(SiS_Pr)) { + tempbl = 0xff; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah); + } + + /* The following two are responsible for eventually wrong colors + * in TV output. The DH (VB_NoLCD) conditions are unknown; the + * b0 was found in some 651 machine (Pim; P4_23=0xe5); the b1 version + * in a 650 box (Jake). What is the criteria? + * Addendum: Another combination 651+301B-DH(b1) (Rapo) needs same + * treatment like the 651+301B-DH(b0) case. Seems more to be the + * chipset than the bridge revision. + */ + + if((IS_SIS740) || (SiS_Pr->ChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + tempah = 0x30; + tempbl = 0xc0; + if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) || + ((SiS_Pr->SiS_ROMNew) && (!(ROMAddr[0x5b] & 0x04)))) { + tempah = 0x00; + tempbl = 0x00; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xcf,tempah); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,tempbl); + } else if(SiS_Pr->SiS_VBType & VB_SIS301) { + /* Fixes "TV-blue-bug" on 315+301 */ + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2c,0xcf); /* For 301 */ + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f); + } else if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); /* For 30xLV */ + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x21,0xc0); + } else if(SiS_Pr->SiS_VBType & VB_NoLCD) { /* For 301B-DH */ + tempah = 0x30; tempah2 = 0xc0; + tempbl = 0xcf; tempbl2 = 0x3f; + if(SiS_Pr->SiS_TVBlue == 0) { + tempah = tempah2 = 0x00; + } else if(SiS_Pr->SiS_TVBlue == -1) { + /* Set on 651/M650, clear on 315/650 */ + if(!(IS_SIS65x)) /* (bridgerev != 0xb0) */ { + tempah = tempah2 = 0x00; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,tempbl,tempah); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,tempbl2,tempah2); + } else { + tempah = 0x30; tempah2 = 0xc0; /* For 30xB, 301C */ + tempbl = 0xcf; tempbl2 = 0x3f; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempah = tempah2 = 0x00; + if(SiS_IsDualEdge(SiS_Pr)) { + tempbl = tempbl2 = 0xff; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,tempbl,tempah); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,tempbl2,tempah2); + } + + if(IS_SIS740) { + tempah = 0x80; + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0x00; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,0x7f,tempah); + } else { + tempah = 0x00; + tempbl = 0x7f; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempbl = 0xff; + if(!(SiS_IsDualEdge(SiS_Pr))) tempah = 0x80; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah); + } + +#endif /* CONFIG_FB_SIS_315 */ + + } else if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + +#ifdef CONFIG_FB_SIS_300 + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f); + + if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) || + ((SiS_Pr->SiS_VBType & VB_NoLCD) && + (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD))) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x23,0x7F); + } else { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x23,0x80); + } +#endif + + } + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x0D,0x80); + if(SiS_Pr->SiS_VBType & VB_SIS30xCLV) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3A,0xC0); + } + } + + } else { /* LVDS */ + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType >= SIS_315H) { + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + + tempah = 0x04; + tempbl = 0xfb; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempah = 0x00; + if(SiS_IsDualEdge(SiS_Pr)) tempbl = 0xff; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah); + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); + } + + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); + + } else if(SiS_Pr->ChipType == SIS_550) { + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); + + } + + } +#endif + + } + +} + +/*********************************************/ +/* GET RESOLUTION DATA */ +/*********************************************/ + +unsigned short +SiS_GetResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + if(ModeNo <= 0x13) + return ((unsigned short)SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo); + else + return ((unsigned short)SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO); +} + +static void +SiS_GetCRT2ResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short xres, yres, modeflag=0, resindex; + + if(SiS_Pr->UseCustomMode) { + xres = SiS_Pr->CHDisplay; + if(SiS_Pr->CModeFlag & HalfDCLK) xres <<= 1; + SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; + /* DoubleScanMode-check done in CheckCalcCustomMode()! */ + SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = SiS_Pr->CVDisplay; + return; + } + + resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex); + + if(ModeNo <= 0x13) { + xres = SiS_Pr->SiS_StResInfo[resindex].HTotal; + yres = SiS_Pr->SiS_StResInfo[resindex].VTotal; + } else { + xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal; + yres = SiS_Pr->SiS_ModeResInfo[resindex].VTotal; + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(!SiS_Pr->SiS_IF_DEF_DSTN && !SiS_Pr->SiS_IF_DEF_FSTN) { + + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1)) { + if((ModeNo != 0x03) && (SiS_Pr->SiS_SetFlag & SetDOSMode)) { + if(yres == 350) yres = 400; + } + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x3a) & 0x01) { + if(ModeNo == 0x12) yres = 400; + } + } + + if(modeflag & HalfDCLK) xres <<= 1; + if(modeflag & DoubleScanMode) yres <<= 1; + + } + + if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1024x768: + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + if(yres == 350) yres = 357; + if(yres == 400) yres = 420; + if(yres == 480) yres = 525; + } + } + break; + case Panel_1280x1024: + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + /* BIOS bug - does this regardless of scaling */ + if(yres == 400) yres = 405; + } + if(yres == 350) yres = 360; + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + if(yres == 360) yres = 375; + } + break; + case Panel_1600x1200: + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if(yres == 1024) yres = 1056; + } + break; + } + } + + } else { + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) { + if(xres == 720) xres = 640; + } + } else if(xres == 720) xres = 640; + + if(SiS_Pr->SiS_SetFlag & SetDOSMode) { + yres = 400; + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480; + } else { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480; + } + if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) yres = 480; + } + + } + SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; + SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres; +} + +/*********************************************/ +/* GET CRT2 TIMING DATA */ +/*********************************************/ + +static void +SiS_GetCRT2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex, unsigned short *CRT2Index, + unsigned short *ResIndex) +{ + unsigned short tempbx=0, tempal=0, resinfo=0; + + if(ModeNo <= 0x13) { + tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { /* LCD */ + + tempbx = SiS_Pr->SiS_LCDResInfo; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 32; + + /* patch index */ + if(SiS_Pr->SiS_LCDResInfo == Panel_1680x1050) { + if (resinfo == SIS_RI_1280x800) tempal = 9; + else if(resinfo == SIS_RI_1400x1050) tempal = 11; + } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x800) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x800_2) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x854)) { + if (resinfo == SIS_RI_1280x768) tempal = 9; + } + + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + /* Pass 1:1 only (center-screen handled outside) */ + /* This is never called for the panel's native resolution */ + /* since Pass1:1 will not be set in this case */ + tempbx = 100; + if(ModeNo >= 0x13) { + tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS; + } + } + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + tempbx = 200; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++; + } + } + } +#endif + + } else { /* TV */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + /* if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_TVMode &= (~TVSetTVSimuMode); */ + tempbx = 2; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + tempbx = 13; + if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) tempbx = 14; + } + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempbx = 7; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tempbx = 6; + else tempbx = 5; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) tempbx += 5; + } else { + if(SiS_Pr->SiS_TVMode & TVSetPAL) tempbx = 3; + else tempbx = 4; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) tempbx += 5; + } + + } + + tempal &= 0x3F; + + if(ModeNo > 0x13) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) { + switch(resinfo) { + case SIS_RI_720x480: + tempal = 6; + if(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetPALN)) tempal = 9; + break; + case SIS_RI_720x576: + case SIS_RI_768x576: + case SIS_RI_1024x576: /* Not in NTSC or YPBPR mode (except 1080i)! */ + tempal = 6; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempal = 8; + } + break; + case SIS_RI_800x480: + tempal = 4; + break; + case SIS_RI_512x384: + case SIS_RI_1024x768: + tempal = 7; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tempal = 8; + } + break; + case SIS_RI_1280x720: + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempal = 9; + } + break; + } + } + } + + *CRT2Index = tempbx; + *ResIndex = tempal; + + } else { /* LVDS, 301B-DH (if running on LCD) */ + + tempbx = 0; + if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + + tempbx = 90; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tempbx = 92; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) tempbx = 99; + } + if(SiS_Pr->SiS_TVMode & TVSetPALM) tempbx = 94; + else if(SiS_Pr->SiS_TVMode & TVSetPALN) tempbx = 96; + } + if(tempbx != 99) { + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx++; + } + + } else { + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: tempbx = 12; break; + case Panel_320x240_1: tempbx = 10; break; + case Panel_320x240_2: + case Panel_320x240_3: tempbx = 14; break; + case Panel_800x600: tempbx = 16; break; + case Panel_1024x600: tempbx = 18; break; + case Panel_1152x768: + case Panel_1024x768: tempbx = 20; break; + case Panel_1280x768: tempbx = 22; break; + case Panel_1280x1024: tempbx = 24; break; + case Panel_1400x1050: tempbx = 26; break; + case Panel_1600x1200: tempbx = 28; break; +#ifdef CONFIG_FB_SIS_300 + case Panel_Barco1366: tempbx = 80; break; +#endif + } + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_320x240_1: + case Panel_320x240_2: + case Panel_320x240_3: + case Panel_640x480: + break; + default: + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + } + + if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 30; + +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { + tempbx = 82; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848 || SiS_Pr->SiS_CustomT == CUT_PANEL856) { + tempbx = 84; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + } +#endif + + } + + (*CRT2Index) = tempbx; + (*ResIndex) = tempal & 0x1F; + } +} + +static void +SiS_GetRAMDAC2DATA(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short tempax=0, tempbx=0, index, dotclock; + unsigned short temp1=0, modeflag=0, tempcx=0; + + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + + if(ModeNo <= 0x13) { + + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + index = SiS_GetModePtr(SiS_Pr,ModeNo,ModeIdIndex); + + tempax = SiS_Pr->SiS_StandTable[index].CRTC[0]; + tempbx = SiS_Pr->SiS_StandTable[index].CRTC[6]; + temp1 = SiS_Pr->SiS_StandTable[index].CRTC[7]; + + dotclock = (modeflag & Charx8Dot) ? 8 : 9; + + } else { + + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + index = SiS_GetRefCRT1CRTC(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWideCRT2); + + tempax = SiS_Pr->SiS_CRT1Table[index].CR[0]; + tempax |= (SiS_Pr->SiS_CRT1Table[index].CR[14] << 8); + tempax &= 0x03FF; + tempbx = SiS_Pr->SiS_CRT1Table[index].CR[6]; + tempcx = SiS_Pr->SiS_CRT1Table[index].CR[13] << 8; + tempcx &= 0x0100; + tempcx <<= 2; + tempbx |= tempcx; + temp1 = SiS_Pr->SiS_CRT1Table[index].CR[7]; + + dotclock = 8; + + } + + if(temp1 & 0x01) tempbx |= 0x0100; + if(temp1 & 0x20) tempbx |= 0x0200; + + tempax += 5; + tempax *= dotclock; + if(modeflag & HalfDCLK) tempax <<= 1; + + tempbx++; + + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = tempbx; +} + +static void +SiS_CalcPanelLinkTiming(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex) +{ + unsigned short ResIndex; + + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + if(SiS_Pr->UseCustomMode) { + ResIndex = SiS_Pr->CHTotal; + if(SiS_Pr->CModeFlag & HalfDCLK) ResIndex <<= 1; + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = ResIndex; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal; + } else { + if(ModeNo < 0x13) { + ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS; + } + if(ResIndex == 0x09) { + if(SiS_Pr->Alternate1600x1200) ResIndex = 0x20; /* 1600x1200 LCDA */ + else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) ResIndex = 0x21; /* 1600x1200 LVDS */ + } + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAVT; + SiS_Pr->SiS_HT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDHT; + SiS_Pr->SiS_VT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDVT; + } + } else { + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + } + } else { + /* This handles custom modes and custom panels */ + SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; + SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT - (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE); + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT - (SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE); + } +} + +static void +SiS_GetCRT2DataLVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short CRT2Index, ResIndex, backup; + const struct SiS_LVDSData *LVDSData = NULL; + + SiS_GetCRT2ResInfo(SiS_Pr, ModeNo, ModeIdIndex); + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + SiS_Pr->SiS_NewFlickerMode = 0; + SiS_Pr->SiS_RVBHRS = 50; + SiS_Pr->SiS_RY1COE = 0; + SiS_Pr->SiS_RY2COE = 0; + SiS_Pr->SiS_RY3COE = 0; + SiS_Pr->SiS_RY4COE = 0; + SiS_Pr->SiS_RVBHRS2 = 0; + } + + if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + +#ifdef CONFIG_FB_SIS_315 + SiS_CalcPanelLinkTiming(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + SiS_CalcLCDACRT1Timing(SiS_Pr, ModeNo, ModeIdIndex); +#endif + + } else { + + /* 301BDH needs LVDS Data */ + backup = SiS_Pr->SiS_IF_DEF_LVDS; + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + SiS_Pr->SiS_IF_DEF_LVDS = 1; + } + + SiS_GetCRT2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + &CRT2Index, &ResIndex); + + SiS_Pr->SiS_IF_DEF_LVDS = backup; + + switch(CRT2Index) { + case 10: LVDSData = SiS_Pr->SiS_LVDS320x240Data_1; break; + case 14: LVDSData = SiS_Pr->SiS_LVDS320x240Data_2; break; + case 12: LVDSData = SiS_Pr->SiS_LVDS640x480Data_1; break; + case 16: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1; break; + case 18: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1; break; + case 20: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; +#ifdef CONFIG_FB_SIS_300 + case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1; break; + case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2; break; + case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1; break; + case 84: LVDSData = SiS_Pr->SiS_LVDS848x480Data_1; break; + case 85: LVDSData = SiS_Pr->SiS_LVDS848x480Data_2; break; +#endif + case 90: LVDSData = SiS_Pr->SiS_CHTVUNTSCData; break; + case 91: LVDSData = SiS_Pr->SiS_CHTVONTSCData; break; + case 92: LVDSData = SiS_Pr->SiS_CHTVUPALData; break; + case 93: LVDSData = SiS_Pr->SiS_CHTVOPALData; break; + case 94: LVDSData = SiS_Pr->SiS_CHTVUPALMData; break; + case 95: LVDSData = SiS_Pr->SiS_CHTVOPALMData; break; + case 96: LVDSData = SiS_Pr->SiS_CHTVUPALNData; break; + case 97: LVDSData = SiS_Pr->SiS_CHTVOPALNData; break; + case 99: LVDSData = SiS_Pr->SiS_CHTVSOPALData; break; + } + + if(LVDSData) { + SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT; + SiS_Pr->SiS_HT = (LVDSData+ResIndex)->LCDHT; + SiS_Pr->SiS_VT = (LVDSData+ResIndex)->LCDVT; + } else { + SiS_CalcPanelLinkTiming(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + + if( (!(SiS_Pr->SiS_VBType & VB_SISVB)) && + (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && + (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) ) { + if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || + (SiS_Pr->SiS_SetFlag & SetDOSMode) ) { + SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; + SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + if(ResIndex < 0x08) { + SiS_Pr->SiS_HDE = 1280; + SiS_Pr->SiS_VDE = 1024; + } + } +#endif + } + } + } +} + +static void +SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned char *ROMAddr = NULL; + unsigned short tempax, tempbx, modeflag, romptr=0; + unsigned short resinfo, CRT2Index, ResIndex; + const struct SiS_LCDData *LCDPtr = NULL; + const struct SiS_TVData *TVPtr = NULL; +#ifdef CONFIG_FB_SIS_315 + short resinfo661; +#endif + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; +#ifdef CONFIG_FB_SIS_315 + resinfo661 = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].ROMMODEIDX661; + if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && + (SiS_Pr->SiS_SetFlag & LCDVESATiming) && + (resinfo661 >= 0) && + (SiS_Pr->SiS_NeedRomModeData) ) { + if((ROMAddr = GetLCDStructPtr661(SiS_Pr))) { + if((romptr = (SISGETROMW(21)))) { + romptr += (resinfo661 * 10); + ROMAddr = SiS_Pr->VirtualRomBase; + } + } + } +#endif + } + + SiS_Pr->SiS_NewFlickerMode = 0; + SiS_Pr->SiS_RVBHRS = 50; + SiS_Pr->SiS_RY1COE = 0; + SiS_Pr->SiS_RY2COE = 0; + SiS_Pr->SiS_RY3COE = 0; + SiS_Pr->SiS_RY4COE = 0; + SiS_Pr->SiS_RVBHRS2 = 0; + + SiS_GetCRT2ResInfo(SiS_Pr,ModeNo,ModeIdIndex); + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + + if(SiS_Pr->UseCustomMode) { + + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + SiS_Pr->SiS_HDE = SiS_Pr->SiS_VGAHDE; + SiS_Pr->SiS_VDE = SiS_Pr->SiS_VGAVDE; + + tempax = SiS_Pr->CHTotal; + if(modeflag & HalfDCLK) tempax <<= 1; + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal; + + } else { + + SiS_GetRAMDAC2DATA(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + + SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, + &CRT2Index,&ResIndex); + + switch(CRT2Index) { + case 2: TVPtr = SiS_Pr->SiS_ExtHiTVData; break; + case 3: TVPtr = SiS_Pr->SiS_ExtPALData; break; + case 4: TVPtr = SiS_Pr->SiS_ExtNTSCData; break; + case 5: TVPtr = SiS_Pr->SiS_Ext525iData; break; + case 6: TVPtr = SiS_Pr->SiS_Ext525pData; break; + case 7: TVPtr = SiS_Pr->SiS_Ext750pData; break; + case 8: TVPtr = SiS_Pr->SiS_StPALData; break; + case 9: TVPtr = SiS_Pr->SiS_StNTSCData; break; + case 10: TVPtr = SiS_Pr->SiS_St525iData; break; + case 11: TVPtr = SiS_Pr->SiS_St525pData; break; + case 12: TVPtr = SiS_Pr->SiS_St750pData; break; + case 13: TVPtr = SiS_Pr->SiS_St1HiTVData; break; + case 14: TVPtr = SiS_Pr->SiS_St2HiTVData; break; + default: TVPtr = SiS_Pr->SiS_StPALData; break; + } + + SiS_Pr->SiS_RVBHCMAX = (TVPtr+ResIndex)->RVBHCMAX; + SiS_Pr->SiS_RVBHCFACT = (TVPtr+ResIndex)->RVBHCFACT; + SiS_Pr->SiS_VGAHT = (TVPtr+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (TVPtr+ResIndex)->VGAVT; + SiS_Pr->SiS_HDE = (TVPtr+ResIndex)->TVHDE; + SiS_Pr->SiS_VDE = (TVPtr+ResIndex)->TVVDE; + SiS_Pr->SiS_RVBHRS2 = (TVPtr+ResIndex)->RVBHRS2 & 0x0fff; + if(modeflag & HalfDCLK) { + SiS_Pr->SiS_RVBHRS = (TVPtr+ResIndex)->HALFRVBHRS; + if(SiS_Pr->SiS_RVBHRS2) { + SiS_Pr->SiS_RVBHRS2 = ((SiS_Pr->SiS_RVBHRS2 + 3) >> 1) - 3; + tempax = ((TVPtr+ResIndex)->RVBHRS2 >> 12) & 0x07; + if((TVPtr+ResIndex)->RVBHRS2 & 0x8000) SiS_Pr->SiS_RVBHRS2 -= tempax; + else SiS_Pr->SiS_RVBHRS2 += tempax; + } + } else { + SiS_Pr->SiS_RVBHRS = (TVPtr+ResIndex)->RVBHRS; + } + SiS_Pr->SiS_NewFlickerMode = ((TVPtr+ResIndex)->FlickerMode) << 7; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + + if((resinfo == SIS_RI_960x600) || + (resinfo == SIS_RI_1024x768) || + (resinfo == SIS_RI_1280x1024) || + (resinfo == SIS_RI_1280x720)) { + SiS_Pr->SiS_NewFlickerMode = 0x40; + } + + if(SiS_Pr->SiS_VGAVDE == 350) SiS_Pr->SiS_TVMode |= TVSetTVSimuMode; + + SiS_Pr->SiS_HT = ExtHiTVHT; + SiS_Pr->SiS_VT = ExtHiTVVT; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + SiS_Pr->SiS_HT = StHiTVHT; + SiS_Pr->SiS_VT = StHiTVVT; + } + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + SiS_Pr->SiS_HT = 1650; + SiS_Pr->SiS_VT = 750; + } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { + SiS_Pr->SiS_HT = NTSCHT; + if(SiS_Pr->SiS_TVMode & TVSet525p1024) SiS_Pr->SiS_HT = NTSC2HT; + SiS_Pr->SiS_VT = NTSCVT; + } else { + SiS_Pr->SiS_HT = NTSCHT; + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) SiS_Pr->SiS_HT = NTSC2HT; + SiS_Pr->SiS_VT = NTSCVT; + } + + } else { + + SiS_Pr->SiS_RY1COE = (TVPtr+ResIndex)->RY1COE; + SiS_Pr->SiS_RY2COE = (TVPtr+ResIndex)->RY2COE; + SiS_Pr->SiS_RY3COE = (TVPtr+ResIndex)->RY3COE; + SiS_Pr->SiS_RY4COE = (TVPtr+ResIndex)->RY4COE; + + if(modeflag & HalfDCLK) { + SiS_Pr->SiS_RY1COE = 0x00; + SiS_Pr->SiS_RY2COE = 0xf4; + SiS_Pr->SiS_RY3COE = 0x10; + SiS_Pr->SiS_RY4COE = 0x38; + } + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + SiS_Pr->SiS_HT = NTSCHT; + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) SiS_Pr->SiS_HT = NTSC2HT; + SiS_Pr->SiS_VT = NTSCVT; + } else { + SiS_Pr->SiS_HT = PALHT; + SiS_Pr->SiS_VT = PALVT; + } + + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + + if(SiS_Pr->UseCustomMode) { + + SiS_Pr->SiS_HDE = SiS_Pr->SiS_VGAHDE; + SiS_Pr->SiS_VDE = SiS_Pr->SiS_VGAVDE; + + tempax = SiS_Pr->CHTotal; + if(modeflag & HalfDCLK) tempax <<= 1; + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal; + + } else { + + bool gotit = false; + + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + gotit = true; + + } else if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) && (romptr) && (ROMAddr) ) { + +#ifdef CONFIG_FB_SIS_315 + SiS_Pr->SiS_RVBHCMAX = ROMAddr[romptr]; + SiS_Pr->SiS_RVBHCFACT = ROMAddr[romptr+1]; + SiS_Pr->SiS_VGAHT = ROMAddr[romptr+2] | ((ROMAddr[romptr+3] & 0x0f) << 8); + SiS_Pr->SiS_VGAVT = (ROMAddr[romptr+4] << 4) | ((ROMAddr[romptr+3] & 0xf0) >> 4); + SiS_Pr->SiS_HT = ROMAddr[romptr+5] | ((ROMAddr[romptr+6] & 0x0f) << 8); + SiS_Pr->SiS_VT = (ROMAddr[romptr+7] << 4) | ((ROMAddr[romptr+6] & 0xf0) >> 4); + SiS_Pr->SiS_RVBHRS2 = ROMAddr[romptr+8] | ((ROMAddr[romptr+9] & 0x0f) << 8); + if((SiS_Pr->SiS_RVBHRS2) && (modeflag & HalfDCLK)) { + SiS_Pr->SiS_RVBHRS2 = ((SiS_Pr->SiS_RVBHRS2 + 3) >> 1) - 3; + tempax = (ROMAddr[romptr+9] >> 4) & 0x07; + if(ROMAddr[romptr+9] & 0x80) SiS_Pr->SiS_RVBHRS2 -= tempax; + else SiS_Pr->SiS_RVBHRS2 += tempax; + } + if(SiS_Pr->SiS_VGAHT) gotit = true; + else { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + SiS_Pr->SiS_RVBHRS2 = 0; + gotit = true; + } +#endif + + } + + if(!gotit) { + + SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, + &CRT2Index,&ResIndex); + + switch(CRT2Index) { + case Panel_1024x768 : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; + case Panel_1024x768 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data; break; + case Panel_1280x720 : + case Panel_1280x720 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x720Data; break; + case Panel_1280x768_2 : LCDPtr = SiS_Pr->SiS_ExtLCD1280x768_2Data; break; + case Panel_1280x768_2+ 32: LCDPtr = SiS_Pr->SiS_StLCD1280x768_2Data; break; + case Panel_1280x800 : + case Panel_1280x800 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x800Data; break; + case Panel_1280x800_2 : + case Panel_1280x800_2+ 32: LCDPtr = SiS_Pr->SiS_LCD1280x800_2Data; break; + case Panel_1280x854 : + case Panel_1280x854 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x854Data; break; + case Panel_1280x960 : + case Panel_1280x960 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x960Data; break; + case Panel_1280x1024 : LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data; break; + case Panel_1280x1024 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; + case Panel_1400x1050 : LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data; break; + case Panel_1400x1050 + 32: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data; break; + case Panel_1600x1200 : LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data; break; + case Panel_1600x1200 + 32: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data; break; + case Panel_1680x1050 : + case Panel_1680x1050 + 32: LCDPtr = SiS_Pr->SiS_LCD1680x1050Data; break; + case 100 : LCDPtr = SiS_Pr->SiS_NoScaleData; break; +#ifdef CONFIG_FB_SIS_315 + case 200 : LCDPtr = SiS310_ExtCompaq1280x1024Data; break; + case 201 : LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; +#endif + default : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; + } + + SiS_Pr->SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX; + SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT; + SiS_Pr->SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (LCDPtr+ResIndex)->VGAVT; + SiS_Pr->SiS_HT = (LCDPtr+ResIndex)->LCDHT; + SiS_Pr->SiS_VT = (LCDPtr+ResIndex)->LCDVT; + + } + + tempax = SiS_Pr->PanelXRes; + tempbx = SiS_Pr->PanelYRes; + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1024x768: + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + if(SiS_Pr->ChipType < SIS_315H) { + if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; + } + } else { + if (SiS_Pr->SiS_VGAVDE == 357) tempbx = 527; + else if(SiS_Pr->SiS_VGAVDE == 420) tempbx = 620; + else if(SiS_Pr->SiS_VGAVDE == 525) tempbx = 775; + else if(SiS_Pr->SiS_VGAVDE == 600) tempbx = 775; + else if(SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; + } + break; + case Panel_1280x960: + if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 700; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 800; + else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960; + break; + case Panel_1280x1024: + if (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768; + else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800; + else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864; + break; + case Panel_1600x1200: + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 875; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 1000; + } + break; + } + + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->SiS_VGAHDE; + tempbx = SiS_Pr->SiS_VGAVDE; + } + + SiS_Pr->SiS_HDE = tempax; + SiS_Pr->SiS_VDE = tempbx; + } + } +} + +static void +SiS_GetCRT2Data(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } else { + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + /* Need LVDS Data for LCD on 301B-DH */ + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } else { + SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + } + + } else { + + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + + } +} + +/*********************************************/ +/* GET LVDS DES (SKEW) DATA */ +/*********************************************/ + +static const struct SiS_LVDSDes * +SiS_GetLVDSDesPtr(struct SiS_Private *SiS_Pr) +{ + const struct SiS_LVDSDes *PanelDesPtr = NULL; + +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_LCDTypeInfo == 4) { + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + PanelDesPtr = SiS_Pr->SiS_PanelType04_1a; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + PanelDesPtr = SiS_Pr->SiS_PanelType04_2a; + } + } else if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { + PanelDesPtr = SiS_Pr->SiS_PanelType04_1b; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + PanelDesPtr = SiS_Pr->SiS_PanelType04_2b; + } + } + } + } + } +#endif + return PanelDesPtr; +} + +static void +SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short modeflag, ResIndex; + const struct SiS_LVDSDes *PanelDesPtr = NULL; + + SiS_Pr->SiS_LCDHDES = 0; + SiS_Pr->SiS_LCDVDES = 0; + + /* Some special cases */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + + /* Trumpion */ + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + } + return; + } + + /* 640x480 on LVDS */ + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480 && SiS_Pr->SiS_LCDTypeInfo == 3) { + SiS_Pr->SiS_LCDHDES = 8; + if (SiS_Pr->SiS_VGAVDE >= 480) SiS_Pr->SiS_LCDVDES = 512; + else if(SiS_Pr->SiS_VGAVDE >= 400) SiS_Pr->SiS_LCDVDES = 436; + else if(SiS_Pr->SiS_VGAVDE >= 350) SiS_Pr->SiS_LCDVDES = 440; + return; + } + } + + } /* LCD */ + + if( (SiS_Pr->UseCustomMode) || + (SiS_Pr->SiS_LCDResInfo == Panel_Custom) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + (SiS_Pr->SiS_CustomT == CUT_PANEL856) || + (SiS_Pr->SiS_LCDInfo & LCDPass11) ) { + return; + } + + if(ModeNo <= 0x13) ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + else ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + + if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + /* non-pass 1:1 only, see above */ + if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) { + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) / 2); + } + if(SiS_Pr->SiS_VGAVDE != SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE) / 2); + } + } + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + switch(SiS_Pr->SiS_CustomT) { + case CUT_UNIWILL1024: + case CUT_UNIWILL10242: + case CUT_CLEVO1400: + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + break; + } + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1280x1024: + if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + break; + case Panel_1280x800: /* Verified for Averatec 6240 */ + case Panel_1280x800_2: /* Verified for Asus A4L */ + case Panel_1280x854: /* Not verified yet FIXME */ + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + break; + } + } +#endif + + } else { + + if((SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + + if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) { + if(ResIndex <= 3) SiS_Pr->SiS_LCDHDES = 256; + } + + } else if((PanelDesPtr = SiS_GetLVDSDesPtr(SiS_Pr))) { + + SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES; + SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES; + + } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + + if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) { + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) / 2); + } + if(SiS_Pr->SiS_VGAVDE != SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE) / 2); + } else { + if(SiS_Pr->ChipType < SIS_315H) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } else { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_800x600: + case Panel_1024x768: + case Panel_1280x1024: + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT; + break; + case Panel_1400x1050: + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + break; + } + } + } + + } else { + + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef CONFIG_FB_SIS_300 + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_800x600: + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } else { + SiS_Pr->SiS_LCDHDES = SiS_Pr->PanelHT + 3; + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT; + if(SiS_Pr->SiS_VGAVDE == 400) SiS_Pr->SiS_LCDVDES -= 2; + else SiS_Pr->SiS_LCDVDES -= 4; + } + break; + case Panel_1024x768: + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } else { + SiS_Pr->SiS_LCDHDES = SiS_Pr->PanelHT - 1; + if(SiS_Pr->SiS_VGAVDE <= 400) SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 8; + if(SiS_Pr->SiS_VGAVDE <= 350) SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 12; + } + break; + case Panel_1024x600: + default: + if( (SiS_Pr->SiS_VGAHDE == SiS_Pr->PanelXRes) && + (SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) ) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } else { + SiS_Pr->SiS_LCDHDES = SiS_Pr->PanelHT - 1; + } + break; + } + + switch(SiS_Pr->SiS_LCDTypeInfo) { + case 1: + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0; + break; + case 3: /* 640x480 only? */ + SiS_Pr->SiS_LCDHDES = 8; + if (SiS_Pr->SiS_VGAVDE >= 480) SiS_Pr->SiS_LCDVDES = 512; + else if(SiS_Pr->SiS_VGAVDE >= 400) SiS_Pr->SiS_LCDVDES = 436; + else if(SiS_Pr->SiS_VGAVDE >= 350) SiS_Pr->SiS_LCDVDES = 440; + break; + } +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1024x768: + case Panel_1280x1024: + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + break; + case Panel_320x240_1: + case Panel_320x240_2: + case Panel_320x240_3: + SiS_Pr->SiS_LCDVDES = 524; + break; + } +#endif + } + } + + if((ModeNo <= 0x13) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 632; + } else if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) { + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) { + if(SiS_Pr->SiS_LCDResInfo >= Panel_1024x768) { + if(SiS_Pr->ChipType < SIS_315H) { + if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320; + } else { +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) SiS_Pr->SiS_LCDHDES = 480; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804; + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 704; + if(!(modeflag & HalfDCLK)) { + SiS_Pr->SiS_LCDHDES = 320; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 632; + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 542; + } +#endif + } + } + } + } + } + } +} + +/*********************************************/ +/* DISABLE VIDEO BRIDGE */ +/*********************************************/ + +#ifdef CONFIG_FB_SIS_315 +static int +SiS_HandlePWD(struct SiS_Private *SiS_Pr) +{ + int ret = 0; +#ifdef SET_PWD + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr = GetLCDStructPtr661_2(SiS_Pr); + unsigned char drivermode = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40; + unsigned short temp; + + if( (SiS_Pr->SiS_VBType & VB_SISPWD) && + (romptr) && + (SiS_Pr->SiS_PWDOffset) ) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2b,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 0]); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2c,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 1]); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2d,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 2]); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2e,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 3]); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2f,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 4]); + temp = 0x00; + if((ROMAddr[romptr + 2] & (0x06 << 1)) && !drivermode) { + temp = 0x80; + ret = 1; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x27,0x7f,temp); + } +#endif + return ret; +} +#endif + +/* NEVER use any variables (VBInfo), this will be called + * from outside the context of modeswitch! + * MUST call getVBType before calling this + */ +void +SiS_DisableBridge(struct SiS_Private *SiS_Pr) +{ +#ifdef CONFIG_FB_SIS_315 + unsigned short tempah, pushax=0, modenum; +#endif + unsigned short temp=0; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { /* ===== For 30xB/C/LV ===== */ + + if(SiS_Pr->ChipType < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 /* 300 series */ + + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); + } else { + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); + } + SiS_PanelDelay(SiS_Pr, 3); + } + if(SiS_Is301B(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0x3f); + SiS_ShortDelay(SiS_Pr,1); + } + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF); + SiS_DisplayOff(SiS_Pr); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); + SiS_UnLockCRT2(SiS_Pr); + if(!(SiS_Pr->SiS_VBType & VB_SISLVDS)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); + } + if( (!(SiS_CRT2IsLCD(SiS_Pr))) || + (!(SiS_CR36BIOSWord23d(SiS_Pr))) ) { + SiS_PanelDelay(SiS_Pr, 2); + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); + } else { + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04); + } + } + +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 /* 315 series */ + + int didpwd = 0; + bool custom1 = (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || + (SiS_Pr->SiS_CustomT == CUT_CLEVO1400); + + modenum = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34) & 0x7f; + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + +#ifdef SET_EMI + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); + } + } +#endif + + didpwd = SiS_HandlePWD(SiS_Pr); + + if( (modenum <= 0x13) || + (SiS_IsVAMode(SiS_Pr)) || + (!(SiS_IsDualEdge(SiS_Pr))) ) { + if(!didpwd) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xfe); + if(custom1) SiS_PanelDelay(SiS_Pr, 3); + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xfc); + } + } + + if(!custom1) { + SiS_DDC2Delay(SiS_Pr,0xff00); + SiS_DDC2Delay(SiS_Pr,0xe000); + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00); + pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06); + if(IS_SIS740) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3); + } + SiS_PanelDelay(SiS_Pr, 3); + } + + } + + if(!(SiS_IsNotM650orLater(SiS_Pr))) { + /* if(SiS_Pr->ChipType < SIS_340) {*/ + tempah = 0xef; + if(SiS_IsVAMode(SiS_Pr)) tempah = 0xf7; + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah); + /*}*/ + } + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,~0x10); + } + + tempah = 0x3f; + if(SiS_IsDualEdge(SiS_Pr)) { + tempah = 0x7f; + if(!(SiS_IsVAMode(SiS_Pr))) tempah = 0xbf; + } + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah); + + if((SiS_IsVAMode(SiS_Pr)) || + ((SiS_Pr->SiS_VBType & VB_SISLVDS) && (modenum <= 0x13))) { + + SiS_DisplayOff(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_PanelDelay(SiS_Pr, 2); + } + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF); + + } + + if((!(SiS_IsVAMode(SiS_Pr))) || + ((SiS_Pr->SiS_VBType & VB_SISLVDS) && (modenum <= 0x13))) { + + if(!(SiS_IsDualEdge(SiS_Pr))) { + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf); + SiS_DisplayOff(SiS_Pr); + } + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_PanelDelay(SiS_Pr, 2); + } + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp); + + } + + if(SiS_IsNotM650orLater(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); + } + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + + if( (!(SiS_IsVAMode(SiS_Pr))) && + (!(SiS_CRT2IsLCD(SiS_Pr))) && + (!(SiS_IsDualEdge(SiS_Pr))) ) { + + if(custom1) SiS_PanelDelay(SiS_Pr, 2); + if(!didpwd) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); + } + if(custom1) SiS_PanelDelay(SiS_Pr, 4); + } + + if(!custom1) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax); + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + if(SiS_IsVAorLCD(SiS_Pr)) { + SiS_PanelDelayLoop(SiS_Pr, 3, 20); + } + } + } + + } + +#endif /* CONFIG_FB_SIS_315 */ + + } + + } else { /* ============ For 301 ================ */ + + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef CONFIG_FB_SIS_300 + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, 3); + } +#endif + } + + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF); /* disable VB */ + SiS_DisplayOff(SiS_Pr); + + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); + } + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); /* disable lock mode */ + + if(SiS_Pr->ChipType >= SIS_315H) { + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp); + } else { +#ifdef CONFIG_FB_SIS_300 + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); /* disable CRT2 */ + if( (!(SiS_CRT2IsLCD(SiS_Pr))) || + (!(SiS_CR36BIOSWord23d(SiS_Pr))) ) { + SiS_PanelDelay(SiS_Pr, 2); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04); + } +#endif + } + + } + + } else { /* ============ For LVDS =============*/ + + if(SiS_Pr->ChipType < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 /* 300 series */ + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + SiS_SetCH700x(SiS_Pr,0x0E,0x09); + } + + if(SiS_Pr->ChipType == SIS_730) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x08)) { + SiS_WaitVBRetrace(SiS_Pr); + } + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, 3); + } + } else { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x08)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_WaitVBRetrace(SiS_Pr); + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x1c)) { + SiS_DisplayOff(SiS_Pr); + } + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, 3); + } + } + } + } + + SiS_DisplayOff(SiS_Pr); + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); + SiS_UnLockCRT2(SiS_Pr); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); + + if( (!(SiS_CRT2IsLCD(SiS_Pr))) || + (!(SiS_CR36BIOSWord23d(SiS_Pr))) ) { + SiS_PanelDelay(SiS_Pr, 2); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04); + } + +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 /* 315 series */ + + if(!(SiS_IsNotM650orLater(SiS_Pr))) { + /*if(SiS_Pr->ChipType < SIS_340) { */ /* XGI needs this */ + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,~0x18); + /* } */ + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + + if(SiS_Pr->ChipType == SIS_740) { + temp = SiS_GetCH701x(SiS_Pr,0x61); + if(temp < 1) { + SiS_SetCH701x(SiS_Pr,0x76,0xac); + SiS_SetCH701x(SiS_Pr,0x66,0x00); + } + + if( (!(SiS_IsDualEdge(SiS_Pr))) || + (SiS_IsTVOrYPbPrOrScart(SiS_Pr)) ) { + SiS_SetCH701x(SiS_Pr,0x49,0x3e); + } + } + + if( (!(SiS_IsDualEdge(SiS_Pr))) || + (SiS_IsVAMode(SiS_Pr)) ) { + SiS_Chrontel701xBLOff(SiS_Pr); + SiS_Chrontel701xOff(SiS_Pr); + } + + if(SiS_Pr->ChipType != SIS_740) { + if( (!(SiS_IsDualEdge(SiS_Pr))) || + (SiS_IsTVOrYPbPrOrScart(SiS_Pr)) ) { + SiS_SetCH701x(SiS_Pr,0x49,0x01); + } + } + + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, 3); + } + + if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || + (!(SiS_IsDualEdge(SiS_Pr))) || + (!(SiS_IsTVOrYPbPrOrScart(SiS_Pr))) ) { + SiS_DisplayOff(SiS_Pr); + } + + if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || + (!(SiS_IsDualEdge(SiS_Pr))) || + (!(SiS_IsVAMode(SiS_Pr))) ) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); + } + + if(SiS_Pr->ChipType == SIS_740) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); + } + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); + + if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || + (!(SiS_IsDualEdge(SiS_Pr))) || + (!(SiS_IsVAMode(SiS_Pr))) ) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); + if(SiS_Pr->ChipType == SIS_550) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xbf); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xef); + } + } + } else { + if(SiS_Pr->ChipType == SIS_740) { + if(SiS_IsLCDOrLCDA(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); + } + } else if(SiS_IsVAMode(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); + } + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_IsDualEdge(SiS_Pr)) { + /* SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xff); */ + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); + } + } + + SiS_UnLockCRT2(SiS_Pr); + + if(SiS_Pr->ChipType == SIS_550) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); /* DirectDVD PAL?*/ + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); /* VB clock / 4 ? */ + } else if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || + (!(SiS_IsDualEdge(SiS_Pr))) || + (!(SiS_IsVAMode(SiS_Pr))) ) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 2); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04); + } + } + } + +#endif /* CONFIG_FB_SIS_315 */ + + } /* 315 series */ + + } /* LVDS */ + +} + +/*********************************************/ +/* ENABLE VIDEO BRIDGE */ +/*********************************************/ + +/* NEVER use any variables (VBInfo), this will be called + * from outside the context of a mode switch! + * MUST call getVBType before calling this + */ +static +void +SiS_EnableBridge(struct SiS_Private *SiS_Pr) +{ + unsigned short temp=0, tempah; +#ifdef CONFIG_FB_SIS_315 + unsigned short temp1, pushax=0; + bool delaylong = false; +#endif + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { /* ====== For 301B et al ====== */ + + if(SiS_Pr->ChipType < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 /* 300 series */ + + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); + } else if(SiS_Pr->SiS_VBType & VB_NoLCD) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x00); + } + if(SiS_Pr->SiS_VBType & (VB_SISLVDS | VB_NoLCD)) { + if(!(SiS_CR36BIOSWord23d(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 0); + } + } + } + + if((SiS_Pr->SiS_VBType & VB_NoLCD) && + (SiS_CRT2IsLCD(SiS_Pr))) { + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); /* Enable CRT2 */ + SiS_DisplayOn(SiS_Pr); + SiS_UnLockCRT2(SiS_Pr); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF); + if(SiS_BridgeInSlavemode(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40); + } + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 1); + } + SiS_WaitVBRetrace(SiS_Pr); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x00); + } + } + + } else { + + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; /* lock mode */ + if(SiS_BridgeInSlavemode(SiS_Pr)) { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20; + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20); /* enable VB processor */ + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0); + SiS_DisplayOn(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 1); + } + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); + } + } + } + + } + + +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 /* 315 series */ + +#ifdef SET_EMI + unsigned char r30=0, r31=0, r32=0, r33=0, cr36=0; + int didpwd = 0; + /* unsigned short emidelay=0; */ +#endif + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef); +#ifdef SET_EMI + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); + } +#endif + } + + if(!(SiS_IsNotM650orLater(SiS_Pr))) { + /*if(SiS_Pr->ChipType < SIS_340) { */ + tempah = 0x10; + if(SiS_LCDAEnabled(SiS_Pr)) { + if(SiS_TVEnabled(SiS_Pr)) tempah = 0x18; + else tempah = 0x08; + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah); + /*}*/ + } + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00); + SiS_DisplayOff(SiS_Pr); + pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06); + if(IS_SIS740) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3); + } + + didpwd = SiS_HandlePWD(SiS_Pr); + + if(SiS_IsVAorLCD(SiS_Pr)) { + if(!didpwd) { + if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) { + SiS_PanelDelayLoop(SiS_Pr, 3, 2); + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); + SiS_PanelDelayLoop(SiS_Pr, 3, 2); + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_GenericDelay(SiS_Pr, 17664); + } + } + } else { + SiS_PanelDelayLoop(SiS_Pr, 3, 2); + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_GenericDelay(SiS_Pr, 17664); + } + } + } + + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40)) { + SiS_PanelDelayLoop(SiS_Pr, 3, 10); + delaylong = true; + } + + } + + if(!(SiS_IsVAMode(SiS_Pr))) { + + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; + if(SiS_BridgeInSlavemode(SiS_Pr)) { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(!(tempah & SetCRT2ToRAMDAC)) { + if(!(SiS_LCDAEnabled(SiS_Pr))) temp |= 0x20; + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); /* enable CRT2 */ + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80); + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_PanelDelay(SiS_Pr, 2); + } + + } else { + + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20); + + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80); + + if(SiS_Pr->SiS_VBType & VB_SISPOWER) { + if( (SiS_LCDAEnabled(SiS_Pr)) || + (SiS_CRT2IsLCD(SiS_Pr)) ) { + /* Enable "LVDS PLL power on" (even on 301C) */ + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x2a,0x7f); + /* Enable "LVDS Driver Power on" (even on 301C) */ + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x7f); + } + } + + tempah = 0xc0; + if(SiS_IsDualEdge(SiS_Pr)) { + tempah = 0x80; + if(!(SiS_IsVAMode(SiS_Pr))) tempah = 0x40; + } + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah); + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + + SiS_PanelDelay(SiS_Pr, 2); + + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1f,0x10); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80); + + if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) { +#ifdef SET_EMI + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); + SiS_GenericDelay(SiS_Pr, 2048); + } +#endif + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c); + + if(SiS_Pr->SiS_VBType & VB_SISEMI) { +#ifdef SET_EMI + cr36 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + + if(SiS_Pr->SiS_ROMNew) { + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr = GetLCDStructPtr661_2(SiS_Pr); + if(romptr) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20); /* Reset */ + SiS_Pr->EMI_30 = 0; + SiS_Pr->EMI_31 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 0]; + SiS_Pr->EMI_32 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 1]; + SiS_Pr->EMI_33 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 2]; + if(ROMAddr[romptr + 1] & 0x10) SiS_Pr->EMI_30 = 0x40; + /* emidelay = SISGETROMW((romptr + 0x22)); */ + SiS_Pr->HaveEMI = SiS_Pr->HaveEMILCD = SiS_Pr->OverruleEMI = true; + } + } + + /* (P4_30|0x40) */ + /* Compal 1400x1050: 0x05, 0x60, 0x00 YES (1.10.7w; CR36=69) */ + /* Compal 1400x1050: 0x0d, 0x70, 0x40 YES (1.10.7x; CR36=69) */ + /* Acer 1280x1024: 0x12, 0xd0, 0x6b NO (1.10.9k; CR36=73) */ + /* Compaq 1280x1024: 0x0d, 0x70, 0x6b YES (1.12.04b; CR36=03) */ + /* Clevo 1024x768: 0x05, 0x60, 0x33 NO (1.10.8e; CR36=12, DL!) */ + /* Clevo 1024x768: 0x0d, 0x70, 0x40 (if type == 3) YES (1.10.8y; CR36=?2) */ + /* Clevo 1024x768: 0x05, 0x60, 0x33 (if type != 3) YES (1.10.8y; CR36=?2) */ + /* Asus 1024x768: ? ? (1.10.8o; CR36=?2) */ + /* Asus 1024x768: 0x08, 0x10, 0x3c (problematic) YES (1.10.8q; CR36=22) */ + + if(SiS_Pr->HaveEMI) { + r30 = SiS_Pr->EMI_30; r31 = SiS_Pr->EMI_31; + r32 = SiS_Pr->EMI_32; r33 = SiS_Pr->EMI_33; + } else { + r30 = 0; + } + + /* EMI_30 is read at driver start; however, the BIOS sets this + * (if it is used) only if the LCD is in use. In case we caught + * the machine while on TV output, this bit is not set and we + * don't know if it should be set - hence our detection is wrong. + * Work-around this here: + */ + + if((!SiS_Pr->HaveEMI) || (!SiS_Pr->HaveEMILCD)) { + switch((cr36 & 0x0f)) { + case 2: + r30 |= 0x40; + if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) r30 &= ~0x40; + if(!SiS_Pr->HaveEMI) { + r31 = 0x05; r32 = 0x60; r33 = 0x33; + if((cr36 & 0xf0) == 0x30) { + r31 = 0x0d; r32 = 0x70; r33 = 0x40; + } + } + break; + case 3: /* 1280x1024 */ + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) r30 |= 0x40; + if(!SiS_Pr->HaveEMI) { + r31 = 0x12; r32 = 0xd0; r33 = 0x6b; + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { + r31 = 0x0d; r32 = 0x70; r33 = 0x6b; + } + } + break; + case 9: /* 1400x1050 */ + r30 |= 0x40; + if(!SiS_Pr->HaveEMI) { + r31 = 0x05; r32 = 0x60; r33 = 0x00; + if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) { + r31 = 0x0d; r32 = 0x70; r33 = 0x40; /* BIOS values */ + } + } + break; + case 11: /* 1600x1200 - unknown */ + r30 |= 0x40; + if(!SiS_Pr->HaveEMI) { + r31 = 0x05; r32 = 0x60; r33 = 0x00; + } + } + } + + /* BIOS values don't work so well sometimes */ + if(!SiS_Pr->OverruleEMI) { +#ifdef COMPAL_HACK + if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) { + if((cr36 & 0x0f) == 0x09) { + r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x00; + } + } +#endif +#ifdef COMPAQ_HACK + if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { + if((cr36 & 0x0f) == 0x03) { + r30 = 0x20; r31 = 0x12; r32 = 0xd0; r33 = 0x6b; + } + } +#endif +#ifdef ASUS_HACK + if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { + if((cr36 & 0x0f) == 0x02) { + /* r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x33; */ /* rev 2 */ + /* r30 = 0x20; r31 = 0x05; r32 = 0x60; r33 = 0x33; */ /* rev 3 */ + /* r30 = 0x60; r31 = 0x0d; r32 = 0x70; r33 = 0x40; */ /* rev 4 */ + /* r30 = 0x20; r31 = 0x0d; r32 = 0x70; r33 = 0x40; */ /* rev 5 */ + } + } +#endif + } + + if(!(SiS_Pr->OverruleEMI && (!r30) && (!r31) && (!r32) && (!r33))) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20); /* Reset */ + SiS_GenericDelay(SiS_Pr, 2048); + } + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x31,r31); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x32,r32); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x33,r33); +#endif /* SET_EMI */ + + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); + +#ifdef SET_EMI + if( (SiS_LCDAEnabled(SiS_Pr)) || + (SiS_CRT2IsLCD(SiS_Pr)) ) { + if(r30 & 0x40) { + /*SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x2a,0x80);*/ + SiS_PanelDelayLoop(SiS_Pr, 3, 5); + if(delaylong) { + SiS_PanelDelayLoop(SiS_Pr, 3, 5); + delaylong = false; + } + SiS_WaitVBRetrace(SiS_Pr); + SiS_WaitVBRetrace(SiS_Pr); + if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { + SiS_GenericDelay(SiS_Pr, 1280); + } + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40); /* Enable */ + /*SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x2a,0x7f);*/ + } + } +#endif + } + } + + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + if(SiS_IsVAorLCD(SiS_Pr)) { + SiS_PanelDelayLoop(SiS_Pr, 3, 10); + if(delaylong) { + SiS_PanelDelayLoop(SiS_Pr, 3, 10); + } + SiS_WaitVBRetrace(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_GenericDelay(SiS_Pr, 2048); + SiS_WaitVBRetrace(SiS_Pr); + } + if(!didpwd) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); + } else { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x03); + } + } + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax); + SiS_DisplayOn(SiS_Pr); + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xff); + + } + + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); + } + +#endif /* CONFIG_FB_SIS_315 */ + + } + + } else { /* ============ For 301 ================ */ + + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x00); + SiS_PanelDelay(SiS_Pr, 0); + } + } + + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; /* lock mode */ + if(SiS_BridgeInSlavemode(SiS_Pr)) { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20; + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); /* enable CRT2 */ + + if(SiS_Pr->ChipType >= SIS_315H) { + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E); + if(!(temp & 0x80)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80); /* BVBDOENABLE=1 */ + } + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20); /* enable VB processor */ + + SiS_VBLongWait(SiS_Pr); + SiS_DisplayOn(SiS_Pr); + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); + } + SiS_VBLongWait(SiS_Pr); + + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_PanelDelay(SiS_Pr, 1); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x00); + } + } + + } + + } else { /* =================== For LVDS ================== */ + + if(SiS_Pr->ChipType < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 /* 300 series */ + + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(SiS_Pr->ChipType == SIS_730) { + SiS_PanelDelay(SiS_Pr, 1); + SiS_PanelDelay(SiS_Pr, 1); + SiS_PanelDelay(SiS_Pr, 1); + } + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x00); + if(!(SiS_CR36BIOSWord23d(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 0); + } + } + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_DisplayOn(SiS_Pr); + SiS_UnLockCRT2(SiS_Pr); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF); + if(SiS_BridgeInSlavemode(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + if(!(SiS_CRT2IsLCD(SiS_Pr))) { + SiS_WaitVBRetrace(SiS_Pr); + SiS_SetCH700x(SiS_Pr,0x0E,0x0B); + } + } + + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 1); + SiS_PanelDelay(SiS_Pr, 1); + } + SiS_WaitVBRetrace(SiS_Pr); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x00); + } + } + } + +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 /* 315 series */ + + if(!(SiS_IsNotM650orLater(SiS_Pr))) { + /*if(SiS_Pr->ChipType < SIS_340) {*/ /* XGI needs this */ + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,0x18); + /*}*/ + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x00); + SiS_PanelDelay(SiS_Pr, 0); + } + } + + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_UnLockCRT2(SiS_Pr); + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7); + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp &= 0x20; + SiS_Chrontel701xBLOff(SiS_Pr); + } + + if(SiS_Pr->ChipType != SIS_550) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); + } + + if(SiS_Pr->ChipType == SIS_740) { + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_IsLCDOrLCDA(SiS_Pr)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); + } + } + } + + temp1 = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E); + if(!(temp1 & 0x80)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(temp) { + SiS_Chrontel701xBLOn(SiS_Pr); + } + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); + if(SiS_Pr->ChipType == SIS_550) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x40); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x10); + } + } + } else if(SiS_IsVAMode(SiS_Pr)) { + if(SiS_Pr->ChipType != SIS_740) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); + } + } + + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_IsTVOrYPbPrOrScart(SiS_Pr)) { + SiS_Chrontel701xOn(SiS_Pr); + } + if( (SiS_IsVAMode(SiS_Pr)) || + (SiS_IsLCDOrLCDA(SiS_Pr)) ) { + SiS_ChrontelDoSomething1(SiS_Pr); + } + } + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + if( (SiS_IsVAMode(SiS_Pr)) || + (SiS_IsLCDOrLCDA(SiS_Pr)) ) { + SiS_Chrontel701xBLOn(SiS_Pr); + SiS_ChrontelInitTVVSync(SiS_Pr); + } + } + } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_PanelDelay(SiS_Pr, 1); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x00); + } + } + } + +#endif /* CONFIG_FB_SIS_315 */ + + } /* 310 series */ + + } /* LVDS */ + +} + +/*********************************************/ +/* SET PART 1 REGISTER GROUP */ +/*********************************************/ + +/* Set CRT2 OFFSET / PITCH */ +static void +SiS_SetCRT2Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RRTI) +{ + unsigned short offset; + unsigned char temp; + + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) return; + + offset = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,RRTI); + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(offset & 0xFF)); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,(offset >> 8)); + + temp = (unsigned char)(((offset >> 3) & 0xFF) + 1); + if(offset & 0x07) temp++; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,temp); +} + +/* Set CRT2 sync and PanelLink mode */ +static void +SiS_SetCRT2Sync(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short RefreshRateTableIndex) +{ + unsigned short tempah=0, tempbl, infoflag; + + tempbl = 0xC0; + + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + } + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { /* LVDS */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + tempah = 0; + } else if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDInfo & LCDSync)) { + tempah = SiS_Pr->SiS_LCDInfo; + } else tempah = infoflag >> 8; + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + tempah |= 0xf0; + } + if( (SiS_Pr->SiS_IF_DEF_FSTN) || + (SiS_Pr->SiS_IF_DEF_DSTN) || + (SiS_Pr->SiS_IF_DEF_TRUMPION) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + (SiS_Pr->SiS_CustomT == CUT_PANEL856) ) { + tempah |= 0x30; + } + if( (SiS_Pr->SiS_IF_DEF_FSTN) || + (SiS_Pr->SiS_IF_DEF_DSTN) ) { + tempah &= ~0xc0; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->ChipType >= SIS_315H) { + tempah >>= 3; + tempah &= 0x18; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xE7,tempah); + /* Don't care about 12/18/24 bit mode - TV is via VGA, not PL */ + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,0xe0); + } + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + } + + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->ChipType < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 /* ---- 300 series --- */ + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { /* 630 - 301B(-DH) */ + + tempah = infoflag >> 8; + tempbl = 0; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempah = SiS_Pr->SiS_LCDInfo; + tempbl = (tempah >> 6) & 0x03; + } + } + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + tempah |= 0xc0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } + + } else { /* 630 - 301 */ + + tempah = ((infoflag >> 8) & 0xc0) | 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + + } + +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 /* ------- 315 series ------ */ + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { /* 315 - LVDS */ + + tempbl = 0; + if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) && + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { + tempah = infoflag >> 8; + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempbl = ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6); + } + } else if((SiS_Pr->SiS_CustomT == CUT_CLEVO1400) && + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050)) { + tempah = infoflag >> 8; + tempbl = 0x03; + } else { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); + tempbl = (tempah >> 6) & 0x03; + tempbl |= 0x08; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempbl |= 0x04; + } + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) tempah |= 0xc0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } + } + + } else { /* 315 - TMDS */ + + tempah = tempbl = infoflag >> 8; + if(!SiS_Pr->UseCustomMode) { + tempbl = 0; + if((SiS_Pr->SiS_VBType & VB_SIS30xC) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + if(ModeNo <= 0x13) { + tempah = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); + } + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempah = SiS_Pr->SiS_LCDInfo; + tempbl = (tempah >> 6) & 0x03; + } + } + } + } + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBType & VB_NoLCD) { + /* Imitate BIOS bug */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempah |= 0xc0; + } + if((SiS_Pr->SiS_VBType & VB_SIS30xC) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempah >>= 3; + tempah &= 0x18; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xe7,tempah); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } + } + } + + } +#endif /* CONFIG_FB_SIS_315 */ + } + } +} + +/* Set CRT2 FIFO on 300/540/630/730 */ +#ifdef CONFIG_FB_SIS_300 +static void +SiS_SetCRT2FIFO_300(struct SiS_Private *SiS_Pr,unsigned short ModeNo) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp, index, modeidindex, refreshratetableindex; + unsigned short VCLK = 0, MCLK, colorth = 0, data2 = 0; + unsigned short tempbx, tempcl, CRT1ModeNo, CRT2ModeNo, SelectRate_backup; + unsigned int data, pci50, pciA0; + static const unsigned char colortharray[] = { + 1, 1, 2, 2, 3, 4 + }; + + SelectRate_backup = SiS_Pr->SiS_SelectCRT2Rate; + + if(!SiS_Pr->CRT1UsesCustomMode) { + + CRT1ModeNo = SiS_Pr->SiS_CRT1Mode; /* get CRT1 ModeNo */ + SiS_SearchModeID(SiS_Pr, &CRT1ModeNo, &modeidindex); + SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); + SiS_Pr->SiS_SelectCRT2Rate = 0; + refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT1ModeNo, modeidindex); + + if(CRT1ModeNo >= 0x13) { + /* Get VCLK */ + index = SiS_GetRefCRTVCLK(SiS_Pr, refreshratetableindex, SiS_Pr->SiS_UseWide); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; + + /* Get colordepth */ + colorth = SiS_GetColorDepth(SiS_Pr,CRT1ModeNo,modeidindex) >> 1; + if(!colorth) colorth++; + } + + } else { + + CRT1ModeNo = 0xfe; + + /* Get VCLK */ + VCLK = SiS_Pr->CSRClock_CRT1; + + /* Get color depth */ + colorth = colortharray[((SiS_Pr->CModeFlag_CRT1 & ModeTypeMask) - 2)]; + + } + + if(CRT1ModeNo >= 0x13) { + /* Get MCLK */ + if(SiS_Pr->ChipType == SIS_300) { + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A); + } else { + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A); + } + index &= 0x07; + MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; + + temp = ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) >> 6) & 0x03) << 1; + if(!temp) temp++; + temp <<= 2; + + data2 = temp - ((colorth * VCLK) / MCLK); + + temp = (28 * 16) % data2; + data2 = (28 * 16) / data2; + if(temp) data2++; + + if(SiS_Pr->ChipType == SIS_300) { + + SiS_GetFIFOThresholdIndex300(SiS_Pr, &tempbx, &tempcl); + data = SiS_GetFIFOThresholdB300(tempbx, tempcl); + + } else { + + pci50 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50); + pciA0 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xa0); + + if(SiS_Pr->ChipType == SIS_730) { + + index = (unsigned short)(((pciA0 >> 28) & 0x0f) * 3); + index += (unsigned short)(((pci50 >> 9)) & 0x03); + + /* BIOS BUG (2.04.5d, 2.04.6a use ah here, which is unset!) */ + index = 0; /* -- do it like the BIOS anyway... */ + + } else { + + pci50 >>= 24; + pciA0 >>= 24; + + index = (pci50 >> 1) & 0x07; + + if(pci50 & 0x01) index += 6; + if(!(pciA0 & 0x01)) index += 24; + + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x80) index += 12; + + } + + data = SiS_GetLatencyFactor630(SiS_Pr, index) + 15; + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x80)) data += 5; + + } + + data += data2; /* CRT1 Request Period */ + + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup; + + if(!SiS_Pr->UseCustomMode) { + + CRT2ModeNo = ModeNo; + SiS_SearchModeID(SiS_Pr, &CRT2ModeNo, &modeidindex); + + refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT2ModeNo, modeidindex); + + /* Get VCLK */ + index = SiS_GetVCLK2Ptr(SiS_Pr, CRT2ModeNo, modeidindex, refreshratetableindex); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; + + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x01) { + VCLK = ROMAddr[0x229] | (ROMAddr[0x22a] << 8); + } + } + } + + } else { + + /* Get VCLK */ + CRT2ModeNo = 0xfe; + VCLK = SiS_Pr->CSRClock; + + } + + /* Get colordepth */ + colorth = SiS_GetColorDepth(SiS_Pr,CRT2ModeNo,modeidindex) >> 1; + if(!colorth) colorth++; + + data = data * VCLK * colorth; + temp = data % (MCLK << 4); + data = data / (MCLK << 4); + if(temp) data++; + + if(data < 6) data = 6; + else if(data > 0x14) data = 0x14; + + if(SiS_Pr->ChipType == SIS_300) { + temp = 0x16; + if((data <= 0x0f) || (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) + temp = 0x13; + } else { + temp = 0x16; + if(( (SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730) ) && + (SiS_Pr->ChipRevision >= 0x30)) + temp = 0x1b; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0xe0,temp); + + if((SiS_Pr->ChipType == SIS_630) && + (SiS_Pr->ChipRevision >= 0x30)) { + if(data > 0x13) data = 0x13; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,0xe0,data); + + } else { /* If mode <= 0x13, we just restore everything */ + + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup; + + } +} +#endif + +/* Set CRT2 FIFO on 315/330 series */ +#ifdef CONFIG_FB_SIS_315 +static void +SiS_SetCRT2FIFO_310(struct SiS_Private *SiS_Pr) +{ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3B); + if( (SiS_Pr->ChipType == SIS_760) && + (SiS_Pr->SiS_SysFlags & SF_760LFB) && + (SiS_Pr->SiS_ModeType == Mode32Bpp) && + (SiS_Pr->SiS_VGAHDE >= 1280) && + (SiS_Pr->SiS_VGAVDE >= 1024) ) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2f,0x03); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3b); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4d,0xc0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2f,0x01); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4d,0xc0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,0x6e); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3f,0x04); + } + +} +#endif + +static unsigned short +SiS_GetVGAHT2(struct SiS_Private *SiS_Pr) +{ + unsigned int tempax,tempbx; + + tempbx = (SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) * SiS_Pr->SiS_RVBHCMAX; + tempax = (SiS_Pr->SiS_VT - SiS_Pr->SiS_VDE) * SiS_Pr->SiS_RVBHCFACT; + tempax = (tempax * SiS_Pr->SiS_HT) / tempbx; + return (unsigned short)tempax; +} + +/* Set Part 1 / SiS bridge slave mode */ +static void +SiS_SetGroup1_301(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short temp, modeflag, i, j, xres=0, VGAVDE; + static const unsigned short CRTranslation[] = { + /* CR0 CR1 CR2 CR3 CR4 CR5 CR6 CR7 */ + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + /* CR8 CR9 SR0A SR0B SR0C SR0D SR0E CR0F */ + 0x00, 0x0b, 0x17, 0x18, 0x19, 0x00, 0x1a, 0x00, + /* CR10 CR11 CR12 CR13 CR14 CR15 CR16 CR17 */ + 0x0c, 0x0d, 0x0e, 0x00, 0x0f, 0x10, 0x11, 0x00 + }; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + xres = SiS_Pr->CHDisplay; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes; + } + + /* The following is only done if bridge is in slave mode: */ + + if(SiS_Pr->ChipType >= SIS_315H) { + if(xres >= 1600) { /* BIOS: == 1600 */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x31,0x04); + } + } + + SiS_Pr->CHTotal = 8224; /* Max HT, 0x2020, results in 0x3ff in registers */ + + SiS_Pr->CHDisplay = SiS_Pr->SiS_VGAHDE; + if(modeflag & HalfDCLK) SiS_Pr->CHDisplay >>= 1; + + SiS_Pr->CHBlankStart = SiS_Pr->CHDisplay; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_Pr->CHBlankStart += 16; + } + + SiS_Pr->CHBlankEnd = 32; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(xres == 1600) SiS_Pr->CHBlankEnd += 80; + } + + temp = SiS_Pr->SiS_VGAHT - 96; + if(!(modeflag & HalfDCLK)) temp -= 32; + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x04); + temp |= ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x0b) & 0xc0) << 2); + temp -= 3; + temp <<= 3; + } else { + if(SiS_Pr->SiS_RVBHRS2) temp = SiS_Pr->SiS_RVBHRS2; + } + SiS_Pr->CHSyncStart = temp; + + SiS_Pr->CHSyncEnd = 0xffe8; /* results in 0x2000 in registers */ + + SiS_Pr->CVTotal = 2049; /* Max VT, 0x0801, results in 0x7ff in registers */ + + VGAVDE = SiS_Pr->SiS_VGAVDE; + if (VGAVDE == 357) VGAVDE = 350; + else if(VGAVDE == 360) VGAVDE = 350; + else if(VGAVDE == 375) VGAVDE = 350; + else if(VGAVDE == 405) VGAVDE = 400; + else if(VGAVDE == 420) VGAVDE = 400; + else if(VGAVDE == 525) VGAVDE = 480; + else if(VGAVDE == 1056) VGAVDE = 1024; + SiS_Pr->CVDisplay = VGAVDE; + + SiS_Pr->CVBlankStart = SiS_Pr->CVDisplay; + + SiS_Pr->CVBlankEnd = 1; + if(ModeNo == 0x3c) SiS_Pr->CVBlankEnd = 226; + + temp = (SiS_Pr->SiS_VGAVT - VGAVDE) >> 1; + SiS_Pr->CVSyncStart = VGAVDE + temp; + + temp >>= 3; + SiS_Pr->CVSyncEnd = SiS_Pr->CVSyncStart + temp; + + SiS_CalcCRRegisters(SiS_Pr, 0); + SiS_Pr->CCRT1CRTC[16] &= ~0xE0; + + for(i = 0; i <= 7; i++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,CRTranslation[i],SiS_Pr->CCRT1CRTC[i]); + } + for(i = 0x10, j = 8; i <= 0x12; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,CRTranslation[i],SiS_Pr->CCRT1CRTC[j]); + } + for(i = 0x15, j = 11; i <= 0x16; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,CRTranslation[i],SiS_Pr->CCRT1CRTC[j]); + } + for(i = 0x0a, j = 13; i <= 0x0c; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,CRTranslation[i],SiS_Pr->CCRT1CRTC[j]); + } + + temp = SiS_Pr->CCRT1CRTC[16] & 0xE0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,CRTranslation[0x0E],0x1F,temp); + + temp = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5; + if(modeflag & DoubleScanMode) temp |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,CRTranslation[0x09],0x5F,temp); + + temp = 0; + temp |= (SiS_GetReg(SiS_Pr->SiS_P3c4,0x01) & 0x01); + if(modeflag & HalfDCLK) temp |= 0x08; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp); /* SR01: HalfDCLK[3], 8/9 div dotclock[0] */ + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,0x00); /* CR14: (text mode: underline location) */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,0x00); /* CR17: n/a */ + + temp = 0; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + temp = (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) << 7; + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* SR0E, dither[7] */ + + temp = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); /* ? */ +} + +/* Setup panel link + * This is used for LVDS, LCDA and Chrontel TV output + * 300/LVDS+TV, 300/301B-DH, 315/LVDS+TV, 315/LCDA + */ +static void +SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short modeflag, resinfo = 0; + unsigned short push2, tempax, tempbx, tempcx, temp; + unsigned int tempeax = 0, tempebx, tempecx, tempvcfact = 0; + bool islvds = false, issis = false, chkdclkfirst = false; +#ifdef CONFIG_FB_SIS_300 + unsigned short crt2crtc = 0; +#endif +#ifdef CONFIG_FB_SIS_315 + unsigned short pushcx; +#endif + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; +#ifdef CONFIG_FB_SIS_300 + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; +#endif + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; +#ifdef CONFIG_FB_SIS_300 + crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; +#endif + } + + /* is lvds if really LVDS, or 301B-DH with external LVDS transmitter */ + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) { + islvds = true; + } + + /* is really sis if sis bridge, but not 301B-DH */ + if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + issis = true; + } + + if((SiS_Pr->ChipType >= SIS_315H) && (islvds) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA))) { + if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { + chkdclkfirst = true; + } + } + +#ifdef CONFIG_FB_SIS_315 + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(IS_SIS330) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); + } else if(IS_SIS740) { + if(islvds) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x03); + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); + } + } else { + if(islvds) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00); + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f); + if(SiS_Pr->SiS_VBType & VB_SIS30xC) { + if((SiS_Pr->SiS_LCDResInfo == Panel_1024x768) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x20); + } + } + } + } + } +#endif + + /* Horizontal */ + + tempax = SiS_Pr->SiS_LCDHDES; + if(islvds) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!SiS_Pr->SiS_IF_DEF_FSTN && !SiS_Pr->SiS_IF_DEF_DSTN) { + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) && + (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) { + tempax -= 8; + } + } + } + } + + temp = (tempax & 0x0007); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* BPLHDESKEW[2:0] */ + temp = (tempax >> 3) & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp); /* BPLHDESKEW[10:3] */ + + tempbx = SiS_Pr->SiS_HDE; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + tempbx = SiS_Pr->PanelXRes; + } + if((SiS_Pr->SiS_LCDResInfo == Panel_320x240_1) || + (SiS_Pr->SiS_LCDResInfo == Panel_320x240_2) || + (SiS_Pr->SiS_LCDResInfo == Panel_320x240_3)) { + tempbx >>= 1; + } + } + + tempax += tempbx; + if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT; + + temp = tempax; + if(temp & 0x07) temp += 8; + temp >>= 3; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp); /* BPLHDEE */ + + tempcx = (SiS_Pr->SiS_HT - tempbx) >> 2; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(SiS_Pr->PanelHRS != 999) tempcx = SiS_Pr->PanelHRS; + } + } + + tempcx += tempax; + if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT; + + temp = (tempcx >> 3) & 0x00FF; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + switch(ModeNo) { + case 0x04: + case 0x05: + case 0x0d: temp = 0x56; break; + case 0x10: temp = 0x60; break; + case 0x13: temp = 0x5f; break; + case 0x40: + case 0x41: + case 0x4f: + case 0x43: + case 0x44: + case 0x62: + case 0x56: + case 0x53: + case 0x5d: + case 0x5e: temp = 0x54; break; + } + } + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp); /* BPLHRS */ + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + temp += 2; + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + temp += 8; + if(SiS_Pr->PanelHRE != 999) { + temp = tempcx + SiS_Pr->PanelHRE; + if(temp >= SiS_Pr->SiS_HT) temp -= SiS_Pr->SiS_HT; + temp >>= 3; + } + } + } else { + temp += 10; + } + + temp &= 0x1F; + temp |= ((tempcx & 0x07) << 5); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp); /* BPLHRE */ + + /* Vertical */ + + tempax = SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + tempax = SiS_Pr->PanelYRes; + } + } + + tempbx = SiS_Pr->SiS_LCDVDES + tempax; + if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; + + push2 = tempbx; + + tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->PanelYRes; + } + } + } + if(islvds) tempcx >>= 1; + else tempcx >>= 2; + + if( (SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) && + (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) && + (SiS_Pr->PanelVRS != 999) ) { + tempcx = SiS_Pr->PanelVRS; + tempbx += tempcx; + if(issis) tempbx++; + } else { + tempbx += tempcx; + if(SiS_Pr->ChipType < SIS_315H) tempbx++; + else if(issis) tempbx++; + } + + if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; + + temp = tempbx & 0x00FF; + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(ModeNo == 0x10) temp = 0xa9; + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp); /* BPLVRS */ + + tempcx >>= 3; + tempcx++; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(SiS_Pr->PanelVRE != 999) tempcx = SiS_Pr->PanelVRE; + } + } + + tempcx += tempbx; + temp = tempcx & 0x000F; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp); /* BPLVRE */ + + temp = ((tempbx >> 8) & 0x07) << 3; + if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) { + if(SiS_Pr->SiS_HDE != 640) { + if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; + } + } else if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; + if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) temp |= 0x40; + tempbx = 0x87; + if((SiS_Pr->ChipType >= SIS_315H) || + (SiS_Pr->ChipRevision >= 0x30)) { + tempbx = 0x07; + if((SiS_Pr->SiS_IF_DEF_CH70xx == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x03) temp |= 0x80; + } + /* Chrontel 701x operates in 24bit mode (8-8-8, 2x12bit multiplexed) via VGA2 */ + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x10) temp |= 0x80; + } else { + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80; + } + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,tempbx,temp); + + tempbx = push2; /* BPLVDEE */ + + tempcx = SiS_Pr->SiS_LCDVDES; /* BPLVDES */ + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: + tempbx = SiS_Pr->SiS_VGAVDE - 1; + tempcx = SiS_Pr->SiS_VGAVDE; + break; + case Panel_800x600: + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_800x600) tempcx++; + } + break; + case Panel_1024x600: + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_1024x600) tempcx++; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(resinfo == SIS_RI_800x600) tempcx++; + } + } + break; + case Panel_1024x768: + if(SiS_Pr->ChipType < SIS_315H) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_1024x768) tempcx++; + } + } + break; + } + } + + temp = ((tempbx >> 8) & 0x07) << 3; + temp |= ((tempcx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,tempbx); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,tempcx); + + /* Vertical scaling */ + + if(SiS_Pr->ChipType < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 /* 300 series */ + tempeax = SiS_Pr->SiS_VGAVDE << 6; + temp = (tempeax % (unsigned int)SiS_Pr->SiS_VDE); + tempeax = tempeax / (unsigned int)SiS_Pr->SiS_VDE; + if(temp) tempeax++; + + if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) tempeax = 0x3F; + + temp = (unsigned short)(tempeax & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp); /* BPLVCFACT */ + tempvcfact = temp; +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 /* 315 series */ + tempeax = SiS_Pr->SiS_VGAVDE << 18; + tempebx = SiS_Pr->SiS_VDE; + temp = (tempeax % tempebx); + tempeax = tempeax / tempebx; + if(temp) tempeax++; + tempvcfact = tempeax; + + temp = (unsigned short)(tempeax & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp); + temp = (unsigned short)((tempeax & 0x00FF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp); + temp = (unsigned short)((tempeax & 0x00030000) >> 16); + if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp); + + if(SiS_Pr->SiS_VBType & VB_SISPART4SCALER) { + temp = (unsigned short)(tempeax & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3c,temp); + temp = (unsigned short)((tempeax & 0x00FF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3b,temp); + temp = (unsigned short)(((tempeax & 0x00030000) >> 16) << 6); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0x3f,temp); + temp = 0; + if(SiS_Pr->SiS_VDE != SiS_Pr->SiS_VGAVDE) temp |= 0x08; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x30,0xf3,temp); + } +#endif + + } + + /* Horizontal scaling */ + + tempeax = SiS_Pr->SiS_VGAHDE; /* 1f = ( (VGAHDE * 65536) / ( (VGAHDE * 65536) / HDE ) ) - 1*/ + if(chkdclkfirst) { + if(modeflag & HalfDCLK) tempeax >>= 1; + } + tempebx = tempeax << 16; + if(SiS_Pr->SiS_HDE == tempeax) { + tempecx = 0xFFFF; + } else { + tempecx = tempebx / SiS_Pr->SiS_HDE; + if(SiS_Pr->ChipType >= SIS_315H) { + if(tempebx % SiS_Pr->SiS_HDE) tempecx++; + } + } + + if(SiS_Pr->ChipType >= SIS_315H) { + tempeax = (tempebx / tempecx) - 1; + } else { + tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1; + } + tempecx = (tempecx << 16) | (tempeax & 0xFFFF); + temp = (unsigned short)(tempecx & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp); + + if(SiS_Pr->ChipType >= SIS_315H) { + tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact; + tempbx = (unsigned short)(tempeax & 0xFFFF); + } else { + tempeax = SiS_Pr->SiS_VGAVDE << 6; + tempbx = tempvcfact & 0x3f; + if(tempbx == 0) tempbx = 64; + tempeax /= tempbx; + tempbx = (unsigned short)(tempeax & 0xFFFF); + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tempbx--; + if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) { + if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) tempbx = 1; + else if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) tempbx = 1; + } + + temp = ((tempbx >> 8) & 0x07) << 3; + temp = temp | ((tempecx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,tempbx); + + tempecx >>= 16; /* BPLHCFACT */ + if(!chkdclkfirst) { + if(modeflag & HalfDCLK) tempecx >>= 1; + } + temp = (unsigned short)((tempecx & 0xFF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp); + temp = (unsigned short)(tempecx & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp); + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SISLVDS)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x20); + } + } else { + if(islvds) { + if(SiS_Pr->ChipType == SIS_740) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03); + } else { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x23); + } + } + } + } +#endif + +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned char *trumpdata; + int i, j = crt2crtc; + unsigned char TrumpMode13[4] = { 0x01, 0x10, 0x2c, 0x00 }; + unsigned char TrumpMode10_1[4] = { 0x01, 0x10, 0x27, 0x00 }; + unsigned char TrumpMode10_2[4] = { 0x01, 0x16, 0x10, 0x00 }; + + if(SiS_Pr->SiS_UseROM) { + trumpdata = &ROMAddr[0x8001 + (j * 80)]; + } else { + if(SiS_Pr->SiS_LCDTypeInfo == 0x0e) j += 7; + trumpdata = &SiS300_TrumpionData[j][0]; + } + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xbf); + for(i=0; i<5; i++) { + SiS_SetTrumpionBlock(SiS_Pr, trumpdata); + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(ModeNo == 0x13) { + for(i=0; i<4; i++) { + SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode13[0]); + } + } else if(ModeNo == 0x10) { + for(i=0; i<4; i++) { + SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_1[0]); + SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_2[0]); + } + } + } + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x25,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x26,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x27,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x28,0x87); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x29,0x5A); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2A,0x4B); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x07,0x03); + tempax = SiS_Pr->SiS_HDE; /* Blps = lcdhdee(lcdhdes+HDE) + 64 */ + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempax >>= 1; + tempax += 64; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,tempax & 0xff); + temp = (tempax >> 8) << 3; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,~0x078,temp); + tempax += 32; /* Blpe = lBlps+32 */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x39,tempax & 0xff); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3A,0x00); /* Bflml = 0 */ + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x3C,~0x007); + + tempax = SiS_Pr->SiS_VDE; + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempax >>= 1; + tempax >>= 1; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3B,tempax & 0xff); + temp = (tempax >> 8) << 3; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp); + + tempeax = SiS_Pr->SiS_HDE; + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempeax >>= 1; + tempeax <<= 2; /* BDxFIFOSTOP = (HDE*4)/128 */ + temp = tempeax & 0x7f; + tempeax >>= 7; + if(temp) tempeax++; + temp = tempeax & 0x3f; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x45,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3F,0x00); /* BDxWadrst0 */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3E,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3D,0x10); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x3C,~0x040); + + tempax = SiS_Pr->SiS_HDE; + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempax >>= 1; + tempax >>= 4; /* BDxWadroff = HDE*4/8/8 */ + pushcx = tempax; + temp = tempax & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x43,temp); + temp = ((tempax & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port, 0x44, 0x07, temp); + + tempax = SiS_Pr->SiS_VDE; /* BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */ + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempax >>= 1; + tempeax = tempax * pushcx; + temp = tempeax & 0xFF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x42,temp); + temp = (tempeax & 0xFF00) >> 8; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x41,temp); + temp = ((tempeax & 0xFF0000) >> 16) | 0x10; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x40,temp); + temp = ((tempeax & 0x01000000) >> 24) << 7; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port, 0x3C, 0x7F, temp); + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2F,0x03); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0x50); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x04,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2F,0x01); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0x38); + + if(SiS_Pr->SiS_IF_DEF_FSTN) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2b,0x02); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2c,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,0x0c); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,0x80); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x39,0xA0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3a,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3b,0xf0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3c,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3d,0x10); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3e,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3f,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x40,0x10); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x41,0x25); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x42,0x80); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x43,0x14); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x44,0x03); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x45,0x0a); + } + } +#endif /* CONFIG_FB_SIS_315 */ +} + +/* Set Part 1 */ +static void +SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; +#endif + unsigned short temp=0, tempax=0, tempbx=0, tempcx=0, bridgeadd=0; + unsigned short pushbx=0, CRT1Index=0, modeflag, resinfo=0; +#ifdef CONFIG_FB_SIS_315 + unsigned short tempbl=0; +#endif + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + return; + } + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + CRT1Index = SiS_GetRefCRT1CRTC(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWideCRT2); + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + SiS_SetCRT2Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + + if( ! ((SiS_Pr->ChipType >= SIS_315H) && + (SiS_Pr->SiS_IF_DEF_LVDS == 1) && + (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) { + + if(SiS_Pr->ChipType < SIS_315H ) { +#ifdef CONFIG_FB_SIS_300 + SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo); +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + SiS_SetCRT2FIFO_310(SiS_Pr); +#endif + } + + /* 1. Horizontal setup */ + + if(SiS_Pr->ChipType < SIS_315H ) { + +#ifdef CONFIG_FB_SIS_300 /* ------------- 300 series --------------*/ + + temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */ + + temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp); /* CRT2 Horizontal Total Overflow [7:4] */ + + temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* CRT2 Horizontal Display Enable End */ + + pushbx = SiS_Pr->SiS_VGAHDE + 12; /* bx BTVGA2HRS 0x0B,0x0C */ + tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2; + tempbx = pushbx + tempcx; + tempcx <<= 1; + tempcx += tempbx; + + bridgeadd = 12; + +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 /* ------------------- 315/330 series --------------- */ + + tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HT 0x08,0x09 */ + if(modeflag & HalfDCLK) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + tempcx >>= 1; + } else { + tempax = SiS_Pr->SiS_VGAHDE >> 1; + tempcx = SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE + tempax; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempcx = SiS_Pr->SiS_HT - tempax; + } + } + } + tempcx--; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,tempcx); /* CRT2 Horizontal Total */ + temp = (tempcx >> 4) & 0xF0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp); /* CRT2 Horizontal Total Overflow [7:4] */ + + tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HDEE 0x0A,0x0C */ + tempbx = SiS_Pr->SiS_VGAHDE; + tempcx -= tempbx; + tempcx >>= 2; + if(modeflag & HalfDCLK) { + tempbx >>= 1; + tempcx >>= 1; + } + tempbx += 16; + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,tempbx); /* CRT2 Horizontal Display Enable End */ + + pushbx = tempbx; + tempcx >>= 1; + tempbx += tempcx; + tempcx += tempbx; + + bridgeadd = 16; + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->ChipType >= SIS_661) { + if((SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { + if(resinfo == SIS_RI_1280x1024) { + tempcx = (tempcx & 0xff00) | 0x30; + } else if(resinfo == SIS_RI_1600x1200) { + tempcx = (tempcx & 0xff00) | 0xff; + } + } + } + } + +#endif /* CONFIG_FB_SIS_315 */ + + } /* 315/330 series */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CHSyncStart + bridgeadd; + tempcx = SiS_Pr->CHSyncEnd + bridgeadd; + tempax = SiS_Pr->SiS_VGAHT; + if(modeflag & HalfDCLK) tempax >>= 1; + tempax--; + if(tempcx > tempax) tempcx = tempax; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + unsigned char cr4, cr14, cr5, cr15; + if(SiS_Pr->UseCustomMode) { + cr4 = SiS_Pr->CCRT1CRTC[4]; + cr14 = SiS_Pr->CCRT1CRTC[14]; + cr5 = SiS_Pr->CCRT1CRTC[5]; + cr15 = SiS_Pr->CCRT1CRTC[15]; + } else { + cr4 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4]; + cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; + cr5 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5]; + cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15]; + } + tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 3) << 3; /* (VGAHRS-3)*8 */ + tempcx = (((cr5 & 0x1f) | ((cr15 & 0x04) << (5-2))) - 3) << 3; /* (VGAHRE-3)*8 */ + tempcx &= 0x00FF; + tempcx |= (tempbx & 0xFF00); + tempbx += bridgeadd; + tempcx += bridgeadd; + tempax = SiS_Pr->SiS_VGAHT; + if(modeflag & HalfDCLK) tempax >>= 1; + tempax--; + if(tempcx > tempax) tempcx = tempax; + } + + if(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSet525p1024)) { + tempbx = 1040; + tempcx = 1044; /* HWCursor bug! */ + } + + } + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,tempbx); /* CRT2 Horizontal Retrace Start */ + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,tempcx); /* CRT2 Horizontal Retrace End */ + + temp = ((tempbx >> 8) & 0x0F) | ((pushbx >> 4) & 0xF0); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp); /* Overflow */ + + /* 2. Vertical setup */ + + tempcx = SiS_Pr->SiS_VGAVT - 1; + temp = tempcx & 0x00FF; + + if(SiS_Pr->ChipType < SIS_661) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) { + temp--; + } + } + } else { + temp--; + } + } else if(SiS_Pr->ChipType >= SIS_315H) { + temp--; + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp); /* CRT2 Vertical Total */ + + tempbx = SiS_Pr->SiS_VGAVDE - 1; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,tempbx); /* CRT2 Vertical Display Enable End */ + + temp = ((tempbx >> 5) & 0x38) | ((tempcx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,temp); /* Overflow */ + + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) { + tempbx++; + tempax = tempbx; + tempcx++; + tempcx -= tempax; + tempcx >>= 2; + tempbx += tempcx; + if(tempcx < 4) tempcx = 4; + tempcx >>= 2; + tempcx += tempbx; + tempcx++; + } else { + tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1; /* BTVGA2VRS 0x10,0x11 */ + tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1; /* BTVGA2VRE 0x11 */ + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CVSyncStart; + tempcx = SiS_Pr->CVSyncEnd; + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + unsigned char cr8, cr7, cr13; + if(SiS_Pr->UseCustomMode) { + cr8 = SiS_Pr->CCRT1CRTC[8]; + cr7 = SiS_Pr->CCRT1CRTC[7]; + cr13 = SiS_Pr->CCRT1CRTC[13]; + tempcx = SiS_Pr->CCRT1CRTC[9]; + } else { + cr8 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8]; + cr7 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; + cr13 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; + tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9]; + } + tempbx = cr8; + if(cr7 & 0x04) tempbx |= 0x0100; + if(cr7 & 0x80) tempbx |= 0x0200; + if(cr13 & 0x08) tempbx |= 0x0400; + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,tempbx); /* CRT2 Vertical Retrace Start */ + + temp = ((tempbx >> 4) & 0x70) | (tempcx & 0x0F); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,temp); /* CRT2 Vert. Retrace End; Overflow */ + + /* 3. Panel delay compensation */ + + if(SiS_Pr->ChipType < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 /* ---------- 300 series -------------- */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = 0x20; + if(SiS_Pr->ChipType == SIS_300) { + temp = 0x10; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) temp = 0x2c; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20; + } + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20; + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960) temp = 0x24; + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) temp = 0x2c; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x08; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) temp = 0x2c; + else temp = 0x20; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x80) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) + temp = ROMAddr[0x221]; + else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) + temp = ROMAddr[0x222]; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) + temp = ROMAddr[0x223]; + else + temp = ROMAddr[0x224]; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC; + } + + } else { + temp = 0x20; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) temp = 0x04; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x80) { + temp = ROMAddr[0x220]; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC; + } + } + + temp &= 0x3c; + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */ + +#endif /* CONFIG_FB_SIS_300 */ + + } else { + +#ifdef CONFIG_FB_SIS_315 /* --------------- 315/330 series ---------------*/ + + if(SiS_Pr->ChipType < SIS_661) { + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + + if(SiS_Pr->ChipType == SIS_740) temp = 0x03; + else temp = 0x00; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a; + tempbl = 0xF0; + if(SiS_Pr->ChipType == SIS_650) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F; + } + } + + if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) { + temp = 0x08; + tempbl = 0; + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0; + } + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,tempbl,temp); /* Panel Link Delay Compensation */ + } + + } /* < 661 */ + + tempax = 0; + if(modeflag & DoubleScanMode) tempax |= 0x80; + if(modeflag & HalfDCLK) tempax |= 0x40; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax); + +#endif /* CONFIG_FB_SIS_315 */ + + } + + } /* Slavemode */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + /* For 301BDH with LCD, we set up the Panel Link */ + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SiS_SetGroup1_301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + } else { + if(SiS_Pr->ChipType < SIS_315H) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } else { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex,RefreshRateTableIndex); + } + } else { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex,RefreshRateTableIndex); + } + } + } +} + +/*********************************************/ +/* SET PART 2 REGISTER GROUP */ +/*********************************************/ + +#ifdef CONFIG_FB_SIS_315 +static unsigned char * +SiS_GetGroup2CLVXPtr(struct SiS_Private *SiS_Pr, int tabletype) +{ + const unsigned char *tableptr = NULL; + unsigned short a, b, p = 0; + + a = SiS_Pr->SiS_VGAHDE; + b = SiS_Pr->SiS_HDE; + if(tabletype) { + a = SiS_Pr->SiS_VGAVDE; + b = SiS_Pr->SiS_VDE; + } + + if(a < b) { + tableptr = SiS_Part2CLVX_1; + } else if(a == b) { + tableptr = SiS_Part2CLVX_2; + } else { + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tableptr = SiS_Part2CLVX_4; + } else { + tableptr = SiS_Part2CLVX_3; + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) tableptr = SiS_Part2CLVX_3; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tableptr = SiS_Part2CLVX_3; + else tableptr = SiS_Part2CLVX_5; + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + tableptr = SiS_Part2CLVX_6; + } + do { + if((tableptr[p] | tableptr[p+1] << 8) == a) break; + p += 0x42; + } while((tableptr[p] | tableptr[p+1] << 8) != 0xffff); + if((tableptr[p] | tableptr[p+1] << 8) == 0xffff) p -= 0x42; + } + p += 2; + return ((unsigned char *)&tableptr[p]); +} + +static void +SiS_SetGroup2_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned char *tableptr; + unsigned char temp; + int i, j; + + if(!(SiS_Pr->SiS_VBType & VB_SISTAP4SCALER)) return; + + tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 0); + for(i = 0x80, j = 0; i <= 0xbf; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port, i, tableptr[j]); + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 1); + for(i = 0xc0, j = 0; i <= 0xff; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port, i, tableptr[j]); + } + } + temp = 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp |= 0x04; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xeb,temp); +} + +static bool +SiS_GetCRT2Part2Ptr(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex,unsigned short *CRT2Index, + unsigned short *ResIndex) +{ + + if(SiS_Pr->ChipType < SIS_315H) return false; + + if(ModeNo <= 0x13) + (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + else + (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + + (*ResIndex) &= 0x3f; + (*CRT2Index) = 0; + + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + (*CRT2Index) = 200; + } + } + + if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) (*CRT2Index) = 206; + } + } + return (((*CRT2Index) != 0)); +} +#endif + +#ifdef CONFIG_FB_SIS_300 +static void +SiS_Group2LCDSpecial(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short crt2crtc) +{ + unsigned short tempcx; + static const unsigned char atable[] = { + 0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02, + 0xab,0x87,0xab,0x9e,0xe7,0x02,0x02 + }; + + if(!SiS_Pr->UseCustomMode) { + if( ( ( (SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730) ) && + (SiS_Pr->ChipRevision > 2) ) && + (SiS_Pr->SiS_LCDResInfo == Panel_1024x768) && + (!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) && + (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) { + if(ModeNo == 0x13) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xB9); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0xCC); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xA6); + } else if((crt2crtc & 0x3F) == 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x2B); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x13); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xE5); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0x08); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xE2); + } + } + + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) { + crt2crtc &= 0x1f; + tempcx = 0; + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + tempcx += 7; + } + } + tempcx += crt2crtc; + if(crt2crtc >= 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xff); + } + + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(crt2crtc == 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x28); + } + } + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x18); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]); + } + } + } +} + +/* For ECS A907. Highly preliminary. */ +static void +SiS_Set300Part2Regs(struct SiS_Private *SiS_Pr, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, + unsigned short ModeNo) +{ + const struct SiS_Part2PortTbl *CRT2Part2Ptr = NULL; + unsigned short crt2crtc, resindex; + int i, j; + + if(SiS_Pr->ChipType != SIS_300) return; + if(!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) return; + if(SiS_Pr->UseCustomMode) return; + + if(ModeNo <= 0x13) { + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + resindex = crt2crtc & 0x3F; + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1; + else CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_2; + + /* The BIOS code (1.16.51,56) is obviously a fragment! */ + if(ModeNo > 0x13) { + CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1; + resindex = 4; + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x02,0x80,(CRT2Part2Ptr+resindex)->CR[1]); + for(i = 2, j = 0x04; j <= 0x06; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + for(j = 0x1c; j <= 0x1d; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + for(j = 0x1f; j <= 0x21; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]); +} +#endif + +static void +SiS_SetTVSpecial(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + if(!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) return; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision)) return; + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) return; + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + const unsigned char specialtv[] = { + 0xa7,0x07,0xf2,0x6e,0x17,0x8b,0x73,0x53, + 0x13,0x40,0x34,0xf4,0x63,0xbb,0xcc,0x7a, + 0x58,0xe4,0x73,0xda,0x13 + }; + int i, j; + for(i = 0x1c, j = 0; i <= 0x30; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,specialtv[j]); + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,0x72); + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750)) { + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1b); + } else { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14); /* 15 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1a); /* 1b */ + } + } + } + } else { + if((ModeNo == 0x38) || (ModeNo == 0x4a) || (ModeNo == 0x64) || + (ModeNo == 0x52) || (ModeNo == 0x58) || (ModeNo == 0x5c)) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b); /* 21 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54); /* 5a */ + } else { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1a); /* 21 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x53); /* 5a */ + } + } +} + +static void +SiS_SetGroup2_Tail(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + unsigned short temp; + + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if(SiS_Pr->SiS_VGAVDE == 525) { + temp = 0xc3; + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + temp++; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) temp += 2; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3); + } else if(SiS_Pr->SiS_VGAVDE == 420) { + temp = 0x4d; + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + temp++; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) temp++; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) { + if(SiS_Pr->SiS_VBType & VB_SIS30xB) { + SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x1a,0x03); + /* Not always for LV, see SetGrp2 */ + } + temp = 1; + if(ModeNo <= 0x13) temp = 3; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0b,temp); + } +#if 0 + /* 651+301C, for 1280x768 - do I really need that? */ + if((SiS_Pr->SiS_PanelXRes == 1280) && (SiS_Pr->SiS_PanelYRes == 768)) { + if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) { + if(((SiS_Pr->SiS_HDE == 640) && (SiS_Pr->SiS_VDE == 480)) || + ((SiS_Pr->SiS_HDE == 320) && (SiS_Pr->SiS_VDE == 240))) { + SiS_SetReg(SiS_Part2Port,0x01,0x2b); + SiS_SetReg(SiS_Part2Port,0x02,0x13); + SiS_SetReg(SiS_Part2Port,0x04,0xe5); + SiS_SetReg(SiS_Part2Port,0x05,0x08); + SiS_SetReg(SiS_Part2Port,0x06,0xe2); + SiS_SetReg(SiS_Part2Port,0x1c,0x21); + SiS_SetReg(SiS_Part2Port,0x1d,0x45); + SiS_SetReg(SiS_Part2Port,0x1f,0x0b); + SiS_SetReg(SiS_Part2Port,0x20,0x00); + SiS_SetReg(SiS_Part2Port,0x21,0xa9); + SiS_SetReg(SiS_Part2Port,0x23,0x0b); + SiS_SetReg(SiS_Part2Port,0x25,0x04); + } + } + } +#endif + } +} + +static void +SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short i, j, tempax, tempbx, tempcx, tempch, tempcl, temp; + unsigned short push2, modeflag, crt2crtc, bridgeoffset; + unsigned int longtemp, PhaseIndex; + bool newtvphase; + const unsigned char *TimingPoint; +#ifdef CONFIG_FB_SIS_315 + unsigned short resindex, CRT2Index; + const struct SiS_Part2PortTbl *CRT2Part2Ptr = NULL; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; +#endif + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + crt2crtc = 0; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + temp = 0; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToAVIDEO)) temp |= 0x08; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO)) temp |= 0x04; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) temp |= 0x02; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) temp |= 0x01; + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) temp |= 0x10; + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,temp); + + PhaseIndex = 0x01; /* SiS_PALPhase */ + TimingPoint = SiS_Pr->SiS_PALTiming; + + newtvphase = false; + if( (SiS_Pr->SiS_VBType & VB_SIS30xBLV) && + ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { + newtvphase = true; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + + TimingPoint = SiS_Pr->SiS_HiTVExtTiming; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + TimingPoint = SiS_Pr->SiS_HiTVSt2Timing; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + TimingPoint = SiS_Pr->SiS_HiTVSt1Timing; + } + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + + i = 0; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) i = 2; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) i = 1; + + TimingPoint = &SiS_YPbPrTable[i][0]; + + PhaseIndex = 0x00; /* SiS_NTSCPhase */ + + } else if(SiS_Pr->SiS_TVMode & TVSetPAL) { + + if(newtvphase) PhaseIndex = 0x09; /* SiS_PALPhase2 */ + + } else { + + TimingPoint = SiS_Pr->SiS_NTSCTiming; + PhaseIndex = (SiS_Pr->SiS_TVMode & TVSetNTSCJ) ? 0x01 : 0x00; /* SiS_PALPhase : SiS_NTSCPhase */ + if(newtvphase) PhaseIndex += 8; /* SiS_PALPhase2 : SiS_NTSCPhase2 */ + + } + + if(SiS_Pr->SiS_TVMode & (TVSetPALM | TVSetPALN)) { + PhaseIndex = (SiS_Pr->SiS_TVMode & TVSetPALM) ? 0x02 : 0x03; /* SiS_PALMPhase : SiS_PALNPhase */ + if(newtvphase) PhaseIndex += 8; /* SiS_PALMPhase2 : SiS_PALNPhase2 */ + } + + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + PhaseIndex = 0x05; /* SiS_SpecialPhaseM */ + } else if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { + PhaseIndex = 0x11; /* SiS_SpecialPhaseJ */ + } else { + PhaseIndex = 0x10; /* SiS_SpecialPhase */ + } + } + + for(i = 0x31, j = 0; i <= 0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS_TVPhase[(PhaseIndex * 4) + j]); + } + + for(i = 0x01, j = 0; i <= 0x2D; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); + } + for(i = 0x39; i <= 0x45; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_ModeType != ModeText) { + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F); + } + } + + SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x0A,SiS_Pr->SiS_NewFlickerMode); + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x35,SiS_Pr->SiS_RY1COE); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x36,SiS_Pr->SiS_RY2COE); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x37,SiS_Pr->SiS_RY3COE); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x38,SiS_Pr->SiS_RY4COE); + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempax = 950; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempax = 680; + else if(SiS_Pr->SiS_TVMode & TVSetPAL) tempax = 520; + else tempax = 440; /* NTSC, YPbPr 525 */ + + if( ((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) && (SiS_Pr->SiS_VDE <= tempax)) || + ( (SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) && + ((SiS_Pr->SiS_VGAHDE == 1024) || (SiS_Pr->SiS_VDE <= tempax)) ) ) { + + tempax -= SiS_Pr->SiS_VDE; + tempax >>= 1; + if(!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p))) { + tempax >>= 1; + } + tempax &= 0x00ff; + + temp = tempax + (unsigned short)TimingPoint[0]; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp); + + temp = tempax + (unsigned short)TimingPoint[1]; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp); + + if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) && (SiS_Pr->SiS_VGAHDE >= 1024)) { + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54); + } else { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x17); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1d); + } + } + + } + + tempcx = SiS_Pr->SiS_HT; + if(SiS_IsDualLink(SiS_Pr)) tempcx >>= 1; + tempcx--; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) tempcx--; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1B,tempcx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,((tempcx >> 8) & 0x0f)); + + tempcx = SiS_Pr->SiS_HT >> 1; + if(SiS_IsDualLink(SiS_Pr)) tempcx >>= 1; + tempcx += 7; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,((tempcx << 4) & 0xf0)); + + tempbx = TimingPoint[j] | (TimingPoint[j+1] << 8); + tempbx += tempcx; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x24,tempbx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0F,((tempbx >> 4) & 0xf0)); + + tempbx += 8; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + tempbx -= 4; + tempcx = tempbx; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x29,0x0F,((tempbx << 4) & 0xf0)); + + j += 2; + tempcx += (TimingPoint[j] | (TimingPoint[j+1] << 8)); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x27,tempcx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x28,0x0F,((tempcx >> 4) & 0xf0)); + + tempcx += 8; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,((tempcx << 4) & 0xf0)); + + tempcx = SiS_Pr->SiS_HT >> 1; + if(SiS_IsDualLink(SiS_Pr)) tempcx >>= 1; + j += 2; + tempcx -= (TimingPoint[j] | ((TimingPoint[j+1]) << 8)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,((tempcx << 4) & 0xf0)); + + tempcx -= 11; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + tempcx = SiS_GetVGAHT2(SiS_Pr) - 1; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2E,tempcx); + + tempbx = SiS_Pr->SiS_VDE; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_VGAVDE == 360) tempbx = 746; + if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 746; + if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 853; + } else if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && + (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p|TVSetYPbPr750p))) ) { + tempbx >>= 1; + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + if((ModeNo <= 0x13) && (crt2crtc == 1)) tempbx++; + } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + if(crt2crtc == 4) tempbx++; + } + } + } + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if((ModeNo == 0x2f) || (ModeNo == 0x5d) || (ModeNo == 0x5e)) tempbx++; + } + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + if(ModeNo == 0x03) tempbx++; /* From 1.10.7w - doesn't make sense */ + } + } + } + tempbx -= 2; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2F,tempbx); + + temp = (tempcx >> 8) & 0x0F; + temp |= ((tempbx >> 2) & 0xC0); + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) { + temp |= 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToAVIDEO) temp |= 0x20; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,temp); + + if(SiS_Pr->SiS_VBType & VB_SISPART4OVERFLOW) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xdf,((tempbx & 0x0400) >> 5)); + } + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + tempbx = SiS_Pr->SiS_VDE; + if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && + (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p))) ) { + tempbx >>= 1; + } + tempbx -= 3; + temp = ((tempbx >> 3) & 0x60) | 0x18; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x46,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x47,tempbx); + + if(SiS_Pr->SiS_VBType & VB_SISPART4OVERFLOW) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xbf,((tempbx & 0x0400) >> 4)); + } + } + + tempbx = 0; + if(!(modeflag & HalfDCLK)) { + if(SiS_Pr->SiS_VGAHDE >= SiS_Pr->SiS_HDE) { + tempax = 0; + tempbx |= 0x20; + } + } + + tempch = tempcl = 0x01; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_VGAHDE >= 960) { + if((!(modeflag & HalfDCLK)) || (SiS_Pr->ChipType < SIS_315H)) { + tempcl = 0x20; + if(SiS_Pr->SiS_VGAHDE >= 1280) { + tempch = 20; + tempbx &= ~0x20; + } else if(SiS_Pr->SiS_VGAHDE >= 1024) { + tempch = 25; + } else { + tempch = 25; /* OK */ + } + } + } + } + + if(!(tempbx & 0x20)) { + if(modeflag & HalfDCLK) tempcl <<= 1; + longtemp = ((SiS_Pr->SiS_VGAHDE * tempch) / tempcl) << 13; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) longtemp <<= 3; + tempax = longtemp / SiS_Pr->SiS_HDE; + if(longtemp % SiS_Pr->SiS_HDE) tempax++; + tempbx |= ((tempax >> 8) & 0x1F); + tempcx = tempax >> 13; + } + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x44,tempax); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x45,0xC0,tempbx); + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + + tempcx &= 0x07; + if(tempbx & 0x20) tempcx = 0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x46,0xF8,tempcx); + + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tempbx = 0x0382; + tempcx = 0x007e; + } else { + tempbx = 0x0369; + tempcx = 0x0061; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4B,tempbx); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4C,tempcx); + temp = (tempcx & 0x0300) >> 6; + temp |= ((tempbx >> 8) & 0x03); + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + temp |= 0x10; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) temp |= 0x20; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) temp |= 0x40; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4D,temp); + + temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,(temp - 3)); + + SiS_SetTVSpecial(SiS_Pr, ModeNo); + + if(SiS_Pr->SiS_VBType & VB_SIS30xCLV) { + temp = 0; + if(SiS_Pr->SiS_TVMode & TVSetPALM) temp = 8; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xf7,temp); + } + + } + + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + if(!(SiS_Pr->SiS_TVMode & TVSetNTSC1024)) { + temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x01); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,(temp - 1)); + } + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xEF); + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0B,0x00); + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) return; + + /* From here: Part2 LCD setup */ + + tempbx = SiS_Pr->SiS_HDE; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; + tempbx--; /* RHACTE = HDE - 1 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2C,tempbx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,((tempbx >> 4) & 0xf0)); + + temp = 0x01; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(SiS_Pr->SiS_ModeType == ModeEGA) { + if(SiS_Pr->SiS_VGAHDE >= 1024) { + temp = 0x02; + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + temp = 0x01; + } + } + } + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0B,temp); + + tempbx = SiS_Pr->SiS_VDE - 1; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x03,tempbx); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0C,0xF8,((tempbx >> 8) & 0x07)); + + tempcx = SiS_Pr->SiS_VT - 1; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x19,tempcx); + temp = (tempcx >> 3) & 0xE0; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + /* Enable dithering; only do this for 32bpp mode */ + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) { + temp |= 0x10; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1A,0x0f,temp); + + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x09,0xF0); + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x0A,0xF0); + + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB); + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF); + +#ifdef CONFIG_FB_SIS_315 + if(SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + &CRT2Index, &resindex)) { + switch(CRT2Index) { + case 206: CRT2Part2Ptr = SiS310_CRT2Part2_Asus1024x768_3; break; + default: + case 200: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1; break; + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x02,0x80,(CRT2Part2Ptr+resindex)->CR[1]); + for(i = 2, j = 0x04; j <= 0x06; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + for(j = 0x1c; j <= 0x1d; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + for(j = 0x1f; j <= 0x21; i++, j++ ) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]); + + SiS_SetGroup2_Tail(SiS_Pr, ModeNo); + + } else { +#endif + + /* Checked for 1024x768, 1280x1024, 1400x1050, 1600x1200 */ + /* Clevo dual-link 1024x768 */ + /* Compaq 1280x1024 has HT 1696 sometimes (calculation OK, if given HT is correct) */ + /* Acer: OK, but uses different setting for VESA timing at 640/800/1024 and 640x400 */ + + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if((SiS_Pr->SiS_LCDInfo & LCDPass11) || (SiS_Pr->PanelYRes == SiS_Pr->SiS_VDE)) { + tempbx = SiS_Pr->SiS_VDE - 1; + tempcx = SiS_Pr->SiS_VT - 1; + } else { + tempbx = SiS_Pr->SiS_VDE + ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2); + tempcx = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2); + } + } else { + tempbx = SiS_Pr->PanelYRes; + tempcx = SiS_Pr->SiS_VT; + tempax = 1; + if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) { + tempax = SiS_Pr->PanelYRes; + /* if(SiS_Pr->SiS_VGAVDE == 525) tempax += 0x3c; */ /* 651+301C */ + if(SiS_Pr->PanelYRes < SiS_Pr->SiS_VDE) { + tempax = tempcx = 0; + } else { + tempax -= SiS_Pr->SiS_VDE; + } + tempax >>= 1; + } + tempcx -= tempax; /* lcdvdes */ + tempbx -= tempax; /* lcdvdee */ + } + + /* Non-expanding: lcdvdes = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */ + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempcx); /* lcdvdes */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempbx); /* lcdvdee */ + + temp = (tempbx >> 5) & 0x38; + temp |= ((tempcx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp); + + tempax = SiS_Pr->SiS_VDE; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + tempax = SiS_Pr->PanelYRes; + } + tempcx = (SiS_Pr->SiS_VT - tempax) >> 4; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) { + tempcx = (SiS_Pr->SiS_VT - tempax) / 10; + } + } + + tempbx = ((SiS_Pr->SiS_VT + SiS_Pr->SiS_VDE) >> 1) - 1; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { /* ? */ + tempax = SiS_Pr->SiS_VT - SiS_Pr->PanelYRes; + if(tempax % 4) { tempax >>= 2; tempax++; } + else { tempax >>= 2; } + tempbx -= (tempax - 1); + } else { + tempbx -= 10; + if(tempbx <= SiS_Pr->SiS_VDE) tempbx = SiS_Pr->SiS_VDE + 1; + } + } + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + tempbx++; + if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (crt2crtc == 6)) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + tempbx = 770; + tempcx = 3; + } + } + } + + /* non-expanding: lcdvrs = ((VT + VDE) / 2) - 10 */ + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CVSyncStart; + } + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx); /* lcdvrs */ + + temp = (tempbx >> 4) & 0xF0; + tempbx += (tempcx + 1); + temp |= (tempbx & 0x0F); + + if(SiS_Pr->UseCustomMode) { + temp &= 0xf0; + temp |= (SiS_Pr->CVSyncEnd & 0x0f); + } + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp); + +#ifdef CONFIG_FB_SIS_300 + SiS_Group2LCDSpecial(SiS_Pr, ModeNo, crt2crtc); +#endif + + bridgeoffset = 7; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) bridgeoffset += 2; + if(SiS_Pr->SiS_VBType & VB_SIS30xCLV) bridgeoffset += 2; /* OK for Averatec 1280x800 (301C) */ + if(SiS_IsDualLink(SiS_Pr)) bridgeoffset++; + else if(SiS_Pr->SiS_VBType & VB_SIS302LV) bridgeoffset++; /* OK for Asus A4L 1280x800 */ + /* Higher bridgeoffset shifts to the LEFT */ + + temp = 0; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) { + temp = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2); + if(SiS_IsDualLink(SiS_Pr)) temp >>= 1; + } + } + temp += bridgeoffset; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1F,temp); /* lcdhdes */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0F,((temp >> 4) & 0xf0)); + + tempcx = SiS_Pr->SiS_HT; + tempax = tempbx = SiS_Pr->SiS_HDE; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) { + tempax = SiS_Pr->PanelXRes; + tempbx = SiS_Pr->PanelXRes - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2); + } + } + if(SiS_IsDualLink(SiS_Pr)) { + tempcx >>= 1; + tempbx >>= 1; + tempax >>= 1; + } + + tempbx += bridgeoffset; + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempbx); /* lcdhdee */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0xF0,((tempbx >> 8) & 0x0f)); + + tempcx = (tempcx - tempax) >> 2; + + tempbx += tempcx; + push2 = tempbx; + + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + if(SiS_Pr->SiS_HDE == 1280) tempbx = (tempbx & 0xff00) | 0x47; + } + } + } + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CHSyncStart; + if(modeflag & HalfDCLK) tempbx <<= 1; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; + tempbx += bridgeoffset; + } + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,tempbx); /* lcdhrs */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,((tempbx >> 4) & 0xf0)); + + tempbx = push2; + + tempcx <<= 1; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) tempcx >>= 2; + } + tempbx += tempcx; + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CHSyncEnd; + if(modeflag & HalfDCLK) tempbx <<= 1; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; + tempbx += bridgeoffset; + } + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempbx); /* lcdhre */ + + SiS_SetGroup2_Tail(SiS_Pr, ModeNo); + +#ifdef CONFIG_FB_SIS_300 + SiS_Set300Part2Regs(SiS_Pr, ModeIdIndex, RefreshRateTableIndex, ModeNo); +#endif +#ifdef CONFIG_FB_SIS_315 + } /* CRT2-LCD from table */ +#endif +} + +/*********************************************/ +/* SET PART 3 REGISTER GROUP */ +/*********************************************/ + +static void +SiS_SetGroup3(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short i; + const unsigned char *tempdi; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; + +#ifndef SIS_CP + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x00,0x00); +#else + SIS_CP_INIT301_CP +#endif + + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x13,0xFA); + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x14,0xC8); + } else { + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x13,0xF5); + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x14,0xB7); + } + + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x13,0xFA); + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x14,0xC8); + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x3D,0xA8); + } + + tempdi = NULL; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + tempdi = SiS_Pr->SiS_HiTVGroup3Data; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + tempdi = SiS_Pr->SiS_HiTVGroup3Simu; + } + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(!(SiS_Pr->SiS_TVMode & TVSetYPbPr525i)) { + tempdi = SiS_HiTVGroup3_1; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempdi = SiS_HiTVGroup3_2; + } + } + if(tempdi) { + for(i=0; i<=0x3E; i++) { + SiS_SetReg(SiS_Pr->SiS_Part3Port,i,tempdi[i]); + } + if(SiS_Pr->SiS_VBType & VB_SIS30xCLV) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { + SiS_SetReg(SiS_Pr->SiS_Part3Port,0x28,0x3f); + } + } + } + +#ifdef SIS_CP + SIS_CP_INIT301_CP2 +#endif +} + +/*********************************************/ +/* SET PART 4 REGISTER GROUP */ +/*********************************************/ + +#ifdef CONFIG_FB_SIS_315 +#if 0 +static void +SiS_ShiftXPos(struct SiS_Private *SiS_Pr, int shift) +{ + unsigned short temp, temp1, temp2; + + temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x1f); + temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x20); + temp = (unsigned short)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1f,temp); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0f,((temp >> 4) & 0xf0)); + temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x2b) & 0x0f; + temp = (unsigned short)((int)(temp) + shift); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2b,0xf0,(temp & 0x0f)); + temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43); + temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x42); + temp = (unsigned short)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,temp); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x42,0x0f,((temp >> 4) & 0xf0)); +} +#endif + +static void +SiS_SetGroup4_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short temp, temp1, resinfo = 0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + + if(!(SiS_Pr->SiS_VBType & VB_SIS30xCLV)) return; + if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToHiVision | SetCRT2ToYPbPr525750))) return; + + if(SiS_Pr->ChipType >= XGI_20) return; + + if((SiS_Pr->ChipType >= SIS_661) && (SiS_Pr->SiS_ROMNew)) { + if(!(ROMAddr[0x61] & 0x04)) return; + } + + if(ModeNo > 0x13) { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3a,0x08); + temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x3a); + if(!(temp & 0x01)) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3a,0xdf); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xfc); + if((SiS_Pr->ChipType < SIS_661) && (!(SiS_Pr->SiS_ROMNew))) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xf8); + } + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0xfb); + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) temp = 0x0000; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) temp = 0x0002; + else if(SiS_Pr->SiS_TVMode & TVSetHiVision) temp = 0x0400; + else temp = 0x0402; + if((SiS_Pr->ChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + temp1 = 0; + if(SiS_Pr->SiS_TVMode & TVAspect43) temp1 = 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0f,0xfb,temp1); + if(SiS_Pr->SiS_TVMode & TVAspect43LB) temp |= 0x01; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0x7c,(temp & 0xff)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0xfb,(temp >> 8)); + if(ModeNo > 0x13) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x39,0xfd); + } + } else { + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x3b) & 0x03; + if(temp1 == 0x01) temp |= 0x01; + if(temp1 == 0x03) temp |= 0x04; /* ? why not 0x10? */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xf8,(temp & 0xff)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0xfb,(temp >> 8)); + if(ModeNo > 0x13) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3b,0xfd); + } + } + +#if 0 + if(SiS_Pr->ChipType >= SIS_661) { /* ? */ + if(SiS_Pr->SiS_TVMode & TVAspect43) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + if(resinfo == SIS_RI_1024x768) { + SiS_ShiftXPos(SiS_Pr, 97); + } else { + SiS_ShiftXPos(SiS_Pr, 111); + } + } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) { + SiS_ShiftXPos(SiS_Pr, 136); + } + } + } +#endif + + } + +} +#endif + +static void +SiS_SetCRT2VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short vclkindex, temp, reg1, reg2; + + if(SiS_Pr->UseCustomMode) { + reg1 = SiS_Pr->CSR2B; + reg2 = SiS_Pr->CSR2C; + } else { + vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + reg1 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A; + reg2 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B; + } + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSet525p1024)) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,0x57); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,0x46); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1f,0xf6); + } else { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,reg1); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,reg2); + } + } else { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,0x01); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,reg2); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,reg1); + } + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x12,0x00); + temp = 0x08; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) temp |= 0x20; + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,temp); +} + +static void +SiS_SetDualLinkEtc(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISDUALLINK) { + if((SiS_CRT2IsLCD(SiS_Pr)) || + (SiS_IsVAMode(SiS_Pr))) { + if(SiS_Pr->SiS_LCDInfo & LCDDualLink) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c); + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,~0x20); + } + } + } + } + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); +#ifdef SET_EMI + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); +#endif + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); + } +} + +static void +SiS_SetGroup4(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short tempax, tempcx, tempbx, modeflag, temp, resinfo; + unsigned int tempebx, tempeax, templong; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x24,0x0e); + } + } + } + + if(SiS_Pr->SiS_VBType & (VB_SIS30xCLV | VB_SIS302LV)) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x10,0x9f); + } + } + + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetDualLinkEtc(SiS_Pr); + return; + } + } + + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x13,SiS_Pr->SiS_RVBHCFACT); + + tempbx = SiS_Pr->SiS_RVBHCMAX; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x14,tempbx); + + temp = (tempbx >> 1) & 0x80; + + tempcx = SiS_Pr->SiS_VGAHT - 1; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x16,tempcx); + + temp |= ((tempcx >> 5) & 0x78); + + tempcx = SiS_Pr->SiS_VGAVT - 1; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempcx -= 5; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x17,tempcx); + + temp |= ((tempcx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x15,temp); + + tempbx = SiS_Pr->SiS_VGAHDE; + if(modeflag & HalfDCLK) tempbx >>= 1; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + temp = 0; + if(tempbx > 800) temp = 0x60; + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + temp = 0; + if(tempbx > 1024) temp = 0xC0; + else if(tempbx >= 960) temp = 0xA0; + } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) { + temp = 0; + if(tempbx >= 1280) temp = 0x40; + else if(tempbx >= 1024) temp = 0x20; + } else { + temp = 0x80; + if(tempbx >= 1024) temp = 0xA0; + } + + temp |= SiS_Pr->Init_P4_0E; + + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) { + temp &= 0xf0; + temp |= 0x0A; + } + } + + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0E,0x10,temp); + + tempeax = SiS_Pr->SiS_VGAVDE; + tempebx = SiS_Pr->SiS_VDE; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(!(temp & 0xE0)) tempebx >>=1; + } + + tempcx = SiS_Pr->SiS_RVBHRS; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x18,tempcx); + tempcx >>= 8; + tempcx |= 0x40; + + if(tempeax <= tempebx) { + tempcx ^= 0x40; + } else { + tempeax -= tempebx; + } + + tempeax *= (256 * 1024); + templong = tempeax % tempebx; + tempeax /= tempebx; + if(templong) tempeax++; + + temp = (unsigned short)(tempeax & 0x000000FF); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1B,temp); + temp = (unsigned short)((tempeax & 0x0000FF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1A,temp); + temp = (unsigned short)((tempeax >> 12) & 0x70); /* sic! */ + temp |= (tempcx & 0x4F); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x19,temp); + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1C,0x28); + + /* Calc Linebuffer max address and set/clear decimode */ + tempbx = 0; + if(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr750p)) tempbx = 0x08; + tempax = SiS_Pr->SiS_VGAHDE; + if(modeflag & HalfDCLK) tempax >>= 1; + if(SiS_IsDualLink(SiS_Pr)) tempax >>= 1; + if(tempax > 800) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + tempax -= 800; + } else { + tempbx = 0x08; + if(tempax == 960) tempax *= 25; /* Correct */ + else if(tempax == 1024) tempax *= 25; + else tempax *= 20; + temp = tempax % 32; + tempax /= 32; + if(temp) tempax++; + tempax++; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(resinfo == SIS_RI_1024x768 || + resinfo == SIS_RI_1024x576 || + resinfo == SIS_RI_1280x1024 || + resinfo == SIS_RI_1280x720) { + /* Otherwise white line or garbage at right edge */ + tempax = (tempax & 0xff00) | 0x20; + } + } + } + } + tempax--; + temp = ((tempax >> 4) & 0x30) | tempbx; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1D,tempax); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1E,temp); + + temp = 0x0036; tempbx = 0xD0; + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { + temp = 0x0026; tempbx = 0xC0; /* See En/DisableBridge() */ + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(!(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSetHiVision | TVSetYPbPr750p | TVSetYPbPr525p))) { + temp |= 0x01; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) { + temp &= ~0x01; + } + } + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,tempbx,temp); + + tempbx = SiS_Pr->SiS_HT >> 1; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; + tempbx -= 2; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x22,tempbx); + temp = (tempbx >> 5) & 0x38; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0xC0,temp); + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x24,0x0e); + /* LCD-too-dark-error-source, see FinalizeLCD() */ + } + } + + SiS_SetDualLinkEtc(SiS_Pr); + + } /* 301B */ + + SiS_SetCRT2VCLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); +} + +/*********************************************/ +/* SET PART 5 REGISTER GROUP */ +/*********************************************/ + +static void +SiS_SetGroup5(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; + + if(SiS_Pr->SiS_ModeType == ModeVGA) { + if(!(SiS_Pr->SiS_VBInfo & (SetInSlaveMode | LoadDACFlag))) { + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex); + } + } +} + +/*********************************************/ +/* MODIFY CRT1 GROUP FOR SLAVE MODE */ +/*********************************************/ + +static bool +SiS_GetLVDSCRT1Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex, unsigned short *ResIndex, + unsigned short *DisplayType) + { + unsigned short modeflag = 0; + bool checkhd = true; + + /* Pass 1:1 not supported here */ + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + (*ResIndex) &= 0x3F; + + if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + + (*DisplayType) = 80; + if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) { + (*DisplayType) = 82; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) (*DisplayType) = 84; + } + } + if((*DisplayType) != 84) { + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; + } + + } else { + + (*DisplayType = 0); + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_320x240_1: (*DisplayType) = 50; + checkhd = false; + break; + case Panel_320x240_2: (*DisplayType) = 14; + break; + case Panel_320x240_3: (*DisplayType) = 18; + break; + case Panel_640x480: (*DisplayType) = 10; + break; + case Panel_1024x600: (*DisplayType) = 26; + break; + default: return true; + } + + if(checkhd) { + if(modeflag & HalfDCLK) (*DisplayType)++; + } + + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x600) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) (*DisplayType) += 2; + } + + } + + return true; +} + +static void +SiS_ModCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short tempah, i, modeflag, j, ResIndex, DisplayType; + const struct SiS_LVDSCRT1Data *LVDSCRT1Ptr=NULL; + static const unsigned short CRIdx[] = { + 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x10, 0x11, 0x15, 0x16 + }; + + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + (SiS_Pr->SiS_CustomT == CUT_PANEL856) ) + return; + + if(SiS_Pr->SiS_IF_DEF_LVDS) { + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return; + } + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return; + } else return; + + if(SiS_Pr->SiS_LCDInfo & LCDPass11) return; + + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_SetFlag & SetDOSMode) return; + } + + if(!(SiS_GetLVDSCRT1Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + &ResIndex, &DisplayType))) { + return; + } + + switch(DisplayType) { + case 50: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_1; break; /* xSTN */ + case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_2; break; /* xSTN */ + case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_2_H; break; /* xSTN */ + case 18: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_3; break; /* xSTN */ + case 19: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_3_H; break; /* xSTN */ + case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1; break; + case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1_H; break; +#if 0 /* Works better with calculated numbers */ + case 26: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1; break; + case 27: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1_H; break; + case 28: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2; break; + case 29: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2_H; break; +#endif + case 80: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC; break; + case 81: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC; break; + case 82: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL; break; + case 83: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL; break; + case 84: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1SOPAL; break; + } + + if(LVDSCRT1Ptr) { + + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + for(i = 0; i <= 10; i++) { + tempah = (LVDSCRT1Ptr + ResIndex)->CR[i]; + SiS_SetReg(SiS_Pr->SiS_P3d4,CRIdx[i],tempah); + } + + for(i = 0x0A, j = 11; i <= 0x0C; i++, j++) { + tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; + SiS_SetReg(SiS_Pr->SiS_P3c4,i,tempah); + } + + tempah = (LVDSCRT1Ptr + ResIndex)->CR[14] & 0xE0; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1f,tempah); + + if(ModeNo <= 0x13) modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + + tempah = ((LVDSCRT1Ptr + ResIndex)->CR[14] & 0x01) << 5; + if(modeflag & DoubleScanMode) tempah |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah); + + } else { + + SiS_CalcLCDACRT1Timing(SiS_Pr, ModeNo, ModeIdIndex); + + } +} + +/*********************************************/ +/* SET CRT2 ECLK */ +/*********************************************/ + +static void +SiS_SetCRT2ECLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short clkbase, vclkindex = 0; + unsigned char sr2b, sr2c; + + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); + if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK == 2) { + RefreshRateTableIndex--; + } + vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + } else { + vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + } + + sr2b = SiS_Pr->SiS_VCLKData[vclkindex].SR2B; + sr2c = SiS_Pr->SiS_VCLKData[vclkindex].SR2C; + + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x01) { + sr2b = ROMAddr[0x227]; + sr2c = ROMAddr[0x228]; + } + } + } + + clkbase = 0x02B; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + clkbase += 3; + } + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x20); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x10); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x00); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b); + SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c); +} + +/*********************************************/ +/* SET UP CHRONTEL CHIPS */ +/*********************************************/ + +static void +SiS_SetCHTVReg(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short TVType, resindex; + const struct SiS_CHTVRegData *CHTVRegData = NULL; + + if(ModeNo <= 0x13) + resindex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + else + resindex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + + resindex &= 0x3F; + + TVType = 0; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + TVType += 2; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) TVType = 8; + } + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + TVType = 4; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; + } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { + TVType = 6; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; + } + } + + switch(TVType) { + case 0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break; + case 1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break; + case 2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL; break; + case 3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; + case 4: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALM; break; + case 5: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALM; break; + case 6: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALN; break; + case 7: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALN; break; + case 8: CHTVRegData = SiS_Pr->SiS_CHTVReg_SOPAL; break; + default: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; + } + + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + +#ifdef CONFIG_FB_SIS_300 + + /* Chrontel 7005 - I assume that it does not come with a 315 series chip */ + + /* We don't support modes >800x600 */ + if (resindex > 5) return; + + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + SiS_SetCH700x(SiS_Pr,0x04,0x43); /* 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/ + SiS_SetCH700x(SiS_Pr,0x09,0x69); /* Black level for PAL (105)*/ + } else { + SiS_SetCH700x(SiS_Pr,0x04,0x03); /* upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/ + SiS_SetCH700x(SiS_Pr,0x09,0x71); /* Black level for NTSC (113)*/ + } + + SiS_SetCH700x(SiS_Pr,0x00,CHTVRegData[resindex].Reg[0]); /* Mode register */ + SiS_SetCH700x(SiS_Pr,0x07,CHTVRegData[resindex].Reg[1]); /* Start active video register */ + SiS_SetCH700x(SiS_Pr,0x08,CHTVRegData[resindex].Reg[2]); /* Position overflow register */ + SiS_SetCH700x(SiS_Pr,0x0a,CHTVRegData[resindex].Reg[3]); /* Horiz Position register */ + SiS_SetCH700x(SiS_Pr,0x0b,CHTVRegData[resindex].Reg[4]); /* Vertical Position register */ + + /* Set minimum flicker filter for Luma channel (SR1-0=00), + minimum text enhancement (S3-2=10), + maximum flicker filter for Chroma channel (S5-4=10) + =00101000=0x28 (When reading, S1-0->S3-2, and S3-2->S1-0!) + */ + SiS_SetCH700x(SiS_Pr,0x01,0x28); + + /* Set video bandwidth + High bandwidth Luma composite video filter(S0=1) + low bandwidth Luma S-video filter (S2-1=00) + disable peak filter in S-video channel (S3=0) + high bandwidth Chroma Filter (S5-4=11) + =00110001=0x31 + */ + SiS_SetCH700x(SiS_Pr,0x03,0xb1); /* old: 3103 */ + + /* Register 0x3D does not exist in non-macrovision register map + (Maybe this is a macrovision register?) + */ +#ifndef SIS_CP + SiS_SetCH70xx(SiS_Pr,0x3d,0x00); +#endif + + /* Register 0x10 only contains 1 writable bit (S0) for sensing, + all other bits a read-only. Macrovision? + */ + SiS_SetCH70xxANDOR(SiS_Pr,0x10,0x00,0x1F); + + /* Register 0x11 only contains 3 writable bits (S0-S2) for + contrast enhancement (set to 010 -> gain 1 Yout = 17/16*(Yin-30) ) + */ + SiS_SetCH70xxANDOR(SiS_Pr,0x11,0x02,0xF8); + + /* Clear DSEN + */ + SiS_SetCH70xxANDOR(SiS_Pr,0x1c,0x00,0xEF); + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { /* ---- NTSC ---- */ + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) { + if(resindex == 0x04) { /* 640x480 overscan: Mode 16 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); /* ACIV on, no need to set FSCI */ + } else if(resindex == 0x05) { /* 800x600 overscan: Mode 23 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x18,0x01,0xF0); /* 0x18-0x1f: FSCI 469,762,048 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x19,0x0C,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1a,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1b,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1c,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1d,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1e,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1f,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x01,0xEF); /* Loop filter on for mode 23 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x00,0xFE); /* ACIV off, need to set FSCI */ + } + } else { + if(resindex == 0x04) { /* ----- 640x480 underscan; Mode 17 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); + } else if(resindex == 0x05) { /* ----- 800x600 underscan: Mode 24 */ +#if 0 + SiS_SetCH70xxANDOR(SiS_Pr,0x18,0x01,0xF0); /* (FSCI was 0x1f1c71c7 - this is for mode 22) */ + SiS_SetCH70xxANDOR(SiS_Pr,0x19,0x09,0xF0); /* FSCI for mode 24 is 428,554,851 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x1a,0x08,0xF0); /* 198b3a63 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x1b,0x0b,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1c,0x04,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1d,0x01,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1e,0x06,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1f,0x05,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off for mode 24 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x00,0xFE); * ACIV off, need to set FSCI */ +#endif /* All alternatives wrong (datasheet wrong?), don't use FSCI */ + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); + } + } + } else { /* ---- PAL ---- */ + /* We don't play around with FSCI in PAL mode */ + if(resindex == 0x04) { + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); /* ACIV on */ + } else { + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); /* ACIV on */ + } + } + +#endif /* 300 */ + + } else { + + /* Chrontel 7019 - assumed that it does not come with a 300 series chip */ + +#ifdef CONFIG_FB_SIS_315 + + unsigned short temp; + + /* We don't support modes >1024x768 */ + if (resindex > 6) return; + + temp = CHTVRegData[resindex].Reg[0]; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) temp |= 0x10; + SiS_SetCH701x(SiS_Pr,0x00,temp); + + SiS_SetCH701x(SiS_Pr,0x01,CHTVRegData[resindex].Reg[1]); + SiS_SetCH701x(SiS_Pr,0x02,CHTVRegData[resindex].Reg[2]); + SiS_SetCH701x(SiS_Pr,0x04,CHTVRegData[resindex].Reg[3]); + SiS_SetCH701x(SiS_Pr,0x03,CHTVRegData[resindex].Reg[4]); + SiS_SetCH701x(SiS_Pr,0x05,CHTVRegData[resindex].Reg[5]); + SiS_SetCH701x(SiS_Pr,0x06,CHTVRegData[resindex].Reg[6]); + + temp = CHTVRegData[resindex].Reg[7]; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) temp = 0x66; + SiS_SetCH701x(SiS_Pr,0x07,temp); + + SiS_SetCH701x(SiS_Pr,0x08,CHTVRegData[resindex].Reg[8]); + SiS_SetCH701x(SiS_Pr,0x15,CHTVRegData[resindex].Reg[9]); + SiS_SetCH701x(SiS_Pr,0x1f,CHTVRegData[resindex].Reg[10]); + SiS_SetCH701x(SiS_Pr,0x0c,CHTVRegData[resindex].Reg[11]); + SiS_SetCH701x(SiS_Pr,0x0d,CHTVRegData[resindex].Reg[12]); + SiS_SetCH701x(SiS_Pr,0x0e,CHTVRegData[resindex].Reg[13]); + SiS_SetCH701x(SiS_Pr,0x0f,CHTVRegData[resindex].Reg[14]); + SiS_SetCH701x(SiS_Pr,0x10,CHTVRegData[resindex].Reg[15]); + + temp = SiS_GetCH701x(SiS_Pr,0x21) & ~0x02; + /* D1 should be set for PAL, PAL-N and NTSC-J, + but I won't do that for PAL unless somebody + tells me to do so. Since the BIOS uses + non-default CIV values and blacklevels, + this might be compensated anyway. + */ + if(SiS_Pr->SiS_TVMode & (TVSetPALN | TVSetNTSCJ)) temp |= 0x02; + SiS_SetCH701x(SiS_Pr,0x21,temp); + +#endif /* 315 */ + + } + +#ifdef SIS_CP + SIS_CP_INIT301_CP3 +#endif + +} + +#ifdef CONFIG_FB_SIS_315 /* ----------- 315 series only ---------- */ + +void +SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr) +{ + unsigned short temp; + + /* Enable Chrontel 7019 LCD panel backlight */ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_Pr->ChipType == SIS_740) { + SiS_SetCH701x(SiS_Pr,0x66,0x65); + } else { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp |= 0x20; + SiS_SetCH701x(SiS_Pr,0x66,temp); + } + } +} + +void +SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr) +{ + unsigned short temp; + + /* Disable Chrontel 7019 LCD panel backlight */ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp &= 0xDF; + SiS_SetCH701x(SiS_Pr,0x66,temp); + } +} + +static void +SiS_ChrontelPowerSequencing(struct SiS_Private *SiS_Pr) +{ + static const unsigned char regtable[] = { 0x67, 0x68, 0x69, 0x6a, 0x6b }; + static const unsigned char table1024_740[] = { 0x01, 0x02, 0x01, 0x01, 0x01 }; + static const unsigned char table1400_740[] = { 0x01, 0x6e, 0x01, 0x01, 0x01 }; + static const unsigned char asus1024_740[] = { 0x19, 0x6e, 0x01, 0x19, 0x09 }; + static const unsigned char asus1400_740[] = { 0x19, 0x6e, 0x01, 0x19, 0x09 }; + static const unsigned char table1024_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 }; + static const unsigned char table1400_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 }; + const unsigned char *tableptr = NULL; + int i; + + /* Set up Power up/down timing */ + + if(SiS_Pr->ChipType == SIS_740) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1024_740; + else tableptr = table1024_740; + } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) { + if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1400_740; + else tableptr = table1400_740; + } else return; + } else { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + tableptr = table1024_650; + } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) { + tableptr = table1400_650; + } else return; + } + + for(i=0; i<5; i++) { + SiS_SetCH701x(SiS_Pr, regtable[i], tableptr[i]); + } +} + +static void +SiS_SetCH701xForLCD(struct SiS_Private *SiS_Pr) +{ + const unsigned char *tableptr = NULL; + unsigned short tempbh; + int i; + static const unsigned char regtable[] = { + 0x1c, 0x5f, 0x64, 0x6f, 0x70, 0x71, + 0x72, 0x73, 0x74, 0x76, 0x78, 0x7d, 0x66 + }; + static const unsigned char table1024_740[] = { + 0x60, 0x02, 0x00, 0x07, 0x40, 0xed, + 0xa3, 0xc8, 0xc7, 0xac, 0xe0, 0x02, 0x44 + }; + static const unsigned char table1280_740[] = { + 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 + }; + static const unsigned char table1400_740[] = { + 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 + }; + static const unsigned char table1600_740[] = { + 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a, 0x44 + }; + static const unsigned char table1024_650[] = { + 0x60, 0x02, 0x00, 0x07, 0x40, 0xed, + 0xa3, 0xc8, 0xc7, 0xac, 0x60, 0x02 + }; + static const unsigned char table1280_650[] = { + 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02 + }; + static const unsigned char table1400_650[] = { + 0x60, 0x03, 0x11, 0x00, 0x40, 0xef, + 0xad, 0xdb, 0xf6, 0xac, 0x60, 0x02 + }; + static const unsigned char table1600_650[] = { + 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a + }; + + if(SiS_Pr->ChipType == SIS_740) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tableptr = table1024_740; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_740; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_740; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_740; + else return; + } else { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tableptr = table1024_650; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_650; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_650; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_650; + else return; + } + + tempbh = SiS_GetCH701x(SiS_Pr,0x74); + if((tempbh == 0xf6) || (tempbh == 0xc7)) { + tempbh = SiS_GetCH701x(SiS_Pr,0x73); + if(tempbh == 0xc8) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) return; + } else if(tempbh == 0xdb) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) return; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) return; + } else if(tempbh == 0xde) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) return; + } + } + + if(SiS_Pr->ChipType == SIS_740) tempbh = 0x0d; + else tempbh = 0x0c; + + for(i = 0; i < tempbh; i++) { + SiS_SetCH701x(SiS_Pr, regtable[i], tableptr[i]); + } + SiS_ChrontelPowerSequencing(SiS_Pr); + tempbh = SiS_GetCH701x(SiS_Pr,0x1e); + tempbh |= 0xc0; + SiS_SetCH701x(SiS_Pr,0x1e,tempbh); + + if(SiS_Pr->ChipType == SIS_740) { + tempbh = SiS_GetCH701x(SiS_Pr,0x1c); + tempbh &= 0xfb; + SiS_SetCH701x(SiS_Pr,0x1c,tempbh); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x03); + tempbh = SiS_GetCH701x(SiS_Pr,0x64); + tempbh |= 0x40; + SiS_SetCH701x(SiS_Pr,0x64,tempbh); + tempbh = SiS_GetCH701x(SiS_Pr,0x03); + tempbh &= 0x3f; + SiS_SetCH701x(SiS_Pr,0x03,tempbh); + } +} + +static void +SiS_ChrontelResetVSync(struct SiS_Private *SiS_Pr) +{ + unsigned char temp, temp1; + + temp1 = SiS_GetCH701x(SiS_Pr,0x49); + SiS_SetCH701x(SiS_Pr,0x49,0x3e); + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp &= 0x7f; /* Use external VSYNC */ + SiS_SetCH701x(SiS_Pr,0x47,temp); + SiS_LongDelay(SiS_Pr, 3); + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp |= 0x80; /* Use internal VSYNC */ + SiS_SetCH701x(SiS_Pr,0x47,temp); + SiS_SetCH701x(SiS_Pr,0x49,temp1); +} + +static void +SiS_Chrontel701xOn(struct SiS_Private *SiS_Pr) +{ + unsigned short temp; + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_Pr->ChipType == SIS_740) { + temp = SiS_GetCH701x(SiS_Pr,0x1c); + temp |= 0x04; /* Invert XCLK phase */ + SiS_SetCH701x(SiS_Pr,0x1c,temp); + } + if(SiS_IsYPbPr(SiS_Pr)) { + temp = SiS_GetCH701x(SiS_Pr,0x01); + temp &= 0x3f; + temp |= 0x80; /* Enable YPrPb (HDTV) */ + SiS_SetCH701x(SiS_Pr,0x01,temp); + } + if(SiS_IsChScart(SiS_Pr)) { + temp = SiS_GetCH701x(SiS_Pr,0x01); + temp &= 0x3f; + temp |= 0xc0; /* Enable SCART + CVBS */ + SiS_SetCH701x(SiS_Pr,0x01,temp); + } + if(SiS_Pr->ChipType == SIS_740) { + SiS_ChrontelResetVSync(SiS_Pr); + SiS_SetCH701x(SiS_Pr,0x49,0x20); /* Enable TV path */ + } else { + SiS_SetCH701x(SiS_Pr,0x49,0x20); /* Enable TV path */ + temp = SiS_GetCH701x(SiS_Pr,0x49); + if(SiS_IsYPbPr(SiS_Pr)) { + temp = SiS_GetCH701x(SiS_Pr,0x73); + temp |= 0x60; + SiS_SetCH701x(SiS_Pr,0x73,temp); + } + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp &= 0x7f; + SiS_SetCH701x(SiS_Pr,0x47,temp); + SiS_LongDelay(SiS_Pr, 2); + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp |= 0x80; + SiS_SetCH701x(SiS_Pr,0x47,temp); + } + } +} + +static void +SiS_Chrontel701xOff(struct SiS_Private *SiS_Pr) +{ + unsigned short temp; + + /* Complete power down of LVDS */ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_Pr->ChipType == SIS_740) { + SiS_LongDelay(SiS_Pr, 1); + SiS_GenericDelay(SiS_Pr, 5887); + SiS_SetCH701x(SiS_Pr,0x76,0xac); + SiS_SetCH701x(SiS_Pr,0x66,0x00); + } else { + SiS_LongDelay(SiS_Pr, 2); + temp = SiS_GetCH701x(SiS_Pr,0x76); + temp &= 0xfc; + SiS_SetCH701x(SiS_Pr,0x76,temp); + SiS_SetCH701x(SiS_Pr,0x66,0x00); + } + } +} + +static void +SiS_ChrontelResetDB(struct SiS_Private *SiS_Pr) +{ + unsigned short temp; + + if(SiS_Pr->ChipType == SIS_740) { + + temp = SiS_GetCH701x(SiS_Pr,0x4a); /* Version ID */ + temp &= 0x01; + if(!temp) { + + if(SiS_WeHaveBacklightCtrl(SiS_Pr)) { + temp = SiS_GetCH701x(SiS_Pr,0x49); + SiS_SetCH701x(SiS_Pr,0x49,0x3e); + } + + /* Reset Chrontel 7019 datapath */ + SiS_SetCH701x(SiS_Pr,0x48,0x10); + SiS_LongDelay(SiS_Pr, 1); + SiS_SetCH701x(SiS_Pr,0x48,0x18); + + if(SiS_WeHaveBacklightCtrl(SiS_Pr)) { + SiS_ChrontelResetVSync(SiS_Pr); + SiS_SetCH701x(SiS_Pr,0x49,temp); + } + + } else { + + /* Clear/set/clear GPIO */ + temp = SiS_GetCH701x(SiS_Pr,0x5c); + temp &= 0xef; + SiS_SetCH701x(SiS_Pr,0x5c,temp); + temp = SiS_GetCH701x(SiS_Pr,0x5c); + temp |= 0x10; + SiS_SetCH701x(SiS_Pr,0x5c,temp); + temp = SiS_GetCH701x(SiS_Pr,0x5c); + temp &= 0xef; + SiS_SetCH701x(SiS_Pr,0x5c,temp); + temp = SiS_GetCH701x(SiS_Pr,0x61); + if(!temp) { + SiS_SetCH701xForLCD(SiS_Pr); + } + } + + } else { /* 650 */ + /* Reset Chrontel 7019 datapath */ + SiS_SetCH701x(SiS_Pr,0x48,0x10); + SiS_LongDelay(SiS_Pr, 1); + SiS_SetCH701x(SiS_Pr,0x48,0x18); + } +} + +static void +SiS_ChrontelInitTVVSync(struct SiS_Private *SiS_Pr) +{ + unsigned short temp; + + if(SiS_Pr->ChipType == SIS_740) { + + if(SiS_WeHaveBacklightCtrl(SiS_Pr)) { + SiS_ChrontelResetVSync(SiS_Pr); + } + + } else { + + SiS_SetCH701x(SiS_Pr,0x76,0xaf); /* Power up LVDS block */ + temp = SiS_GetCH701x(SiS_Pr,0x49); + temp &= 1; + if(temp != 1) { /* TV block powered? (0 = yes, 1 = no) */ + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp &= 0x70; + SiS_SetCH701x(SiS_Pr,0x47,temp); /* enable VSYNC */ + SiS_LongDelay(SiS_Pr, 3); + temp = SiS_GetCH701x(SiS_Pr,0x47); + temp |= 0x80; + SiS_SetCH701x(SiS_Pr,0x47,temp); /* disable VSYNC */ + } + + } +} + +static void +SiS_ChrontelDoSomething3(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + unsigned short temp,temp1; + + if(SiS_Pr->ChipType == SIS_740) { + + temp = SiS_GetCH701x(SiS_Pr,0x61); + if(temp < 1) { + temp++; + SiS_SetCH701x(SiS_Pr,0x61,temp); + } + SiS_SetCH701x(SiS_Pr,0x66,0x45); /* Panel power on */ + SiS_SetCH701x(SiS_Pr,0x76,0xaf); /* All power on */ + SiS_LongDelay(SiS_Pr, 1); + SiS_GenericDelay(SiS_Pr, 5887); + + } else { /* 650 */ + + temp1 = 0; + temp = SiS_GetCH701x(SiS_Pr,0x61); + if(temp < 2) { + temp++; + SiS_SetCH701x(SiS_Pr,0x61,temp); + temp1 = 1; + } + SiS_SetCH701x(SiS_Pr,0x76,0xac); + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp |= 0x5f; + SiS_SetCH701x(SiS_Pr,0x66,temp); + if(ModeNo > 0x13) { + if(SiS_WeHaveBacklightCtrl(SiS_Pr)) { + SiS_GenericDelay(SiS_Pr, 1023); + } else { + SiS_GenericDelay(SiS_Pr, 767); + } + } else { + if(!temp1) + SiS_GenericDelay(SiS_Pr, 767); + } + temp = SiS_GetCH701x(SiS_Pr,0x76); + temp |= 0x03; + SiS_SetCH701x(SiS_Pr,0x76,temp); + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp &= 0x7f; + SiS_SetCH701x(SiS_Pr,0x66,temp); + SiS_LongDelay(SiS_Pr, 1); + + } +} + +static void +SiS_ChrontelDoSomething2(struct SiS_Private *SiS_Pr) +{ + unsigned short temp; + + SiS_LongDelay(SiS_Pr, 1); + + do { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp &= 0x04; /* PLL stable? -> bail out */ + if(temp == 0x04) break; + + if(SiS_Pr->ChipType == SIS_740) { + /* Power down LVDS output, PLL normal operation */ + SiS_SetCH701x(SiS_Pr,0x76,0xac); + } + + SiS_SetCH701xForLCD(SiS_Pr); + + temp = SiS_GetCH701x(SiS_Pr,0x76); + temp &= 0xfb; /* Reset PLL */ + SiS_SetCH701x(SiS_Pr,0x76,temp); + SiS_LongDelay(SiS_Pr, 2); + temp = SiS_GetCH701x(SiS_Pr,0x76); + temp |= 0x04; /* PLL normal operation */ + SiS_SetCH701x(SiS_Pr,0x76,temp); + if(SiS_Pr->ChipType == SIS_740) { + SiS_SetCH701x(SiS_Pr,0x78,0xe0); /* PLL loop filter */ + } else { + SiS_SetCH701x(SiS_Pr,0x78,0x60); + } + SiS_LongDelay(SiS_Pr, 2); + } while(0); + + SiS_SetCH701x(SiS_Pr,0x77,0x00); /* MV? */ +} + +static void +SiS_ChrontelDoSomething1(struct SiS_Private *SiS_Pr) +{ + unsigned short temp; + + temp = SiS_GetCH701x(SiS_Pr,0x03); + temp |= 0x80; /* Set datapath 1 to TV */ + temp &= 0xbf; /* Set datapath 2 to LVDS */ + SiS_SetCH701x(SiS_Pr,0x03,temp); + + if(SiS_Pr->ChipType == SIS_740) { + + temp = SiS_GetCH701x(SiS_Pr,0x1c); + temp &= 0xfb; /* Normal XCLK phase */ + SiS_SetCH701x(SiS_Pr,0x1c,temp); + + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x03); + + temp = SiS_GetCH701x(SiS_Pr,0x64); + temp |= 0x40; /* ? Bit not defined */ + SiS_SetCH701x(SiS_Pr,0x64,temp); + + temp = SiS_GetCH701x(SiS_Pr,0x03); + temp &= 0x3f; /* D1 input to both LVDS and TV */ + SiS_SetCH701x(SiS_Pr,0x03,temp); + + if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) { + SiS_SetCH701x(SiS_Pr,0x63,0x40); /* LVDS off */ + SiS_LongDelay(SiS_Pr, 1); + SiS_SetCH701x(SiS_Pr,0x63,0x00); /* LVDS on */ + SiS_ChrontelResetDB(SiS_Pr); + SiS_ChrontelDoSomething2(SiS_Pr); + SiS_ChrontelDoSomething3(SiS_Pr, 0); + } else { + temp = SiS_GetCH701x(SiS_Pr,0x66); + if(temp != 0x45) { + SiS_ChrontelResetDB(SiS_Pr); + SiS_ChrontelDoSomething2(SiS_Pr); + SiS_ChrontelDoSomething3(SiS_Pr, 0); + } + } + + } else { /* 650 */ + + SiS_ChrontelResetDB(SiS_Pr); + SiS_ChrontelDoSomething2(SiS_Pr); + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34); + SiS_ChrontelDoSomething3(SiS_Pr,temp); + SiS_SetCH701x(SiS_Pr,0x76,0xaf); /* All power on, LVDS normal operation */ + + } + +} +#endif /* 315 series */ + +/*********************************************/ +/* MAIN: SET CRT2 REGISTER GROUP */ +/*********************************************/ + +bool +SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ +#ifdef CONFIG_FB_SIS_300 + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; +#endif + unsigned short ModeIdIndex, RefreshRateTableIndex; + + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + + if(!SiS_Pr->UseCustomMode) { + SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex); + } else { + ModeIdIndex = 0; + } + + /* Used for shifting CR33 */ + SiS_Pr->SiS_SelectCRT2Rate = 4; + + SiS_UnLockCRT2(SiS_Pr); + + RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex); + + SiS_SaveCRT2Info(SiS_Pr,ModeNo); + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + SiS_DisableBridge(SiS_Pr); + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->ChipType == SIS_730)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,0x80); + } + SiS_SetCRT2ModeRegs(SiS_Pr, ModeNo, ModeIdIndex); + } + + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { + SiS_LockCRT2(SiS_Pr); + SiS_DisplayOn(SiS_Pr); + return true; + } + + SiS_GetCRT2Data(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + + /* Set up Panel Link for LVDS and LCDA */ + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0; + if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) || + ((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) || + ((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS30xBLV)) ) { + SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + SiS_SetGroup1(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + + SiS_SetGroup2(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); +#ifdef CONFIG_FB_SIS_315 + SiS_SetGroup2_C_ELV(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); +#endif + SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex); + SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); +#ifdef CONFIG_FB_SIS_315 + SiS_SetGroup4_C_ELV(SiS_Pr, ModeNo, ModeIdIndex); +#endif + SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex); + + SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex); + + /* For 301BDH (Panel link initialization): */ + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + + if(!((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10)))) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SiS_ModCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + } + SiS_SetCRT2ECLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + } + + } else { + + SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex); + + SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex); + + SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex); + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { +#ifdef CONFIG_FB_SIS_315 + SiS_SetCH701xForLCD(SiS_Pr); +#endif + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_SetCHTVReg(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex); + } + } + } + + } + +#ifdef CONFIG_FB_SIS_300 + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->SiS_UseOEM) { + if((SiS_Pr->SiS_UseROM) && (SiS_Pr->SiS_UseOEM == -1)) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + SiS_OEM300Setting(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + } else { + SiS_OEM300Setting(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + } + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + SetOEMLCDData2(SiS_Pr, ModeNo, ModeIdIndex,RefreshRateTableIndex); + } + SiS_DisplayOn(SiS_Pr); + } + } + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->ChipType < SIS_661) { + SiS_FinalizeLCD(SiS_Pr, ModeNo, ModeIdIndex); + SiS_OEM310Setting(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } else { + SiS_OEM661Setting(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40); + } + } +#endif + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + SiS_EnableBridge(SiS_Pr); + } + + SiS_DisplayOn(SiS_Pr); + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + /* Disable LCD panel when using TV */ + SiS_SetRegSR11ANDOR(SiS_Pr,0xFF,0x0C); + } else { + /* Disable TV when using LCD */ + SiS_SetCH70xxANDOR(SiS_Pr,0x0e,0x01,0xf8); + } + } + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + SiS_LockCRT2(SiS_Pr); + } + + return true; +} + + +/*********************************************/ +/* ENABLE/DISABLE LCD BACKLIGHT (SIS) */ +/*********************************************/ + +void +SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr) +{ + /* Switch on LCD backlight on SiS30xLV */ + SiS_DDC2Delay(SiS_Pr,0xff00); + if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); + SiS_WaitVBRetrace(SiS_Pr); + } + if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x01)) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); + } +} + +void +SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr) +{ + /* Switch off LCD backlight on SiS30xLV */ + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); + SiS_DDC2Delay(SiS_Pr,0xff00); +} + +/*********************************************/ +/* DDC RELATED FUNCTIONS */ +/*********************************************/ + +static void +SiS_SetupDDCN(struct SiS_Private *SiS_Pr) +{ + SiS_Pr->SiS_DDC_NData = ~SiS_Pr->SiS_DDC_Data; + SiS_Pr->SiS_DDC_NClk = ~SiS_Pr->SiS_DDC_Clk; + if((SiS_Pr->SiS_DDC_Index == 0x11) && (SiS_Pr->SiS_SensibleSR11)) { + SiS_Pr->SiS_DDC_NData &= 0x0f; + SiS_Pr->SiS_DDC_NClk &= 0x0f; + } +} + +#ifdef CONFIG_FB_SIS_300 +static unsigned char * +SiS_SetTrumpBlockLoop(struct SiS_Private *SiS_Pr, unsigned char *dataptr) +{ + int i, j, num; + unsigned short tempah,temp; + unsigned char *mydataptr; + + for(i=0; i<20; i++) { /* Do 20 attempts to write */ + mydataptr = dataptr; + num = *mydataptr++; + if(!num) return mydataptr; + if(i) { + SiS_SetStop(SiS_Pr); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT * 2); + } + if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ + tempah = SiS_Pr->SiS_DDC_DeviceAddr; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write DAB (S0=0=write) */ + if(temp) continue; /* (ERROR: no ack) */ + tempah = *mydataptr++; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write register number */ + if(temp) continue; /* (ERROR: no ack) */ + for(j=0; j<num; j++) { + tempah = *mydataptr++; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah);/* Write DAB (S0=0=write) */ + if(temp) break; + } + if(temp) continue; + if(SiS_SetStop(SiS_Pr)) continue; + return mydataptr; + } + return NULL; +} + +static bool +SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr) +{ + SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB (Device Address Byte) */ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + + SiS_SetSwitchDDC2(SiS_Pr); + + while(*dataptr) { + dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr); + if(!dataptr) return false; + } + return true; +} +#endif + +/* The Chrontel 700x is connected to the 630/730 via + * the 630/730's DDC/I2C port. + * + * On 630(S)T chipset, the index changed from 0x11 to + * 0x0a, possibly for working around the DDC problems + */ + +static bool +SiS_SetChReg(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val, unsigned short myor) +{ + unsigned short temp, i; + + for(i=0; i<20; i++) { /* Do 20 attempts to write */ + if(i) { + SiS_SetStop(SiS_Pr); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT * 4); + } + if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ + temp = SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_DeviceAddr); /* Write DAB (S0=0=write) */ + if(temp) continue; /* (ERROR: no ack) */ + temp = SiS_WriteDDC2Data(SiS_Pr, (reg | myor)); /* Write RAB (700x: set bit 7, see datasheet) */ + if(temp) continue; /* (ERROR: no ack) */ + temp = SiS_WriteDDC2Data(SiS_Pr, val); /* Write data */ + if(temp) continue; /* (ERROR: no ack) */ + if(SiS_SetStop(SiS_Pr)) continue; /* Set stop condition */ + SiS_Pr->SiS_ChrontelInit = 1; + return true; + } + return false; +} + +/* Write to Chrontel 700x */ +void +SiS_SetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val) +{ + SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB (Device Address Byte) */ + + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + + if(!(SiS_Pr->SiS_ChrontelInit)) { + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + } + + if( (!(SiS_SetChReg(SiS_Pr, reg, val, 0x80))) && + (!(SiS_Pr->SiS_ChrontelInit)) ) { + SiS_Pr->SiS_DDC_Index = 0x0a; + SiS_Pr->SiS_DDC_Data = 0x80; + SiS_Pr->SiS_DDC_Clk = 0x40; + SiS_SetupDDCN(SiS_Pr); + + SiS_SetChReg(SiS_Pr, reg, val, 0x80); + } +} + +/* Write to Chrontel 701x */ +/* Parameter is [Data (S15-S8) | Register no (S7-S0)] */ +void +SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val) +{ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB (Device Address Byte) */ + SiS_SetChReg(SiS_Pr, reg, val, 0); +} + +static +void +SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val) +{ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) + SiS_SetCH700x(SiS_Pr, reg, val); + else + SiS_SetCH701x(SiS_Pr, reg, val); +} + +static unsigned short +SiS_GetChReg(struct SiS_Private *SiS_Pr, unsigned short myor) +{ + unsigned short tempah, temp, i; + + for(i=0; i<20; i++) { /* Do 20 attempts to read */ + if(i) { + SiS_SetStop(SiS_Pr); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT * 4); + } + if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ + temp = SiS_WriteDDC2Data(SiS_Pr,SiS_Pr->SiS_DDC_DeviceAddr); /* Write DAB (S0=0=write) */ + if(temp) continue; /* (ERROR: no ack) */ + temp = SiS_WriteDDC2Data(SiS_Pr,SiS_Pr->SiS_DDC_ReadAddr | myor); /* Write RAB (700x: | 0x80) */ + if(temp) continue; /* (ERROR: no ack) */ + if (SiS_SetStart(SiS_Pr)) continue; /* Re-start */ + temp = SiS_WriteDDC2Data(SiS_Pr,SiS_Pr->SiS_DDC_DeviceAddr | 0x01);/* DAB (S0=1=read) */ + if(temp) continue; /* (ERROR: no ack) */ + tempah = SiS_ReadDDC2Data(SiS_Pr); /* Read byte */ + if(SiS_SetStop(SiS_Pr)) continue; /* Stop condition */ + SiS_Pr->SiS_ChrontelInit = 1; + return tempah; + } + return 0xFFFF; +} + +/* Read from Chrontel 700x */ +/* Parameter is [Register no (S7-S0)] */ +unsigned short +SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempbx) +{ + unsigned short result; + + SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB */ + + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + + if(!(SiS_Pr->SiS_ChrontelInit)) { + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + } + + SiS_Pr->SiS_DDC_ReadAddr = tempbx; + + if( ((result = SiS_GetChReg(SiS_Pr,0x80)) == 0xFFFF) && + (!SiS_Pr->SiS_ChrontelInit) ) { + + SiS_Pr->SiS_DDC_Index = 0x0a; + SiS_Pr->SiS_DDC_Data = 0x80; + SiS_Pr->SiS_DDC_Clk = 0x40; + SiS_SetupDDCN(SiS_Pr); + + result = SiS_GetChReg(SiS_Pr,0x80); + } + return result; +} + +/* Read from Chrontel 701x */ +/* Parameter is [Register no (S7-S0)] */ +unsigned short +SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short tempbx) +{ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB */ + + SiS_Pr->SiS_DDC_ReadAddr = tempbx; + + return SiS_GetChReg(SiS_Pr,0); +} + +/* Read from Chrontel 70xx */ +/* Parameter is [Register no (S7-S0)] */ +static +unsigned short +SiS_GetCH70xx(struct SiS_Private *SiS_Pr, unsigned short tempbx) +{ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) + return SiS_GetCH700x(SiS_Pr, tempbx); + else + return SiS_GetCH701x(SiS_Pr, tempbx); +} + +void +SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg, + unsigned char myor, unsigned short myand) +{ + unsigned short tempbl; + + tempbl = (SiS_GetCH70xx(SiS_Pr, (reg & 0xFF)) & myand) | myor; + SiS_SetCH70xx(SiS_Pr, reg, tempbl); +} + +/* Our own DDC functions */ +static +unsigned short +SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, + unsigned short adaptnum, unsigned short DDCdatatype, bool checkcr32, + unsigned int VBFlags2) +{ + unsigned char ddcdtype[] = { 0xa0, 0xa0, 0xa0, 0xa2, 0xa6 }; + unsigned char flag, cr32; + unsigned short temp = 0, myadaptnum = adaptnum; + + if(adaptnum != 0) { + if(!(VBFlags2 & VB2_SISTMDSBRIDGE)) return 0xFFFF; + if((VBFlags2 & VB2_30xBDH) && (adaptnum == 1)) return 0xFFFF; + } + + /* adapternum for SiS bridges: 0 = CRT1, 1 = LCD, 2 = VGA2 */ + + SiS_Pr->SiS_ChrontelInit = 0; /* force re-detection! */ + + SiS_Pr->SiS_DDC_SecAddr = 0; + SiS_Pr->SiS_DDC_DeviceAddr = ddcdtype[DDCdatatype]; + SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_P3c4; + SiS_Pr->SiS_DDC_Index = 0x11; + flag = 0xff; + + cr32 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x32); + +#if 0 + if(VBFlags2 & VB2_SISBRIDGE) { + if(myadaptnum == 0) { + if(!(cr32 & 0x20)) { + myadaptnum = 2; + if(!(cr32 & 0x10)) { + myadaptnum = 1; + if(!(cr32 & 0x08)) { + myadaptnum = 0; + } + } + } + } + } +#endif + + if(VGAEngine == SIS_300_VGA) { /* 300 series */ + + if(myadaptnum != 0) { + flag = 0; + if(VBFlags2 & VB2_SISBRIDGE) { + SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port; + SiS_Pr->SiS_DDC_Index = 0x0f; + } + } + + if(!(VBFlags2 & VB2_301)) { + if((cr32 & 0x80) && (checkcr32)) { + if(myadaptnum >= 1) { + if(!(cr32 & 0x08)) { + myadaptnum = 1; + if(!(cr32 & 0x10)) return 0xFFFF; + } + } + } + } + + temp = 4 - (myadaptnum * 2); + if(flag) temp = 0; + + } else { /* 315/330 series */ + + /* here we simplify: 0 = CRT1, 1 = CRT2 (VGA, LCD) */ + + if(VBFlags2 & VB2_SISBRIDGE) { + if(myadaptnum == 2) { + myadaptnum = 1; + } + } + + if(myadaptnum == 1) { + flag = 0; + if(VBFlags2 & VB2_SISBRIDGE) { + SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port; + SiS_Pr->SiS_DDC_Index = 0x0f; + } + } + + if((cr32 & 0x80) && (checkcr32)) { + if(myadaptnum >= 1) { + if(!(cr32 & 0x08)) { + myadaptnum = 1; + if(!(cr32 & 0x10)) return 0xFFFF; + } + } + } + + temp = myadaptnum; + if(myadaptnum == 1) { + temp = 0; + if(VBFlags2 & VB2_LVDS) flag = 0xff; + } + + if(flag) temp = 0; + } + + SiS_Pr->SiS_DDC_Data = 0x02 << temp; + SiS_Pr->SiS_DDC_Clk = 0x01 << temp; + + SiS_SetupDDCN(SiS_Pr); + + return 0; +} + +static unsigned short +SiS_WriteDABDDC(struct SiS_Private *SiS_Pr) +{ + if(SiS_SetStart(SiS_Pr)) return 0xFFFF; + if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_DeviceAddr)) { + return 0xFFFF; + } + if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_SecAddr)) { + return 0xFFFF; + } + return 0; +} + +static unsigned short +SiS_PrepareReadDDC(struct SiS_Private *SiS_Pr) +{ + if(SiS_SetStart(SiS_Pr)) return 0xFFFF; + if(SiS_WriteDDC2Data(SiS_Pr, (SiS_Pr->SiS_DDC_DeviceAddr | 0x01))) { + return 0xFFFF; + } + return 0; +} + +static unsigned short +SiS_PrepareDDC(struct SiS_Private *SiS_Pr) +{ + if(SiS_WriteDABDDC(SiS_Pr)) SiS_WriteDABDDC(SiS_Pr); + if(SiS_PrepareReadDDC(SiS_Pr)) return (SiS_PrepareReadDDC(SiS_Pr)); + return 0; +} + +static void +SiS_SendACK(struct SiS_Private *SiS_Pr, unsigned short yesno) +{ + SiS_SetSCLKLow(SiS_Pr); + if(yesno) { + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0); + } + SiS_SetSCLKHigh(SiS_Pr); +} + +static unsigned short +SiS_DoProbeDDC(struct SiS_Private *SiS_Pr) +{ + unsigned char mask, value; + unsigned short temp, ret=0; + bool failed = false; + + SiS_SetSwitchDDC2(SiS_Pr); + if(SiS_PrepareDDC(SiS_Pr)) { + SiS_SetStop(SiS_Pr); + return 0xFFFF; + } + mask = 0xf0; + value = 0x20; + if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) { + temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr); + SiS_SendACK(SiS_Pr, 0); + if(temp == 0) { + mask = 0xff; + value = 0xff; + } else { + failed = true; + ret = 0xFFFF; + } + } + if(!failed) { + temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr); + SiS_SendACK(SiS_Pr, 1); + temp &= mask; + if(temp == value) ret = 0; + else { + ret = 0xFFFF; + if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) { + if(temp == 0x30) ret = 0; + } + } + } + SiS_SetStop(SiS_Pr); + return ret; +} + +static +unsigned short +SiS_ProbeDDC(struct SiS_Private *SiS_Pr) +{ + unsigned short flag; + + flag = 0x180; + SiS_Pr->SiS_DDC_DeviceAddr = 0xa0; + if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x02; + SiS_Pr->SiS_DDC_DeviceAddr = 0xa2; + if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x08; + SiS_Pr->SiS_DDC_DeviceAddr = 0xa6; + if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x10; + if(!(flag & 0x1a)) flag = 0; + return flag; +} + +static +unsigned short +SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, unsigned char *buffer) +{ + unsigned short flag, length, i; + unsigned char chksum,gotcha; + + if(DDCdatatype > 4) return 0xFFFF; + + flag = 0; + SiS_SetSwitchDDC2(SiS_Pr); + if(!(SiS_PrepareDDC(SiS_Pr))) { + length = 127; + if(DDCdatatype != 1) length = 255; + chksum = 0; + gotcha = 0; + for(i=0; i<length; i++) { + buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr); + chksum += buffer[i]; + gotcha |= buffer[i]; + SiS_SendACK(SiS_Pr, 0); + } + buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr); + chksum += buffer[i]; + SiS_SendACK(SiS_Pr, 1); + if(gotcha) flag = (unsigned short)chksum; + else flag = 0xFFFF; + } else { + flag = 0xFFFF; + } + SiS_SetStop(SiS_Pr); + return flag; +} + +/* Our private DDC functions + + It complies somewhat with the corresponding VESA function + in arguments and return values. + + Since this is probably called before the mode is changed, + we use our pre-detected pSiS-values instead of SiS_Pr as + regards chipset and video bridge type. + + Arguments: + adaptnum: 0=CRT1(analog), 1=CRT2/LCD(digital), 2=CRT2/VGA2(analog) + CRT2 DDC is only supported on SiS301, 301B, 301C, 302B. + LCDA is CRT1, but DDC is read from CRT2 port. + DDCdatatype: 0=Probe, 1=EDID, 2=EDID+VDIF, 3=EDID V2 (P&D), 4=EDID V2 (FPDI-2) + buffer: ptr to 256 data bytes which will be filled with read data. + + Returns 0xFFFF if error, otherwise + if DDCdatatype > 0: Returns 0 if reading OK (included a correct checksum) + if DDCdatatype = 0: Returns supported DDC modes + + */ +unsigned short +SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, + unsigned short adaptnum, unsigned short DDCdatatype, unsigned char *buffer, + unsigned int VBFlags2) +{ + unsigned char sr1f, cr17=1; + unsigned short result; + + if(adaptnum > 2) + return 0xFFFF; + + if(DDCdatatype > 4) + return 0xFFFF; + + if((!(VBFlags2 & VB2_VIDEOBRIDGE)) && (adaptnum > 0)) + return 0xFFFF; + + if(SiS_InitDDCRegs(SiS_Pr, VBFlags, VGAEngine, adaptnum, DDCdatatype, false, VBFlags2) == 0xFFFF) + return 0xFFFF; + + sr1f = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f); + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1f,0x3f,0x04); + if(VGAEngine == SIS_300_VGA) { + cr17 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80; + if(!cr17) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x17,0x80); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x01); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03); + } + } + if((sr1f) || (!cr17)) { + SiS_WaitRetrace1(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); + } + + if(DDCdatatype == 0) { + result = SiS_ProbeDDC(SiS_Pr); + } else { + result = SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer); + if((!result) && (DDCdatatype == 1)) { + if((buffer[0] == 0x00) && (buffer[1] == 0xff) && + (buffer[2] == 0xff) && (buffer[3] == 0xff) && + (buffer[4] == 0xff) && (buffer[5] == 0xff) && + (buffer[6] == 0xff) && (buffer[7] == 0x00) && + (buffer[0x12] == 1)) { + if(!SiS_Pr->DDCPortMixup) { + if(adaptnum == 1) { + if(!(buffer[0x14] & 0x80)) result = 0xFFFE; + } else { + if(buffer[0x14] & 0x80) result = 0xFFFE; + } + } + } + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x1f,sr1f); + if(VGAEngine == SIS_300_VGA) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x17,0x7f,cr17); + } + return result; +} + +/* Generic I2C functions for Chrontel & DDC --------- */ + +static void +SiS_SetSwitchDDC2(struct SiS_Private *SiS_Pr) +{ + SiS_SetSCLKHigh(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); + + SiS_SetSCLKLow(SiS_Pr); + SiS_WaitRetrace1(SiS_Pr); +} + +unsigned short +SiS_ReadDDC1Bit(struct SiS_Private *SiS_Pr) +{ + SiS_WaitRetrace1(SiS_Pr); + return ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x02) >> 1); +} + +/* Set I2C start condition */ +/* This is done by a SD high-to-low transition while SC is high */ +static unsigned short +SiS_SetStart(struct SiS_Private *SiS_Pr) +{ + if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* SD->high */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* SD->low = start condition */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->low) */ + return 0; +} + +/* Set I2C stop condition */ +/* This is done by a SD low-to-high transition while SC is high */ +static unsigned short +SiS_SetStop(struct SiS_Private *SiS_Pr) +{ + if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* SD->low */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* SD->high = stop condition */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->high) */ + return 0; +} + +/* Write 8 bits of data */ +static unsigned short +SiS_WriteDDC2Data(struct SiS_Private *SiS_Pr, unsigned short tempax) +{ + unsigned short i,flag,temp; + + flag = 0x80; + for(i = 0; i < 8; i++) { + SiS_SetSCLKLow(SiS_Pr); /* SC->low */ + if(tempax & flag) { + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* Write bit (1) to SD */ + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* Write bit (0) to SD */ + } + SiS_SetSCLKHigh(SiS_Pr); /* SC->high */ + flag >>= 1; + } + temp = SiS_CheckACK(SiS_Pr); /* Check acknowledge */ + return temp; +} + +static unsigned short +SiS_ReadDDC2Data(struct SiS_Private *SiS_Pr) +{ + unsigned short i, temp, getdata; + + getdata = 0; + for(i = 0; i < 8; i++) { + getdata <<= 1; + SiS_SetSCLKLow(SiS_Pr); + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); + SiS_SetSCLKHigh(SiS_Pr); + temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); + if(temp & SiS_Pr->SiS_DDC_Data) getdata |= 0x01; + } + return getdata; +} + +static unsigned short +SiS_SetSCLKLow(struct SiS_Private *SiS_Pr) +{ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NClk, + 0x00); /* SetSCLKLow() */ + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + return 0; +} + +static unsigned short +SiS_SetSCLKHigh(struct SiS_Private *SiS_Pr) +{ + unsigned short temp, watchdog=1000; + + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NClk, + SiS_Pr->SiS_DDC_Clk); /* SetSCLKHigh() */ + do { + temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); + } while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog); + if (!watchdog) { + return 0xFFFF; + } + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + return 0; +} + +/* Check I2C acknowledge */ +/* Returns 0 if ack ok, non-0 if ack not ok */ +static unsigned short +SiS_CheckACK(struct SiS_Private *SiS_Pr) +{ + unsigned short tempah; + + SiS_SetSCLKLow(SiS_Pr); /* (SC->low) */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* (SD->high) */ + SiS_SetSCLKHigh(SiS_Pr); /* SC->high = clock impulse for ack */ + tempah = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); /* Read SD */ + SiS_SetSCLKLow(SiS_Pr); /* SC->low = end of clock impulse */ + if(tempah & SiS_Pr->SiS_DDC_Data) return 1; /* Ack OK if bit = 0 */ + return 0; +} + +/* End of I2C functions ----------------------- */ + + +/* =============== SiS 315/330 O.E.M. ================= */ + +#ifdef CONFIG_FB_SIS_315 + +static unsigned short +GetRAMDACromptr(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr; + + if(SiS_Pr->ChipType < SIS_330) { + romptr = SISGETROMW(0x128); + if(SiS_Pr->SiS_VBType & VB_SIS30xB) + romptr = SISGETROMW(0x12a); + } else { + romptr = SISGETROMW(0x1a8); + if(SiS_Pr->SiS_VBType & VB_SIS30xB) + romptr = SISGETROMW(0x1aa); + } + return romptr; +} + +static unsigned short +GetLCDromptr(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr; + + if(SiS_Pr->ChipType < SIS_330) { + romptr = SISGETROMW(0x120); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) + romptr = SISGETROMW(0x122); + } else { + romptr = SISGETROMW(0x1a0); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) + romptr = SISGETROMW(0x1a2); + } + return romptr; +} + +static unsigned short +GetTVromptr(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr; + + if(SiS_Pr->ChipType < SIS_330) { + romptr = SISGETROMW(0x114); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) + romptr = SISGETROMW(0x11a); + } else { + romptr = SISGETROMW(0x194); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) + romptr = SISGETROMW(0x19a); + } + return romptr; +} + +static unsigned short +GetLCDPtrIndexBIOS(struct SiS_Private *SiS_Pr) +{ + unsigned short index; + + if((IS_SIS650) && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { + if(!(SiS_IsNotM650orLater(SiS_Pr))) { + if((index = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xf0)) { + index >>= 4; + index *= 3; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; + else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++; + return index; + } + } + } + + index = SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) index -= 5; + if(SiS_Pr->SiS_VBType & VB_SIS301C) { /* 1.15.20 and later (not VB specific) */ + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) index -= 5; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768) index -= 5; + } else { + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) index -= 6; + } + index--; + index *= 3; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; + else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++; + return index; +} + +static unsigned short +GetLCDPtrIndex(struct SiS_Private *SiS_Pr) +{ + unsigned short index; + + index = ((SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F) - 1) * 3; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; + else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++; + return index; +} + +static unsigned short +GetTVPtrIndex(struct SiS_Private *SiS_Pr) +{ + unsigned short index; + + index = 0; + if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 1; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) index = 2; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) index = 0; + + index <<= 1; + + if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) { + index++; + } + + return index; +} + +static unsigned int +GetOEMTVPtr661_2_GEN(struct SiS_Private *SiS_Pr, int addme) +{ + unsigned short index = 0, temp = 0; + + if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 1; + if(SiS_Pr->SiS_TVMode & TVSetPALM) index = 2; + if(SiS_Pr->SiS_TVMode & TVSetPALN) index = 3; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) index = 6; + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + index = 4; + if(SiS_Pr->SiS_TVMode & TVSetPALM) index++; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) index = 7; + } + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) { + index += addme; + temp++; + } + temp += 0x0100; + } + return (unsigned int)(index | (temp << 16)); +} + +static unsigned int +GetOEMTVPtr661_2_OLD(struct SiS_Private *SiS_Pr) +{ + return (GetOEMTVPtr661_2_GEN(SiS_Pr, 8)); +} + +#if 0 +static unsigned int +GetOEMTVPtr661_2_NEW(struct SiS_Private *SiS_Pr) +{ + return (GetOEMTVPtr661_2_GEN(SiS_Pr, 6)); +} +#endif + +static int +GetOEMTVPtr661(struct SiS_Private *SiS_Pr) +{ + int index = 0; + + if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 2; + if(SiS_Pr->SiS_ROMNew) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 4; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 6; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 8; + if(SiS_Pr->SiS_TVMode & TVSetHiVision) index = 10; + } else { + if(SiS_Pr->SiS_TVMode & TVSetHiVision) index = 4; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 6; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 8; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 10; + } + + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) index++; + + return index; +} + +static void +SetDelayComp(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short delay=0,index,myindex,temp,romptr=0; + bool dochiptest = true; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x20,0xbf); + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x35,0x7f); + } + + /* Find delay (from ROM, internal tables, PCI subsystem) */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { /* ------------ VGA */ + + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + romptr = GetRAMDACromptr(SiS_Pr); + } + if(romptr) delay = ROMAddr[romptr]; + else { + delay = 0x04; + if(SiS_Pr->SiS_VBType & VB_SIS30xB) { + if(IS_SIS650) { + delay = 0x0a; + } else if(IS_SIS740) { + delay = 0x00; + } else if(SiS_Pr->ChipType < SIS_330) { + delay = 0x0c; + } else { + delay = 0x0c; + } + } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + delay = 0x00; + } + } + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD|SetCRT2ToLCDA)) { /* ---------- LCD/LCDA */ + + bool gotitfrompci = false; + + /* Could we detect a PDC for LCD or did we get a user-defined? If yes, use it */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->PDC != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((SiS_Pr->PDC >> 1) & 0x0f)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((SiS_Pr->PDC & 0x01) << 7)); + return; + } + } else { + if(SiS_Pr->PDCA != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((SiS_Pr->PDCA << 3) & 0xf0)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((SiS_Pr->PDCA & 0x01) << 6)); + return; + } + } + + /* Custom Panel? */ + + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + delay = 0x00; + if((SiS_Pr->PanelXRes <= 1280) && (SiS_Pr->PanelYRes <= 1024)) { + delay = 0x20; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,delay); + } else { + delay = 0x0c; + if(SiS_Pr->SiS_VBType & VB_SIS301C) { + delay = 0x03; + if((SiS_Pr->PanelXRes > 1280) && (SiS_Pr->PanelYRes > 1024)) { + delay = 0x00; + } + } else if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + if(IS_SIS740) delay = 0x01; + else delay = 0x03; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,delay); + } + return; + } + + /* This is a piece of typical SiS crap: They code the OEM LCD + * delay into the code, at no defined place in the BIOS. + * We now have to start doing a PCI subsystem check here. + */ + + switch(SiS_Pr->SiS_CustomT) { + case CUT_COMPAQ1280: + case CUT_COMPAQ12802: + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + gotitfrompci = true; + dochiptest = false; + delay = 0x03; + } + break; + case CUT_CLEVO1400: + case CUT_CLEVO14002: + gotitfrompci = true; + dochiptest = false; + delay = 0x02; + break; + case CUT_CLEVO1024: + case CUT_CLEVO10242: + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + gotitfrompci = true; + dochiptest = false; + delay = 0x33; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2D,delay); + delay &= 0x0f; + } + break; + } + + /* Could we find it through the PCI ID? If no, use ROM or table */ + + if(!gotitfrompci) { + + index = GetLCDPtrIndexBIOS(SiS_Pr); + myindex = GetLCDPtrIndex(SiS_Pr); + + if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { + + if(SiS_IsNotM650orLater(SiS_Pr)) { + + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + /* Always use the second pointer on 650; some BIOSes */ + /* still carry old 301 data at the first location */ + /* romptr = SISGETROMW(0x120); */ + /* if(SiS_Pr->SiS_VBType & VB_SIS302LV) */ + romptr = SISGETROMW(0x122); + if(!romptr) return; + delay = ROMAddr[(romptr + index)]; + } else { + delay = SiS310_LCDDelayCompensation_650301LV[myindex]; + } + + } else { + + delay = SiS310_LCDDelayCompensation_651301LV[myindex]; + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) + delay = SiS310_LCDDelayCompensation_651302LV[myindex]; + + } + + } else if(SiS_Pr->SiS_UseROM && + (!(SiS_Pr->SiS_ROMNew)) && + (SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) && + (SiS_Pr->SiS_LCDResInfo != Panel_1280x768) && + (SiS_Pr->SiS_LCDResInfo != Panel_1280x960) && + (SiS_Pr->SiS_LCDResInfo != Panel_1600x1200) && + ((romptr = GetLCDromptr(SiS_Pr)))) { + + /* Data for 1280x1024 wrong in 301B BIOS */ + /* Data for 1600x1200 wrong in 301C BIOS */ + delay = ROMAddr[(romptr + index)]; + + } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + + if(IS_SIS740) delay = 0x03; + else delay = 0x00; + + } else { + + delay = SiS310_LCDDelayCompensation_301[myindex]; + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + if(IS_SIS740) delay = 0x01; + else if(SiS_Pr->ChipType <= SIS_315PRO) delay = SiS310_LCDDelayCompensation_3xx301LV[myindex]; + else delay = SiS310_LCDDelayCompensation_650301LV[myindex]; + } else if(SiS_Pr->SiS_VBType & VB_SIS301C) { + if(IS_SIS740) delay = 0x01; /* ? */ + else delay = 0x03; + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) delay = 0x00; /* experience */ + } else if(SiS_Pr->SiS_VBType & VB_SIS30xB) { + if(IS_SIS740) delay = 0x01; + else delay = SiS310_LCDDelayCompensation_3xx301B[myindex]; + } + + } + + } /* got it from PCI */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,((delay << 4) & 0xf0)); + dochiptest = false; + } + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* ------------ TV */ + + index = GetTVPtrIndex(SiS_Pr); + + if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { + + if(SiS_IsNotM650orLater(SiS_Pr)) { + + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + /* Always use the second pointer on 650; some BIOSes */ + /* still carry old 301 data at the first location */ + /* romptr = SISGETROMW(0x114); */ + /* if(SiS_Pr->SiS_VBType & VB_SIS302LV) */ + romptr = SISGETROMW(0x11a); + if(!romptr) return; + delay = ROMAddr[romptr + index]; + + } else { + + delay = SiS310_TVDelayCompensation_301B[index]; + + } + + } else { + + switch(SiS_Pr->SiS_CustomT) { + case CUT_COMPAQ1280: + case CUT_COMPAQ12802: + case CUT_CLEVO1400: + case CUT_CLEVO14002: + delay = 0x02; + dochiptest = false; + break; + case CUT_CLEVO1024: + case CUT_CLEVO10242: + delay = 0x03; + dochiptest = false; + break; + default: + delay = SiS310_TVDelayCompensation_651301LV[index]; + if(SiS_Pr->SiS_VBType & VB_SIS302LV) { + delay = SiS310_TVDelayCompensation_651302LV[index]; + } + } + } + + } else if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + + romptr = GetTVromptr(SiS_Pr); + if(!romptr) return; + delay = ROMAddr[romptr + index]; + + } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + + delay = SiS310_TVDelayCompensation_LVDS[index]; + + } else { + + delay = SiS310_TVDelayCompensation_301[index]; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(IS_SIS740) { + delay = SiS310_TVDelayCompensation_740301B[index]; + /* LV: use 301 data? BIOS bug? */ + } else { + delay = SiS310_TVDelayCompensation_301B[index]; + if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x02; + } + } + + } + + if(SiS_LCDAEnabled(SiS_Pr)) { + delay &= 0x0f; + dochiptest = false; + } + + } else return; + + /* Write delay */ + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SISLVDS) && dochiptest) { + + temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xf0) >> 4; + if(temp == 8) { /* 1400x1050 BIOS (COMPAL) */ + delay &= 0x0f; + delay |= 0xb0; + } else if(temp == 6) { + delay &= 0x0f; + delay |= 0xc0; + } else if(temp > 7) { /* 1280x1024 BIOS (which one?) */ + delay = 0x35; + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2D,delay); + + } else { + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay); + + } + + } else { /* LVDS */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay); + } else { + if(IS_SIS650 && (SiS_Pr->SiS_IF_DEF_CH70xx != 0)) { + delay <<= 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,delay); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay); + } + } + + } + +} + +static void +SetAntiFlicker(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,temp1,romptr=0; + + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p|TVSetYPbPr525p)) return; + + if(ModeNo<=0x13) + index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex; + else + index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex; + + temp = GetTVPtrIndex(SiS_Pr); + temp >>= 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ + temp1 = temp; + + if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { + if(SiS_Pr->ChipType >= SIS_661) { + temp1 = GetOEMTVPtr661(SiS_Pr); + temp1 >>= 1; + romptr = SISGETROMW(0x260); + if(SiS_Pr->ChipType >= SIS_760) { + romptr = SISGETROMW(0x360); + } + } else if(SiS_Pr->ChipType >= SIS_330) { + romptr = SISGETROMW(0x192); + } else { + romptr = SISGETROMW(0x112); + } + } + + if(romptr) { + temp1 <<= 1; + temp = ROMAddr[romptr + temp1 + index]; + } else { + temp = SiS310_TVAntiFlick1[temp][index]; + } + temp <<= 4; + + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8f,temp); /* index 0A D[6:4] */ +} + +static void +SetEdgeEnhance(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,temp1,romptr=0; + + temp = temp1 = GetTVPtrIndex(SiS_Pr) >> 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ + + if(ModeNo <= 0x13) + index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex; + else + index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex; + + if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { + if(SiS_Pr->ChipType >= SIS_661) { + romptr = SISGETROMW(0x26c); + if(SiS_Pr->ChipType >= SIS_760) { + romptr = SISGETROMW(0x36c); + } + temp1 = GetOEMTVPtr661(SiS_Pr); + temp1 >>= 1; + } else if(SiS_Pr->ChipType >= SIS_330) { + romptr = SISGETROMW(0x1a4); + } else { + romptr = SISGETROMW(0x124); + } + } + + if(romptr) { + temp1 <<= 1; + temp = ROMAddr[romptr + temp1 + index]; + } else { + temp = SiS310_TVEdge1[temp][index]; + } + temp <<= 5; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x3A,0x1F,temp); /* index 0A D[7:5] */ +} + +static void +SetYFilter(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex) +{ + unsigned short index, temp, i, j; + + if(ModeNo <= 0x13) { + index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex; + } else { + index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex; + } + + temp = GetTVPtrIndex(SiS_Pr) >> 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ + + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) temp = 1; /* NTSC-J uses PAL */ + else if(SiS_Pr->SiS_TVMode & TVSetPALM) temp = 3; /* PAL-M */ + else if(SiS_Pr->SiS_TVMode & TVSetPALN) temp = 4; /* PAL-N */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) temp = 1; /* HiVision uses PAL */ + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]); + } + for(i=0x48; i<=0x4A; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]); + } + } else { + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter1[temp][index][j]); + } + } +} + +static void +SetPhaseIncr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,i,j,resinfo,romptr=0; + unsigned int lindex; + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return; + + /* NTSC-J data not in BIOS, and already set in SetGroup2 */ + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) return; + + if((SiS_Pr->ChipType >= SIS_661) || SiS_Pr->SiS_ROMNew) { + lindex = GetOEMTVPtr661_2_OLD(SiS_Pr) & 0xffff; + lindex <<= 2; + for(j=0, i=0x31; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS_TVPhase[lindex + j]); + } + return; + } + + /* PAL-M, PAL-N not in BIOS, and already set in SetGroup2 */ + if(SiS_Pr->SiS_TVMode & (TVSetPALM | TVSetPALN)) return; + + if(ModeNo<=0x13) { + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + temp = GetTVPtrIndex(SiS_Pr); + /* 0: NTSC Graphics, 1: NTSC Text, 2: PAL Graphics, + * 3: PAL Text, 4: HiTV Graphics 5: HiTV Text + */ + if(SiS_Pr->SiS_UseROM) { + romptr = SISGETROMW(0x116); + if(SiS_Pr->ChipType >= SIS_330) { + romptr = SISGETROMW(0x196); + } + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + romptr = SISGETROMW(0x11c); + if(SiS_Pr->ChipType >= SIS_330) { + romptr = SISGETROMW(0x19c); + } + if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && (!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode))) { + romptr = SISGETROMW(0x116); + if(SiS_Pr->ChipType >= SIS_330) { + romptr = SISGETROMW(0x196); + } + } + } + } + if(romptr) { + romptr += (temp << 2); + for(j=0, i=0x31; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]); + } + } else { + index = temp % 2; + temp >>= 1; /* 0:NTSC, 1:PAL, 2:HiTV */ + for(j=0, i=0x31; i<=0x34; i++, j++) { + if(!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]); + else if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr2[temp][index][j]); + else + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]); + } + } + + if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision))) { + if((!(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetYPbPr525p | TVSetYPbPr750p))) && (ModeNo > 0x13)) { + if((resinfo == SIS_RI_640x480) || + (resinfo == SIS_RI_800x600)) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x21); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0xf0); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xf5); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7f); + } else if(resinfo == SIS_RI_1024x768) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x1e); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0x8b); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xfb); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7b); + } + } + } +} + +static void +SetDelayComp661(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RTI) +{ + unsigned short delay = 0, romptr = 0, index, lcdpdcindex; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + + if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToRAMDAC))) + return; + + /* 1. New ROM: VGA2 and LCD/LCDA-Pass1:1 */ + /* (If a custom mode is used, Pass1:1 is always set; hence we do this:) */ + + if(SiS_Pr->SiS_ROMNew) { + if((SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) || + ((SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) && + (SiS_Pr->SiS_LCDInfo & LCDPass11))) { + index = 25; + if(SiS_Pr->UseCustomMode) { + index = SiS_Pr->CSRClock; + } else if(ModeNo > 0x13) { + index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RTI); + index = SiS_Pr->SiS_VCLKData[index].CLOCK; + } + if(index < 25) index = 25; + index = ((index / 25) - 1) << 1; + if((ROMAddr[0x5b] & 0x80) || (SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD))) { + index++; + } + romptr = SISGETROMW(0x104); + delay = ROMAddr[romptr + index]; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD)) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7)); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6)); + } + return; + } + } + + /* 2. Old ROM: VGA2 and LCD/LCDA-Pass 1:1 */ + + if(SiS_Pr->UseCustomMode) delay = 0x04; + else if(ModeNo <= 0x13) delay = 0x04; + else delay = (SiS_Pr->SiS_RefIndex[RTI].Ext_PDC >> 4); + delay |= (delay << 8); + + if(SiS_Pr->ChipType >= XGI_20) { + + delay = 0x0606; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + + delay = 0x0404; + if(SiS_Pr->SiS_XGIROM) { + index = GetTVPtrIndex(SiS_Pr); + if((romptr = SISGETROMW(0x35e))) { + delay = (ROMAddr[romptr + index] & 0x0f) << 1; + delay |= (delay << 8); + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->ChipType == XGI_40 && SiS_Pr->ChipRevision == 0x02) { + delay -= 0x0404; + } + } + } + + } else if(SiS_Pr->ChipType >= SIS_340) { + + delay = 0x0606; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + delay = 0x0404; + } + /* TODO (eventually) */ + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + + /* 3. TV */ + + index = GetOEMTVPtr661(SiS_Pr); + if(SiS_Pr->SiS_ROMNew) { + romptr = SISGETROMW(0x106); + if(SiS_Pr->SiS_VBType & VB_UMC) romptr += 12; + delay = ROMAddr[romptr + index]; + } else { + delay = 0x04; + if(index > 3) delay = 0; + } + + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + + /* 4. LCD, LCDA (for new ROM only LV and non-Pass 1:1) */ + + if( (SiS_Pr->SiS_LCDResInfo != Panel_Custom) && + ((romptr = GetLCDStructPtr661_2(SiS_Pr))) ) { + + lcdpdcindex = (SiS_Pr->SiS_VBType & VB_UMC) ? 14 : 12; + + /* For LVDS (and sometimes TMDS), the BIOS must know about the correct value */ + delay = ROMAddr[romptr + lcdpdcindex + 1]; /* LCD */ + delay |= (ROMAddr[romptr + lcdpdcindex] << 8); /* LCDA */ + + } else { + + /* TMDS: Set our own, since BIOS has no idea */ + /* (This is done on >=661 only, since <661 is calling this only for LVDS) */ + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1024x768: delay = 0x0008; break; + case Panel_1280x720: delay = 0x0004; break; + case Panel_1280x768: + case Panel_1280x768_2:delay = 0x0004; break; + case Panel_1280x800: + case Panel_1280x800_2:delay = 0x0004; break; /* Verified for 1280x800 */ + case Panel_1280x854: delay = 0x0004; break; /* FIXME */ + case Panel_1280x1024: delay = 0x1e04; break; + case Panel_1400x1050: delay = 0x0004; break; + case Panel_1600x1200: delay = 0x0400; break; + case Panel_1680x1050: delay = 0x0e04; break; + default: + if((SiS_Pr->PanelXRes <= 1024) && (SiS_Pr->PanelYRes <= 768)) { + delay = 0x0008; + } else if((SiS_Pr->PanelXRes == 1280) && (SiS_Pr->PanelYRes == 1024)) { + delay = 0x1e04; + } else if((SiS_Pr->PanelXRes <= 1400) && (SiS_Pr->PanelYRes <= 1050)) { + delay = 0x0004; + } else if((SiS_Pr->PanelXRes <= 1600) && (SiS_Pr->PanelYRes <= 1200)) { + delay = 0x0400; + } else + delay = 0x0e04; + break; + } + } + + /* Override by detected or user-set values */ + /* (but only if, for some reason, we can't read value from BIOS) */ + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->PDC != -1)) { + delay = SiS_Pr->PDC & 0x1f; + } + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) && (SiS_Pr->PDCA != -1)) { + delay = (SiS_Pr->PDCA & 0x1f) << 8; + } + + } + + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + delay >>= 8; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6)); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7)); + } +} + +static void +SetCRT2SyncDither661(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short RTI) +{ + unsigned short infoflag; + unsigned char temp; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + + if(ModeNo <= 0x13) { + infoflag = SiS_GetRegByte(SiS_Pr->SiS_P3ca+2); + } else if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RTI].Ext_InfoFlag; + } + + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + infoflag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); /* No longer check D5 */ + } + + infoflag &= 0xc0; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + temp = (infoflag >> 6) | 0x0c; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + temp ^= 0x04; + if(SiS_Pr->SiS_ModeType >= Mode24Bpp) temp |= 0x10; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xe0,temp); + } else { + temp = 0x30; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) temp = 0x20; + temp |= infoflag; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,temp); + temp = 0; + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + if(SiS_Pr->SiS_ModeType >= Mode24Bpp) temp |= 0x80; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0x7f,temp); + } + + } +} + +static void +SetPanelParms661(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr, temp1, temp2; + + if(SiS_Pr->SiS_VBType & (VB_SISLVDS | VB_SIS30xC)) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x24,0x0f); + } + + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + if(SiS_Pr->LVDSHL != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,SiS_Pr->LVDSHL); + } + } + + if(SiS_Pr->SiS_ROMNew) { + + if((romptr = GetLCDStructPtr661_2(SiS_Pr))) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + temp1 = (ROMAddr[romptr] & 0x03) | 0x0c; + temp2 = 0xfc; + if(SiS_Pr->LVDSHL != -1) { + temp1 &= 0xfc; + temp2 = 0xf3; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,temp2,temp1); + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + temp1 = (ROMAddr[romptr + 1] & 0x80) >> 1; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d,0xbf,temp1); + } + } + + } +} + +static void +SiS_OEM310Setting(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RRTI) +{ + if((SiS_Pr->SiS_ROMNew) && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { + SetDelayComp661(SiS_Pr, ModeNo, ModeIdIndex, RRTI); + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + SetCRT2SyncDither661(SiS_Pr, ModeNo, RRTI); + SetPanelParms661(SiS_Pr); + } + } else { + SetDelayComp(SiS_Pr,ModeNo); + } + + if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + SetAntiFlicker(SiS_Pr,ModeNo,ModeIdIndex); + SetPhaseIncr(SiS_Pr,ModeNo,ModeIdIndex); + SetYFilter(SiS_Pr,ModeNo,ModeIdIndex); + if(SiS_Pr->SiS_VBType & VB_SIS301) { + SetEdgeEnhance(SiS_Pr,ModeNo,ModeIdIndex); + } + } +} + +static void +SiS_OEM661Setting(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) +{ + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + SetDelayComp661(SiS_Pr, ModeNo, ModeIdIndex, RRTI); + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + SetCRT2SyncDither661(SiS_Pr, ModeNo, RRTI); + SetPanelParms661(SiS_Pr); + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SetPhaseIncr(SiS_Pr, ModeNo, ModeIdIndex); + SetYFilter(SiS_Pr, ModeNo, ModeIdIndex); + SetAntiFlicker(SiS_Pr, ModeNo, ModeIdIndex); + if(SiS_Pr->SiS_VBType & VB_SIS301) { + SetEdgeEnhance(SiS_Pr, ModeNo, ModeIdIndex); + } + } + } +} + +/* FinalizeLCD + * This finalizes some CRT2 registers for the very panel used. + * If we have a backup if these registers, we use it; otherwise + * we set the register according to most BIOSes. However, this + * function looks quite different in every BIOS, so you better + * pray that we have a backup... + */ +static void +SiS_FinalizeLCD(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short tempcl,tempch,tempbl,tempbh,tempbx,tempax,temp; + unsigned short resinfo,modeflag; + + if(!(SiS_Pr->SiS_VBType & VB_SISLVDS)) return; + if(SiS_Pr->SiS_ROMNew) return; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->LVDSHL != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,SiS_Pr->LVDSHL); + } + } + + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return; + if(SiS_Pr->UseCustomMode) return; + + switch(SiS_Pr->SiS_CustomT) { + case CUT_COMPAQ1280: + case CUT_COMPAQ12802: + case CUT_CLEVO1400: + case CUT_CLEVO14002: + return; + } + + if(ModeNo <= 0x13) { + resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(IS_SIS650) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4, 0x5f) & 0xf0)) { + if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x02); + } else { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03); + } + } + } + + if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + /* Maybe all panels? */ + if(SiS_Pr->LVDSHL == -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01); + } + return; + } + } + + if(SiS_Pr->SiS_CustomT == CUT_CLEVO10242) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->LVDSHL == -1) { + /* Maybe all panels? */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01); + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + tempch = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4; + if(tempch == 3) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x25); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x1b); + } + } + return; + } + } + } + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); +#ifdef SET_EMI + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); +#endif + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); + } + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(SiS_Pr->LVDSHL == -1) { + /* Maybe ACER only? */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01); + } + } + tempch = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1f,0x76); + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(tempch == 0x03) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x25); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x1b); + } + if(SiS_Pr->Backup && (SiS_Pr->Backup_Mode == ModeNo)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,SiS_Pr->Backup_14); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,SiS_Pr->Backup_15); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,SiS_Pr->Backup_16); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,SiS_Pr->Backup_17); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,SiS_Pr->Backup_18); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,SiS_Pr->Backup_19); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1a,SiS_Pr->Backup_1a); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,SiS_Pr->Backup_1b); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,SiS_Pr->Backup_1c); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,SiS_Pr->Backup_1d); + } else if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { /* 1.10.8w */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,0x90); + if(ModeNo <= 0x13) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x11); + if((resinfo == 0) || (resinfo == 2)) return; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x18); + if((resinfo == 1) || (resinfo == 3)) return; + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02); + if((ModeNo > 0x13) && (resinfo == SIS_RI_1024x768)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02); /* 1.10.7u */ +#if 0 + tempbx = 806; /* 0x326 */ /* other older BIOSes */ + tempbx--; + temp = tempbx & 0xff; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); + temp = (tempbx >> 8) & 0x03; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1d,0xf8,temp); +#endif + } + } else if(ModeNo <= 0x13) { + if(ModeNo <= 1) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x70); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0xff); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x48); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x12); + } + if(!(modeflag & HalfDCLK)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,0x20); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,0x1a); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,0x28); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,0x00); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x4c); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0xdc); + if(ModeNo == 0x12) { + switch(tempch) { + case 0: + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x95); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0xdc); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1a,0x10); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x95); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x48); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x12); + break; + case 2: + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x95); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x48); + break; + case 3: + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x95); + break; + } + } + } + } + } + } else { + tempcl = tempbh = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x01); + tempcl &= 0x0f; + tempbh &= 0x70; + tempbh >>= 4; + tempbl = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x04); + tempbx = (tempbh << 8) | tempbl; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if((resinfo == SIS_RI_1024x768) || (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD))) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + tempbx = 770; + } else { + if(tempbx > 770) tempbx = 770; + if(SiS_Pr->SiS_VGAVDE < 600) { + tempax = 768 - SiS_Pr->SiS_VGAVDE; + tempax >>= 4; /* 1.10.7w; 1.10.6s: 3; */ + if(SiS_Pr->SiS_VGAVDE <= 480) tempax >>= 4; /* 1.10.7w; 1.10.6s: < 480; >>=1; */ + tempbx -= tempax; + } + } + } else return; + } + temp = tempbx & 0xff; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,temp); + temp = ((tempbx & 0xff00) >> 4) | tempcl; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,temp); + } + } +} + +#endif + +/* ================= SiS 300 O.E.M. ================== */ + +#ifdef CONFIG_FB_SIS_300 + +static void +SetOEMLCDData2(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex, + unsigned short RefTabIndex) +{ + unsigned short crt2crtc=0, modeflag, myindex=0; + unsigned char temp; + int i; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + crt2crtc = SiS_Pr->SiS_RefIndex[RefTabIndex].Ext_CRT2CRTC; + } + + crt2crtc &= 0x3f; + + if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xdf); + } + + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + if(modeflag & HalfDCLK) myindex = 1; + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + for(i=0; i<7; i++) { + if(barco_p1[myindex][crt2crtc][i][0]) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port, + barco_p1[myindex][crt2crtc][i][0], + barco_p1[myindex][crt2crtc][i][2], + barco_p1[myindex][crt2crtc][i][1]); + } + } + } + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + if(temp & 0x80) { + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x18); + temp++; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp); + } + } +} + +static unsigned short +GetOEMLCDPtr(struct SiS_Private *SiS_Pr, int Flag) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short tempbx=0,romptr=0; + static const unsigned char customtable300[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff + }; + static const unsigned char customtable630[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff + }; + + if(SiS_Pr->ChipType == SIS_300) { + + tempbx = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0x0f; + if(SiS_Pr->SiS_VBType & VB_SIS301) tempbx &= 0x07; + tempbx -= 2; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 4; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 3; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x235] & 0x80) { + tempbx = SiS_Pr->SiS_LCDTypeInfo; + if(Flag) { + romptr = SISGETROMW(0x255); + if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo]; + else tempbx = customtable300[SiS_Pr->SiS_LCDTypeInfo]; + if(tempbx == 0xFF) return 0xFFFF; + } + tempbx <<= 1; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++; + } + } + + } else { + + if(Flag) { + if(SiS_Pr->SiS_UseROM) { + romptr = SISGETROMW(0x255); + if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo]; + else tempbx = 0xff; + } else { + tempbx = customtable630[SiS_Pr->SiS_LCDTypeInfo]; + } + if(tempbx == 0xFF) return 0xFFFF; + tempbx <<= 2; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempbx += 2; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + return tempbx; + } + tempbx = SiS_Pr->SiS_LCDTypeInfo << 2; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempbx += 2; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + + } + + return tempbx; +} + +static void +SetOEMLCDDelay(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,romptr=0; + + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x237] & 0x01)) return; + if(!(ROMAddr[0x237] & 0x02)) return; + romptr = SISGETROMW(0x24b); + } + + /* The Panel Compensation Delay should be set according to tables + * here. Unfortunately, various BIOS versions don't care about + * a uniform way using eg. ROM byte 0x220, but use different + * hard coded delays (0x04, 0x20, 0x18) in SetGroup1(). + * Thus we don't set this if the user selected a custom pdc or if + * we otherwise detected a valid pdc. + */ + if(SiS_Pr->PDC != -1) return; + + temp = GetOEMLCDPtr(SiS_Pr, 0); + + if(SiS_Pr->UseCustomMode) + index = 0; + else + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex; + + if(SiS_Pr->ChipType != SIS_300) { + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = SiS300_OEMLCDDelay2[temp][index]; + } else { + temp = SiS300_OEMLCDDelay3[temp][index]; + } + } + } else { + if(SiS_Pr->SiS_UseROM && (ROMAddr[0x235] & 0x80)) { + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + temp = SiS300_OEMLCDDelay5[temp][index]; + } + } else { + if(SiS_Pr->SiS_UseROM) { + romptr = ROMAddr[0x249] | (ROMAddr[0x24a] << 8); + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + temp = SiS300_OEMLCDDelay4[temp][index]; + } + } else { + temp = SiS300_OEMLCDDelay4[temp][index]; + } + } + } + temp &= 0x3c; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* index 0A D[6:4] */ +} + +static void +SetOEMLCDData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ +#if 0 /* Unfinished; Data table missing */ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp; + + if((SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x237] & 0x01)) return; + if(!(ROMAddr[0x237] & 0x04)) return; + /* No rom pointer in BIOS header! */ + } + + temp = GetOEMLCDPtr(SiS_Pr, 1); + if(temp == 0xFFFF) return; + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex]._VB_LCDHIndex; + for(i=0x14, j=0; i<=0x17; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,i,SiS300_LCDHData[temp][index][j]); + } + SiS_SetRegANDOR(SiS_SiS_Part1Port,0x1a, 0xf8, (SiS300_LCDHData[temp][index][j] & 0x07)); + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex]._VB_LCDVIndex; + SiS_SetReg(SiS_SiS_Part1Port,0x18, SiS300_LCDVData[temp][index][0]); + SiS_SetRegANDOR(SiS_SiS_Part1Port,0x19, 0xF0, SiS300_LCDVData[temp][index][1]); + SiS_SetRegANDOR(SiS_SiS_Part1Port,0x1A, 0xC7, (SiS300_LCDVData[temp][index][2] & 0x38)); + for(i=0x1b, j=3; i<=0x1d; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,i,SiS300_LCDVData[temp][index][j]); + } +#endif +} + +static unsigned short +GetOEMTVPtr(struct SiS_Private *SiS_Pr) +{ + unsigned short index; + + index = 0; + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) index += 4; + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) index += 2; + else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) index += 3; + else if(SiS_Pr->SiS_TVMode & TVSetPAL) index += 1; + } else { + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) index += 2; + if(SiS_Pr->SiS_TVMode & TVSetPAL) index += 1; + } + return index; +} + +static void +SetOEMTVDelay(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,romptr=0; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x238] & 0x01)) return; + if(!(ROMAddr[0x238] & 0x02)) return; + romptr = SISGETROMW(0x241); + } + + temp = GetOEMTVPtr(SiS_Pr); + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVDelayIndex; + + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = SiS300_OEMTVDelay301[temp][index]; + } else { + temp = SiS300_OEMTVDelayLVDS[temp][index]; + } + } + temp &= 0x3c; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); +} + +static void +SetOEMAntiFlicker(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,romptr=0; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x238] & 0x01)) return; + if(!(ROMAddr[0x238] & 0x04)) return; + romptr = SISGETROMW(0x243); + } + + temp = GetOEMTVPtr(SiS_Pr); + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVFlickerIndex; + + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += index; + temp = ROMAddr[romptr]; + } else { + temp = SiS300_OEMTVFlicker[temp][index]; + } + temp &= 0x70; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8F,temp); +} + +static void +SetOEMPhaseIncr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,i,j,temp,romptr=0; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) return; + + if(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSetNTSCJ | TVSetPALM | TVSetPALN)) return; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x238] & 0x01)) return; + if(!(ROMAddr[0x238] & 0x08)) return; + romptr = SISGETROMW(0x245); + } + + temp = GetOEMTVPtr(SiS_Pr); + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex; + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + for(i=0x31, j=0; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Phase2[temp][index][j]); + } + } else { + if(romptr) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += (index * 4); + for(i=0x31, j=0; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]); + } + } else { + for(i=0x31, j=0; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Phase1[temp][index][j]); + } + } + } +} + +static void +SetOEMYFilter(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,i,j,romptr=0; + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSCART | SetCRT2ToHiVision | SetCRT2ToYPbPr525750)) return; + + if(SiS_Pr->SiS_UseROM) { + if(!(ROMAddr[0x238] & 0x01)) return; + if(!(ROMAddr[0x238] & 0x10)) return; + romptr = SISGETROMW(0x247); + } + + temp = GetOEMTVPtr(SiS_Pr); + + if(SiS_Pr->SiS_TVMode & TVSetPALM) temp = 8; + else if(SiS_Pr->SiS_TVMode & TVSetPALN) temp = 9; + /* NTSCJ uses NTSC filters */ + + index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex; + + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]); + } + for(i=0x48; i<=0x4A; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]); + } + } else { + if((romptr) && (!(SiS_Pr->SiS_TVMode & (TVSetPALM|TVSetPALN)))) { + romptr += (temp * 2); + romptr = SISGETROMW(romptr); + romptr += (index * 4); + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]); + } + } else { + for(i=0x35, j=0; i<=0x38; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter1[temp][index][j]); + } + } + } +} + +static unsigned short +SiS_SearchVBModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo) +{ + unsigned short ModeIdIndex; + unsigned char VGAINFO = SiS_Pr->SiS_VGAINFO; + + if(*ModeNo <= 5) *ModeNo |= 1; + + for(ModeIdIndex=0; ; ModeIdIndex++) { + if(SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == *ModeNo) break; + if(SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == 0xFF) return 0; + } + + if(*ModeNo != 0x07) { + if(*ModeNo > 0x03) return ModeIdIndex; + if(VGAINFO & 0x80) return ModeIdIndex; + ModeIdIndex++; + } + + if(VGAINFO & 0x10) ModeIdIndex++; /* 400 lines */ + /* else 350 lines */ + return ModeIdIndex; +} + +static void +SiS_OEM300Setting(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefTableIndex) +{ + unsigned short OEMModeIdIndex = 0; + + if(!SiS_Pr->UseCustomMode) { + OEMModeIdIndex = SiS_SearchVBModeID(SiS_Pr,&ModeNo); + if(!(OEMModeIdIndex)) return; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SetOEMLCDDelay(SiS_Pr, ModeNo, OEMModeIdIndex); + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + SetOEMLCDData(SiS_Pr, ModeNo, OEMModeIdIndex); + } + } + if(SiS_Pr->UseCustomMode) return; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SetOEMTVDelay(SiS_Pr, ModeNo,OEMModeIdIndex); + if(SiS_Pr->SiS_VBType & VB_SISVB) { + SetOEMAntiFlicker(SiS_Pr, ModeNo, OEMModeIdIndex); + SetOEMPhaseIncr(SiS_Pr, ModeNo, OEMModeIdIndex); + SetOEMYFilter(SiS_Pr, ModeNo, OEMModeIdIndex); + } + } +} +#endif + diff --git a/drivers/video/fbdev/sis/init301.h b/drivers/video/fbdev/sis/init301.h new file mode 100644 index 0000000..2112d6d --- /dev/null +++ b/drivers/video/fbdev/sis/init301.h @@ -0,0 +1,456 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Data and prototypes for init301.c + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _INIT301_H_ +#define _INIT301_H_ + +#include "initdef.h" + +#include "vgatypes.h" +#include "vstruct.h" +#ifdef SIS_CP +#undef SIS_CP +#endif +#include <linux/types.h> +#include <asm/io.h> +#include <linux/fb.h> +#include "sis.h" +#include <video/sisfb.h> + +static const unsigned char SiS_YPbPrTable[3][64] = { + { + 0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c, + 0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b, + 0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17, + 0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02, + 0x03,0x0a,0x65,0x9d /*0x8d*/,0x08,0x92,0x8f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x53 /*0x50*/, + 0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00 + }, + { + 0x33,0x06,0x06,0x09,0x0b,0x0c,0x0c,0x0c, + 0x98,0x0a,0x01,0x0d,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, + 0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4f,0x13, + 0xad,0x11,0xad,0x1d,0x40,0x8a,0x3d,0xb8, + 0x51,0x5e,0x60,0x49,0x7d,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x4e, + 0x43,0x41,0x11,0x00,0xfc,0xff,0x32,0x00 + }, + { +#if 0 /* OK, but sticks to left edge */ + 0x13,0x1d,0xe8,0x09,0x09,0xed,0x0c,0x0c, + 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, + 0xed,0x50,0x70,0x9f,0x16,0x59,0x21 /*0x2b*/,0x13, + 0x27,0x0b,0x27,0xfc,0x30,0x27,0x1c,0xb0, + 0x4b,0x4b,0x65 /*0x6f*/,0x2f,0x63,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x27, + 0x00,0x40,0x11,0x00,0xfc,0xff,0x32,0x00 +#endif +#if 1 /* Perfect */ + 0x23,0x2d,0xe8,0x09,0x09,0xed,0x0c,0x0c, + 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, + 0xed,0x50,0x70,0x9f,0x16,0x59,0x60,0x13, + 0x27,0x0b,0x27,0xfc,0x30,0x27,0x1c,0xb0, + 0x4b,0x4b,0x6f,0x2f,0x63,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x73, + 0x00,0x40,0x11,0x00,0xfc,0xff,0x32,0x00 +#endif + } +}; + +static const unsigned char SiS_TVPhase[] = +{ + 0x21,0xED,0xBA,0x08, /* 0x00 SiS_NTSCPhase */ + 0x2A,0x05,0xE3,0x00, /* 0x01 SiS_PALPhase */ + 0x21,0xE4,0x2E,0x9B, /* 0x02 SiS_PALMPhase */ + 0x21,0xF4,0x3E,0xBA, /* 0x03 SiS_PALNPhase */ + 0x1E,0x8B,0xA2,0xA7, + 0x1E,0x83,0x0A,0xE0, /* 0x05 SiS_SpecialPhaseM */ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x21,0xF0,0x7B,0xD6, /* 0x08 SiS_NTSCPhase2 */ + 0x2A,0x09,0x86,0xE9, /* 0x09 SiS_PALPhase2 */ + 0x21,0xE6,0xEF,0xA4, /* 0x0a SiS_PALMPhase2 */ + 0x21,0xF6,0x94,0x46, /* 0x0b SiS_PALNPhase2 */ + 0x1E,0x8B,0xA2,0xA7, + 0x1E,0x83,0x0A,0xE0, /* 0x0d SiS_SpecialPhaseM */ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x1e,0x8c,0x5c,0x7a, /* 0x10 SiS_SpecialPhase */ + 0x25,0xd4,0xfd,0x5e /* 0x11 SiS_SpecialPhaseJ */ +}; + +static const unsigned char SiS_HiTVGroup3_1[] = { + 0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x13, + 0xb1, 0x41, 0x62, 0x62, 0xff, 0xf4, 0x45, 0xa6, + 0x25, 0x2f, 0x67, 0xf6, 0xbf, 0xff, 0x8e, 0x20, + 0xac, 0xda, 0x60, 0xfe, 0x6a, 0x9a, 0x06, 0x10, + 0xd1, 0x04, 0x18, 0x0a, 0xff, 0x80, 0x00, 0x80, + 0x3b, 0x77, 0x00, 0xef, 0xe0, 0x10, 0xb0, 0xe0, + 0x10, 0x4f, 0x0f, 0x0f, 0x05, 0x0f, 0x08, 0x6e, + 0x1a, 0x1f, 0x25, 0x2a, 0x4c, 0xaa, 0x01 +}; + +static const unsigned char SiS_HiTVGroup3_2[] = { + 0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x7a, + 0x54, 0x41, 0xe7, 0xe7, 0xff, 0xf4, 0x45, 0xa6, + 0x25, 0x2f, 0x67, 0xf6, 0xbf, 0xff, 0x8e, 0x20, + 0xac, 0x6a, 0x60, 0x2b, 0x52, 0xcd, 0x61, 0x10, + 0x51, 0x04, 0x18, 0x0a, 0x1f, 0x80, 0x00, 0x80, + 0xff, 0xa4, 0x04, 0x2b, 0x94, 0x21, 0x72, 0x94, + 0x26, 0x05, 0x01, 0x0f, 0xed, 0x0f, 0x0a, 0x64, + 0x18, 0x1d, 0x23, 0x28, 0x4c, 0xaa, 0x01 +}; + +/* 301C / 302ELV extended Part2 TV registers (4 tap scaler) */ + +static const unsigned char SiS_Part2CLVX_1[] = { + 0x00,0x00, + 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F,0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, + 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E,0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, + 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C,0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, + 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C,0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E +}; + +static const unsigned char SiS_Part2CLVX_2[] = { + 0x00,0x00, + 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F,0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, + 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E,0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, + 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C,0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, + 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C,0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E +}; + +static const unsigned char SiS_Part2CLVX_3[] = { /* NTSC, 525i, 525p */ + 0xE0,0x01, + 0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D,0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D, + 0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C,0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C, + 0x7D,0x13,0x13,0x7D,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0E,0x18,0x7E, + 0x7D,0x0C,0x19,0x7E,0x7D,0x0A,0x19,0x00,0x7D,0x08,0x1A,0x01,0x7E,0x06,0x1A,0x02, + 0x58,0x02, + 0x07,0x14,0x07,0x7E,0x06,0x14,0x09,0x7D,0x05,0x14,0x0A,0x7D,0x04,0x13,0x0B,0x7E, + 0x03,0x13,0x0C,0x7E,0x02,0x12,0x0D,0x7F,0x01,0x12,0x0E,0x7F,0x01,0x11,0x0F,0x7F, + 0x00,0x10,0x10,0x00,0x7F,0x0F,0x11,0x01,0x7F,0x0E,0x12,0x01,0x7E,0x0D,0x12,0x03, + 0x7E,0x0C,0x13,0x03,0x7E,0x0B,0x13,0x04,0x7E,0x0A,0x14,0x04,0x7D,0x09,0x14,0x06, + 0x00,0x03, + 0x09,0x0F,0x09,0x7F,0x08,0x0F,0x09,0x00,0x07,0x0F,0x0A,0x00,0x06,0x0F,0x0A,0x01, + 0x06,0x0E,0x0B,0x01,0x05,0x0E,0x0B,0x02,0x04,0x0E,0x0C,0x02,0x04,0x0D,0x0C,0x03, + 0x03,0x0D,0x0D,0x03,0x02,0x0C,0x0D,0x05,0x02,0x0C,0x0E,0x04,0x01,0x0B,0x0E,0x06, + 0x01,0x0B,0x0E,0x06,0x00,0x0A,0x0F,0x07,0x00,0x0A,0x0F,0x07,0x00,0x09,0x0F,0x08, + 0xFF,0xFF +}; + +static const unsigned char SiS_Part2CLVX_4[] = { /* PAL */ + 0x58,0x02, + 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E,0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, + 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C,0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, + 0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E,0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E, + 0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01,0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04, + 0x00,0x03, + 0x08,0x12,0x08,0x7E,0x07,0x12,0x09,0x7E,0x06,0x12,0x0A,0x7E,0x05,0x11,0x0B,0x7F, + 0x04,0x11,0x0C,0x7F,0x03,0x11,0x0C,0x00,0x03,0x10,0x0D,0x00,0x02,0x0F,0x0E,0x01, + 0x01,0x0F,0x0F,0x01,0x01,0x0E,0x0F,0x02,0x00,0x0D,0x10,0x03,0x7F,0x0C,0x11,0x04, + 0x7F,0x0C,0x11,0x04,0x7F,0x0B,0x11,0x05,0x7E,0x0A,0x12,0x06,0x7E,0x09,0x12,0x07, + 0x40,0x02, + 0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E,0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D, + 0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D,0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C, + 0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0D,0x18,0x7F, + 0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00,0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02, + 0xFF,0xFF +}; + +static const unsigned char SiS_Part2CLVX_5[] = { /* 750p */ + 0x00,0x03, + 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E,0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, + 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C,0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, + 0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E,0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E, + 0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01,0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04, + 0xFF,0xFF +}; + +static const unsigned char SiS_Part2CLVX_6[] = { /* 1080i */ + 0x00,0x04, + 0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E,0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D, + 0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D,0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C, + 0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0D,0x18,0x7F, + 0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00,0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02, + 0xFF,0xFF, +}; + +#ifdef CONFIG_FB_SIS_315 +/* 661 et al LCD data structure (2.03.00) */ +static const unsigned char SiS_LCDStruct661[] = { + /* 1024x768 */ +/* type|CR37| HDE | VDE | HT | VT | hss | hse */ + 0x02,0xC0,0x00,0x04,0x00,0x03,0x40,0x05,0x26,0x03,0x10,0x00,0x88, + 0x00,0x02,0x00,0x06,0x00,0x41,0x5A,0x64,0x00,0x00,0x00,0x00,0x04, + /* | vss | vse |clck| clock |CRT2DataP|CRT2DataP|idx */ + /* VESA non-VESA noscale */ + /* 1280x1024 */ + 0x03,0xC0,0x00,0x05,0x00,0x04,0x98,0x06,0x2A,0x04,0x30,0x00,0x70, + 0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x00,0x00,0x00,0x00,0x08, + /* 1400x1050 */ + 0x09,0x20,0x78,0x05,0x1A,0x04,0x98,0x06,0x2A,0x04,0x18,0x00,0x38, + 0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x00,0x00,0x00,0x00,0x09, + /* 1600x1200 */ + 0x0B,0xE0,0x40,0x06,0xB0,0x04,0x70,0x08,0xE2,0x04,0x40,0x00,0xC0, + 0x00,0x01,0x00,0x03,0x00,0xA2,0x70,0x24,0x00,0x00,0x00,0x00,0x0A, + /* 1280x768 (_2) */ + 0x0A,0xE0,0x00,0x05,0x00,0x03,0x7C,0x06,0x26,0x03,0x30,0x00,0x70, + 0x00,0x03,0x00,0x06,0x00,0x4D,0xC8,0x48,0x00,0x00,0x00,0x00,0x06, + /* 1280x720 */ + 0x0E,0xE0,0x00,0x05,0xD0,0x02,0x80,0x05,0x26,0x03,0x10,0x00,0x20, + 0x00,0x01,0x00,0x06,0x00,0x45,0x9C,0x62,0x00,0x00,0x00,0x00,0x05, + /* 1280x800 (_2) */ + 0x0C,0xE0,0x00,0x05,0x20,0x03,0x10,0x06,0x2C,0x03,0x30,0x00,0x70, + 0x00,0x04,0x00,0x03,0x00,0x49,0xCE,0x1E,0x00,0x00,0x00,0x00,0x09, + /* 1680x1050 */ + 0x0D,0xE0,0x90,0x06,0x1A,0x04,0x6C,0x07,0x2A,0x04,0x1A,0x00,0x4C, + 0x00,0x03,0x00,0x06,0x00,0x79,0xBE,0x44,0x00,0x00,0x00,0x00,0x06, + /* 1280x800_3 */ + 0x0C,0xE0,0x00,0x05,0x20,0x03,0xAA,0x05,0x2E,0x03,0x30,0x00,0x50, + 0x00,0x04,0x00,0x03,0x00,0x47,0xA9,0x10,0x00,0x00,0x00,0x00,0x07, + /* 800x600 */ + 0x01,0xC0,0x20,0x03,0x58,0x02,0x20,0x04,0x74,0x02,0x2A,0x00,0x80, + 0x00,0x06,0x00,0x04,0x00,0x28,0x63,0x4B,0x00,0x00,0x00,0x00,0x00, + /* 1280x854 */ + 0x08,0xE0,0x00,0x05,0x56,0x03,0x80,0x06,0x5d,0x03,0x10,0x00,0x70, + 0x00,0x01,0x00,0x03,0x00,0x54,0x75,0x13,0x00,0x00,0x00,0x00,0x08 +}; +#endif + +#ifdef CONFIG_FB_SIS_300 +static unsigned char SiS300_TrumpionData[14][80] = { + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x0B,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x10,0x00,0x00,0x04,0x23, + 0x00,0x00,0x03,0x28,0x03,0x10,0x05,0x08,0x40,0x10,0x00,0x10,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xBC,0x01,0xFF,0x03,0xFF,0x19,0x01,0x00,0x05,0x09,0x04,0x04,0x05, + 0x04,0x0C,0x09,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5A,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x27,0x00,0x80,0x02, + 0x20,0x03,0x07,0x00,0x5E,0x01,0x0D,0x02,0x60,0x0C,0x30,0x11,0x00,0x00,0x04,0x23, + 0x00,0x00,0x03,0x80,0x03,0x28,0x06,0x08,0x40,0x11,0x00,0x11,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0x90,0x01,0xFF,0x0F,0xF4,0x19,0x01,0x00,0x05,0x01,0x00,0x04,0x05, + 0x04,0x0C,0x02,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEC,0x57,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x8A,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xD9,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x59,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x72,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xDA,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x00,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x16,0x00,0xE0,0x01,0x0D,0x02,0x60,0x0C,0x30,0x98,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x45,0x03,0x48,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xF4,0x01,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x05,0x01,0x00,0x05,0x05, + 0x04,0x0C,0x08,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xBF,0x00,0x20,0x03, + 0x20,0x04,0x0D,0x00,0x58,0x02,0x71,0x02,0x80,0x0C,0x30,0x9A,0x00,0xFA,0x03,0x1D, + 0x00,0x01,0x03,0x22,0x03,0x28,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x1D,0x00,0x1D, + 0x03,0x11,0x60,0x39,0x03,0x40,0x05,0xF4,0x18,0x07,0x02,0x06,0x04,0x01,0x06,0x0B, + 0x02,0x0A,0x20,0x19,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xEF,0x00,0x00,0x04, + 0x40,0x05,0x13,0x00,0x00,0x03,0x26,0x03,0x88,0x0C,0x30,0x90,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x24,0x03,0x28,0x06,0x08,0x40,0x90,0x00,0x90,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0x40,0x05,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x08,0x01,0x00,0x08,0x01, + 0x00,0x08,0x01,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }, + /* variant 2 */ + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x15,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x18,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x44,0x03,0x28,0x06,0x08,0x40,0x18,0x00,0x18,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xA6,0x01,0xFF,0x03,0xFF,0x19,0x01,0x00,0x05,0x13,0x04,0x04,0x05, + 0x04,0x0C,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x15,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x18,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x44,0x03,0x28,0x06,0x08,0x40,0x18,0x00,0x18,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xA6,0x01,0xFF,0x03,0xFF,0x19,0x01,0x00,0x05,0x13,0x04,0x04,0x05, + 0x04,0x0C,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x8A,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xDA,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x72,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xDA,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x00,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x16,0x00,0xE0,0x01,0x0D,0x02,0x60,0x0C,0x30,0x98,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x45,0x03,0x48,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xF4,0x01,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x05,0x01,0x00,0x05,0x05, + 0x04,0x0C,0x08,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEA,0x58,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0xBF,0x00,0x20,0x03, + 0x20,0x04,0x0D,0x00,0x58,0x02,0x71,0x02,0x80,0x0C,0x30,0x9A,0x00,0xFA,0x03,0x1D, + 0x00,0x01,0x03,0x22,0x03,0x28,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x1D,0x00,0x1D, + 0x03,0x11,0x60,0x39,0x03,0x40,0x05,0xF4,0x18,0x07,0x02,0x06,0x04,0x01,0x06,0x0B, + 0x02,0x0A,0x20,0x19,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEA,0x58,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0xEF,0x00,0x00,0x04, + 0x40,0x05,0x13,0x00,0x00,0x03,0x26,0x03,0x88,0x0C,0x30,0x90,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x24,0x03,0x28,0x06,0x08,0x40,0x90,0x00,0x90,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0x40,0x05,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x08,0x01,0x00,0x08,0x01, + 0x00,0x08,0x01,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEA,0x58,0x01,0xBE,0x01,0x00 } +}; +#endif + +void SiS_UnLockCRT2(struct SiS_Private *SiS_Pr); +void SiS_EnableCRT2(struct SiS_Private *SiS_Pr); +unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); +void SiS_WaitRetrace1(struct SiS_Private *SiS_Pr); +bool SiS_IsDualEdge(struct SiS_Private *SiS_Pr); +bool SiS_IsVAMode(struct SiS_Private *SiS_Pr); +void SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, int checkcrt2mode); +void SiS_SetYPbPr(struct SiS_Private *SiS_Pr); +void SiS_SetTVMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +void SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +unsigned short SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex); +unsigned short SiS_GetResInfo(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned short ModeIdIndex); +void SiS_DisableBridge(struct SiS_Private *SiS_Pr); +bool SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +void SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr); +void SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr); + +void SiS_SetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempax); +void SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +unsigned short SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short tempax); +void SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg, + unsigned char orval,unsigned short andval); +#ifdef CONFIG_FB_SIS_315 +static void SiS_Chrontel701xOn(struct SiS_Private *SiS_Pr); +static void SiS_Chrontel701xOff(struct SiS_Private *SiS_Pr); +static void SiS_ChrontelInitTVVSync(struct SiS_Private *SiS_Pr); +static void SiS_ChrontelDoSomething1(struct SiS_Private *SiS_Pr); +void SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr); +void SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr); +#endif /* 315 */ + +#ifdef CONFIG_FB_SIS_300 +static bool SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr); +void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo); +#endif + +void SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime); +unsigned short SiS_ReadDDC1Bit(struct SiS_Private *SiS_Pr); +unsigned short SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, + unsigned short adaptnum, unsigned short DDCdatatype, + unsigned char *buffer, unsigned int VBFlags2); + +static unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, + int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype, + bool checkcr32, unsigned int VBFlags2); +static unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr); +static unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, + unsigned char *buffer); +static void SiS_SetSwitchDDC2(struct SiS_Private *SiS_Pr); +static unsigned short SiS_SetStart(struct SiS_Private *SiS_Pr); +static unsigned short SiS_SetStop(struct SiS_Private *SiS_Pr); +static unsigned short SiS_SetSCLKLow(struct SiS_Private *SiS_Pr); +static unsigned short SiS_SetSCLKHigh(struct SiS_Private *SiS_Pr); +static unsigned short SiS_ReadDDC2Data(struct SiS_Private *SiS_Pr); +static unsigned short SiS_WriteDDC2Data(struct SiS_Private *SiS_Pr, unsigned short tempax); +static unsigned short SiS_CheckACK(struct SiS_Private *SiS_Pr); +static unsigned short SiS_WriteDABDDC(struct SiS_Private *SiS_Pr); +static unsigned short SiS_PrepareReadDDC(struct SiS_Private *SiS_Pr); +static unsigned short SiS_PrepareDDC(struct SiS_Private *SiS_Pr); +static void SiS_SendACK(struct SiS_Private *SiS_Pr, unsigned short yesno); +static unsigned short SiS_DoProbeDDC(struct SiS_Private *SiS_Pr); + +#ifdef CONFIG_FB_SIS_300 +static void SiS_OEM300Setting(struct SiS_Private *SiS_Pr, + unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefTabindex); +static void SetOEMLCDData2(struct SiS_Private *SiS_Pr, + unsigned short ModeNo, unsigned short ModeIdIndex,unsigned short RefTableIndex); +#endif +#ifdef CONFIG_FB_SIS_315 +static void SiS_OEM310Setting(struct SiS_Private *SiS_Pr, + unsigned short ModeNo,unsigned short ModeIdIndex, unsigned short RRTI); +static void SiS_OEM661Setting(struct SiS_Private *SiS_Pr, + unsigned short ModeNo,unsigned short ModeIdIndex, unsigned short RRTI); +static void SiS_FinalizeLCD(struct SiS_Private *, unsigned short, unsigned short); +#endif + +extern void SiS_DisplayOff(struct SiS_Private *SiS_Pr); +extern void SiS_DisplayOn(struct SiS_Private *SiS_Pr); +extern bool SiS_SearchModeID(struct SiS_Private *, unsigned short *, unsigned short *); +extern unsigned short SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern unsigned short SiS_GetModePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); +extern unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); +extern unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex); +extern void SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth); +extern unsigned short SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); +extern unsigned short SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); +#ifdef CONFIG_FB_SIS_300 +extern void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *tempbx, + unsigned short *tempcl); +extern unsigned short SiS_GetFIFOThresholdB300(unsigned short tempbx, unsigned short tempcl); +extern unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index); +extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg); +extern unsigned int sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg); +#endif + +#endif diff --git a/drivers/video/fbdev/sis/initdef.h b/drivers/video/fbdev/sis/initdef.h new file mode 100644 index 0000000..264b55a --- /dev/null +++ b/drivers/video/fbdev/sis/initdef.h @@ -0,0 +1,708 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Global definitions for init.c and init301.c + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _INITDEF_ +#define _INITDEF_ + +#define IS_SIS330 (SiS_Pr->ChipType == SIS_330) +#define IS_SIS550 (SiS_Pr->ChipType == SIS_550) +#define IS_SIS650 (SiS_Pr->ChipType == SIS_650) /* All versions, incl 651, M65x */ +#define IS_SIS740 (SiS_Pr->ChipType == SIS_740) +#define IS_SIS651 (SiS_Pr->SiS_SysFlags & (SF_Is651 | SF_Is652)) +#define IS_SISM650 (SiS_Pr->SiS_SysFlags & (SF_IsM650 | SF_IsM652 | SF_IsM653)) +#define IS_SIS65x (IS_SIS651 || IS_SISM650) /* Only special versions of 65x */ +#define IS_SIS661 (SiS_Pr->ChipType == SIS_661) +#define IS_SIS741 (SiS_Pr->ChipType == SIS_741) +#define IS_SIS660 (SiS_Pr->ChipType == SIS_660) +#define IS_SIS760 (SiS_Pr->ChipType == SIS_760) +#define IS_SIS761 (SiS_Pr->ChipType == SIS_761) +#define IS_SIS661741660760 (IS_SIS661 || IS_SIS741 || IS_SIS660 || IS_SIS760 || IS_SIS761) +#define IS_SIS650740 ((SiS_Pr->ChipType >= SIS_650) && (SiS_Pr->ChipType < SIS_330)) +#define IS_SIS550650740 (IS_SIS550 || IS_SIS650740) +#define IS_SIS650740660 (IS_SIS650 || IS_SIS740 || IS_SIS661741660760) +#define IS_SIS550650740660 (IS_SIS550 || IS_SIS650740660) + +#define SISGETROMW(x) (ROMAddr[(x)] | (ROMAddr[(x)+1] << 8)) + +/* SiS_VBType */ +#define VB_SIS301 0x0001 +#define VB_SIS301B 0x0002 +#define VB_SIS302B 0x0004 +#define VB_SIS301LV 0x0008 +#define VB_SIS302LV 0x0010 +#define VB_SIS302ELV 0x0020 +#define VB_SIS301C 0x0040 +#define VB_SIS307T 0x0080 +#define VB_SIS307LV 0x0100 +#define VB_UMC 0x4000 +#define VB_NoLCD 0x8000 +#define VB_SIS30xB (VB_SIS301B | VB_SIS301C | VB_SIS302B | VB_SIS307T) +#define VB_SIS30xC (VB_SIS301C | VB_SIS307T) +#define VB_SISTMDS (VB_SIS301 | VB_SIS301B | VB_SIS301C | VB_SIS302B | VB_SIS307T) +#define VB_SISLVDS (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SIS30xBLV (VB_SIS30xB | VB_SISLVDS) +#define VB_SIS30xCLV (VB_SIS30xC | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISVB (VB_SIS301 | VB_SIS30xBLV) +#define VB_SISLCDA (VB_SIS302B | VB_SIS301C | VB_SIS307T | VB_SISLVDS) +#define VB_SISTMDSLCDA (VB_SIS301C | VB_SIS307T) +#define VB_SISPART4SCALER (VB_SIS301C | VB_SIS307T | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISHIVISION (VB_SIS301 | VB_SIS301B | VB_SIS302B) +#define VB_SISYPBPR (VB_SIS301C | VB_SIS307T | VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISTAP4SCALER (VB_SIS301C | VB_SIS307T | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISPART4OVERFLOW (VB_SIS301C | VB_SIS307T | VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISPWD (VB_SIS301C | VB_SIS307T | VB_SISLVDS) +#define VB_SISEMI (VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISPOWER (VB_SIS301C | VB_SIS307T | VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISDUALLINK (VB_SIS302LV | VB_SIS302ELV | VB_SIS307T | VB_SIS307LV) +#define VB_SISVGA2 VB_SISTMDS +#define VB_SISRAMDAC202 (VB_SIS301C | VB_SIS307T) + +/* VBInfo */ +#define SetSimuScanMode 0x0001 /* CR 30 */ +#define SwitchCRT2 0x0002 +#define SetCRT2ToAVIDEO 0x0004 +#define SetCRT2ToSVIDEO 0x0008 +#define SetCRT2ToSCART 0x0010 +#define SetCRT2ToLCD 0x0020 +#define SetCRT2ToRAMDAC 0x0040 +#define SetCRT2ToHiVision 0x0080 /* for SiS bridge */ +#define SetCRT2ToCHYPbPr SetCRT2ToHiVision /* for Chrontel */ +#define SetNTSCTV 0x0000 /* CR 31 */ +#define SetPALTV 0x0100 /* Deprecated here, now in TVMode */ +#define SetInSlaveMode 0x0200 +#define SetNotSimuMode 0x0400 +#define SetNotSimuTVMode SetNotSimuMode +#define SetDispDevSwitch 0x0800 +#define SetCRT2ToYPbPr525750 0x0800 +#define LoadDACFlag 0x1000 +#define DisableCRT2Display 0x2000 +#define DriverMode 0x4000 +#define HotKeySwitch 0x8000 +#define SetCRT2ToLCDA 0x8000 + +/* v-- Needs change in sis_vga.c if changed (GPIO) --v */ +#define SetCRT2ToTV (SetCRT2ToYPbPr525750|SetCRT2ToHiVision|SetCRT2ToSCART|SetCRT2ToSVIDEO|SetCRT2ToAVIDEO) +#define SetCRT2ToTVNoYPbPrHiVision (SetCRT2ToSCART | SetCRT2ToSVIDEO | SetCRT2ToAVIDEO) +#define SetCRT2ToTVNoHiVision (SetCRT2ToYPbPr525750 | SetCRT2ToSCART | SetCRT2ToSVIDEO | SetCRT2ToAVIDEO) + +/* SiS_ModeType */ +#define ModeText 0x00 +#define ModeCGA 0x01 +#define ModeEGA 0x02 +#define ModeVGA 0x03 +#define Mode15Bpp 0x04 +#define Mode16Bpp 0x05 +#define Mode24Bpp 0x06 +#define Mode32Bpp 0x07 + +#define ModeTypeMask 0x07 +#define IsTextMode 0x07 + +#define DACInfoFlag 0x0018 +#define MemoryInfoFlag 0x01E0 +#define MemorySizeShift 5 + +/* modeflag */ +#define Charx8Dot 0x0200 +#define LineCompareOff 0x0400 +#define CRT2Mode 0x0800 +#define HalfDCLK 0x1000 +#define NoSupportSimuTV 0x2000 +#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ +#define DoubleScanMode 0x8000 + +/* Infoflag */ +#define SupportTV 0x0008 +#define SupportTV1024 0x0800 +#define SupportCHTV 0x0800 +#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ +#define SupportHiVision 0x0010 +#define SupportYPbPr750p 0x1000 +#define SupportLCD 0x0020 +#define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ +#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ +#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ +#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ +#define InterlaceMode 0x0080 +#define SyncPP 0x0000 +#define HaveWideTiming 0x2000 /* Have specific wide- and non-wide timing */ +#define SyncPN 0x4000 +#define SyncNP 0x8000 +#define SyncNN 0xc000 + +/* SetFlag */ +#define ProgrammingCRT2 0x0001 +#define LowModeTests 0x0002 +/* #define TVSimuMode 0x0002 - deprecated */ +/* #define RPLLDIV2XO 0x0004 - deprecated */ +#define LCDVESATiming 0x0008 +#define EnableLVDSDDA 0x0010 +#define SetDispDevSwitchFlag 0x0020 +#define CheckWinDos 0x0040 +#define SetDOSMode 0x0080 + +/* TVMode flag */ +#define TVSetPAL 0x0001 +#define TVSetNTSCJ 0x0002 +#define TVSetPALM 0x0004 +#define TVSetPALN 0x0008 +#define TVSetCHOverScan 0x0010 +#define TVSetYPbPr525i 0x0020 /* new 0x10 */ +#define TVSetYPbPr525p 0x0040 /* new 0x20 */ +#define TVSetYPbPr750p 0x0080 /* new 0x40 */ +#define TVSetHiVision 0x0100 /* new 0x80; = 1080i, software-wise identical */ +#define TVSetTVSimuMode 0x0200 /* new 0x200, prev. 0x800 */ +#define TVRPLLDIV2XO 0x0400 /* prev 0x1000 */ +#define TVSetNTSC1024 0x0800 /* new 0x100, prev. 0x2000 */ +#define TVSet525p1024 0x1000 /* TW */ +#define TVAspect43 0x2000 +#define TVAspect169 0x4000 +#define TVAspect43LB 0x8000 + +/* YPbPr flag (>=315, <661; converted to TVMode) */ +#define YPbPr525p 0x0001 +#define YPbPr750p 0x0002 +#define YPbPr525i 0x0004 +#define YPbPrHiVision 0x0008 +#define YPbPrModeMask (YPbPr750p | YPbPr525p | YPbPr525i | YPbPrHiVision) + +/* SysFlags (to identify special versions) */ +#define SF_Is651 0x0001 +#define SF_IsM650 0x0002 +#define SF_Is652 0x0004 +#define SF_IsM652 0x0008 +#define SF_IsM653 0x0010 +#define SF_IsM661 0x0020 +#define SF_IsM741 0x0040 +#define SF_IsM760 0x0080 +#define SF_760UMA 0x4000 /* 76x: We have UMA */ +#define SF_760LFB 0x8000 /* 76x: We have LFB */ + +/* CR32 (Newer 630, and 315 series) + + [0] VB connected with CVBS + [1] VB connected with SVHS + [2] VB connected with SCART + [3] VB connected with LCD + [4] VB connected with CRT2 (secondary VGA) + [5] CRT1 monitor is connected + [6] VB connected with Hi-Vision TV + [7] <= 330: VB connected with DVI combo connector + >= 661: VB connected to YPbPr +*/ + +/* CR35 (300 series only) */ +#define TVOverScan 0x10 +#define TVOverScanShift 4 + +/* CR35 (661 series only) + [0] 1 = PAL, 0 = NTSC + [1] 1 = NTSC-J (if D0 = 0) + [2] 1 = PALM (if D0 = 1) + [3] 1 = PALN (if D0 = 1) + [4] 1 = Overscan (Chrontel only) + [7:5] (only if D2 in CR38 is set) + 000 525i + 001 525p + 010 750p + 011 1080i (or HiVision on 301, 301B) +*/ + +/* CR37 + [0] Set 24/18 bit (0/1) RGB to LVDS/TMDS transmitter (set by BIOS) + [3:1] External chip + 300 series: + 001 SiS301 (never seen) + 010 LVDS + 011 LVDS + Tumpion Zurac + 100 LVDS + Chrontel 7005 + 110 Chrontel 7005 + 315/330 series + 001 SiS30x (never seen) + 010 LVDS + 011 LVDS + Chrontel 7019 + 660 series [2:1] only: + reserved (chip type now in CR38) + All other combinations reserved + [3] 661 only: Pass 1:1 data + [4] LVDS: 0: Panel Link expands / 1: Panel Link does not expand + 30x: 0: Bridge scales / 1: Bridge does not scale = Panel scales (if possible) + [5] LCD polarity select + 0: VESA DMT Standard + 1: EDID 2.x defined + [6] LCD horizontal polarity select + 0: High active + 1: Low active + [7] LCD vertical polarity select + 0: High active + 1: Low active +*/ + +/* CR37: LCDInfo */ +#define LCDRGB18Bit 0x0001 +#define LCDNonExpanding 0x0010 +#define LCDSync 0x0020 +#define LCDPass11 0x0100 /* 0: center screen, 1: Pass 1:1 data */ +#define LCDDualLink 0x0200 + +#define DontExpandLCD LCDNonExpanding +#define LCDNonExpandingShift 4 +#define DontExpandLCDShift LCDNonExpandingShift +#define LCDSyncBit 0x00e0 +#define LCDSyncShift 6 + +/* CR38 (315 series) */ +#define EnableDualEdge 0x01 +#define SetToLCDA 0x02 /* LCD channel A (301C/302B/30x(E)LV and 650+LVDS only) */ +#define EnableCHScart 0x04 /* Scart on Ch7019 (unofficial definition - TW) */ +#define EnableCHYPbPr 0x08 /* YPbPr on Ch7019 (480i HDTV); only on 650/Ch7019 systems */ +#define EnableSiSYPbPr 0x08 /* Enable YPbPr mode (30xLV/301C only) */ +#define EnableYPbPr525i 0x00 /* Enable 525i YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnableYPbPr525p 0x10 /* Enable 525p YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnableYPbPr750p 0x20 /* Enable 750p YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnableYPbPr1080i 0x30 /* Enable 1080i YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnablePALM 0x40 /* 1 = Set PALM */ +#define EnablePALN 0x80 /* 1 = Set PALN */ +#define EnableNTSCJ EnablePALM /* Not BIOS */ + +/* CR38 (661 and later) + D[7:5] 000 No VB + 001 301 series VB + 010 LVDS + 011 Chrontel 7019 + 100 Conexant + D2 Enable YPbPr output (see CR35) + D[1:0] LCDA (like before) +*/ + +#define EnablePALMN 0x40 /* Romflag: 1 = Allow PALM/PALN */ + +/* CR39 (650 only) */ +#define LCDPass1_1 0x01 /* 0: center screen, 1: pass 1:1 data output */ +#define Enable302LV_DualLink 0x04 /* 302LV only; enable dual link */ + +/* CR39 (661 and later) + D[7] LVDS (SiS or third party) + D[1:0] YPbPr Aspect Ratio + 00 4:3 letterbox + 01 4:3 + 10 16:9 + 11 4:3 +*/ + +/* CR3B (651+301C) + D[1:0] YPbPr Aspect Ratio + ? +*/ + +/* CR79 (315/330 series only; not 661 and later) + [3-0] Notify driver + 0001 Mode Switch event (set by BIOS) + 0010 Epansion On/Off event + 0011 TV UnderScan/OverScan event + 0100 Set Brightness event + 0101 Set Contrast event + 0110 Set Mute event + 0111 Set Volume Up/Down event + [4] Enable Backlight Control by BIOS/driver + (set by driver; set means that the BIOS should + not touch the backlight registers because eg. + the driver already switched off the backlight) + [5] PAL/NTSC (set by BIOS) + [6] Expansion On/Off (set by BIOS; copied to CR32[4]) + [7] TV UnderScan/OverScan (set by BIOS) +*/ + +/* CR7C - 661 and later + [7] DualEdge enabled (or: to be enabled) + [6] CRT2 = TV/LCD/VGA enabled (or: to be enabled) + [5] Init done (set at end of SiS_Init) + {4] LVDS LCD capabilities + [3] LVDS LCD capabilities + [2] LVDS LCD capabilities (PWD) + [1] LVDS LCD capabilities (PWD) + [0] LVDS=1, TMDS=0 (SiS or third party) +*/ + +/* CR7E - 661 and later + VBType: + [7] LVDS (third party) + [3] 301C + [2] 302LV + [1] 301LV + [0] 301B +*/ + +/* LCDResInfo */ +#define Panel300_800x600 0x01 /* CR36 */ +#define Panel300_1024x768 0x02 +#define Panel300_1280x1024 0x03 +#define Panel300_1280x960 0x04 +#define Panel300_640x480 0x05 +#define Panel300_1024x600 0x06 +#define Panel300_1152x768 0x07 +#define Panel300_1280x768 0x0a +#define Panel300_Custom 0x0f +#define Panel300_Barco1366 0x10 + +#define Panel310_800x600 0x01 +#define Panel310_1024x768 0x02 +#define Panel310_1280x1024 0x03 +#define Panel310_640x480 0x04 +#define Panel310_1024x600 0x05 +#define Panel310_1152x864 0x06 +#define Panel310_1280x960 0x07 +#define Panel310_1152x768 0x08 /* LVDS only */ +#define Panel310_1400x1050 0x09 +#define Panel310_1280x768 0x0a +#define Panel310_1600x1200 0x0b +#define Panel310_320x240_2 0x0c /* xSTN */ +#define Panel310_320x240_3 0x0d /* xSTN */ +#define Panel310_320x240_1 0x0e /* xSTN - This is fake, can be any */ +#define Panel310_Custom 0x0f + +#define Panel661_800x600 0x01 +#define Panel661_1024x768 0x02 +#define Panel661_1280x1024 0x03 +#define Panel661_640x480 0x04 +#define Panel661_1024x600 0x05 +#define Panel661_1152x864 0x06 +#define Panel661_1280x960 0x07 +#define Panel661_1280x854 0x08 +#define Panel661_1400x1050 0x09 +#define Panel661_1280x768 0x0a +#define Panel661_1600x1200 0x0b +#define Panel661_1280x800 0x0c +#define Panel661_1680x1050 0x0d +#define Panel661_1280x720 0x0e +#define Panel661_Custom 0x0f + +#define Panel_800x600 0x01 /* Unified values */ +#define Panel_1024x768 0x02 /* MUST match BIOS values from 0-e */ +#define Panel_1280x1024 0x03 +#define Panel_640x480 0x04 +#define Panel_1024x600 0x05 +#define Panel_1152x864 0x06 +#define Panel_1280x960 0x07 +#define Panel_1152x768 0x08 /* LVDS only */ +#define Panel_1400x1050 0x09 +#define Panel_1280x768 0x0a /* 30xB/C and LVDS only (BIOS: all) */ +#define Panel_1600x1200 0x0b +#define Panel_1280x800 0x0c /* 661etc (TMDS) */ +#define Panel_1680x1050 0x0d /* 661etc */ +#define Panel_1280x720 0x0e /* 661etc */ +#define Panel_Custom 0x0f /* MUST BE 0x0f (for DVI DDC detection) */ +#define Panel_320x240_1 0x10 /* SiS 550 xSTN */ +#define Panel_Barco1366 0x11 +#define Panel_848x480 0x12 +#define Panel_320x240_2 0x13 /* SiS 550 xSTN */ +#define Panel_320x240_3 0x14 /* SiS 550 xSTN */ +#define Panel_1280x768_2 0x15 /* 30xLV */ +#define Panel_1280x768_3 0x16 /* (unused) */ +#define Panel_1280x800_2 0x17 /* 30xLV */ +#define Panel_856x480 0x18 +#define Panel_1280x854 0x19 /* 661etc */ + +/* Index in ModeResInfo table */ +#define SIS_RI_320x200 0 +#define SIS_RI_320x240 1 +#define SIS_RI_320x400 2 +#define SIS_RI_400x300 3 +#define SIS_RI_512x384 4 +#define SIS_RI_640x400 5 +#define SIS_RI_640x480 6 +#define SIS_RI_800x600 7 +#define SIS_RI_1024x768 8 +#define SIS_RI_1280x1024 9 +#define SIS_RI_1600x1200 10 +#define SIS_RI_1920x1440 11 +#define SIS_RI_2048x1536 12 +#define SIS_RI_720x480 13 +#define SIS_RI_720x576 14 +#define SIS_RI_1280x960 15 +#define SIS_RI_800x480 16 +#define SIS_RI_1024x576 17 +#define SIS_RI_1280x720 18 +#define SIS_RI_856x480 19 +#define SIS_RI_1280x768 20 +#define SIS_RI_1400x1050 21 +#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ +#define SIS_RI_848x480 23 +#define SIS_RI_1360x768 24 +#define SIS_RI_1024x600 25 +#define SIS_RI_1152x768 26 +#define SIS_RI_768x576 27 +#define SIS_RI_1360x1024 28 +#define SIS_RI_1680x1050 29 +#define SIS_RI_1280x800 30 +#define SIS_RI_1920x1080 31 +#define SIS_RI_960x540 32 +#define SIS_RI_960x600 33 +#define SIS_RI_1280x854 34 + +/* CR5F */ +#define IsM650 0x80 + +/* Timing data */ +#define NTSCHT 1716 +#define NTSC2HT 1920 +#define NTSCVT 525 +#define PALHT 1728 +#define PALVT 625 +#define StHiTVHT 892 +#define StHiTVVT 1126 +#define StHiTextTVHT 1000 +#define StHiTextTVVT 1126 +#define ExtHiTVHT 2100 +#define ExtHiTVVT 1125 + +/* Indices in (VB)VCLKData tables */ + +#define VCLK28 0x00 /* Index in VCLKData table (300 and 315) */ +#define VCLK40 0x04 /* Index in VCLKData table (300 and 315) */ +#define VCLK65_300 0x09 /* Index in VCLKData table (300) */ +#define VCLK108_2_300 0x14 /* Index in VCLKData table (300) */ +#define VCLK81_300 0x3f /* Index in VCLKData table (300) */ +#define VCLK108_3_300 0x42 /* Index in VCLKData table (300) */ +#define VCLK100_300 0x43 /* Index in VCLKData table (300) */ +#define VCLK34_300 0x3d /* Index in VCLKData table (300) */ +#define VCLK_CUSTOM_300 0x47 + +#define VCLK65_315 0x0b /* Indices in (VB)VCLKData table (315) */ +#define VCLK108_2_315 0x19 +#define VCLK81_315 0x5b +#define VCLK162_315 0x5e +#define VCLK108_3_315 0x45 +#define VCLK100_315 0x46 +#define VCLK34_315 0x55 +#define VCLK68_315 0x0d +#define VCLK_1280x800_315_2 0x5c +#define VCLK121_315 0x5d +#define VCLK130_315 0x72 +#define VCLK_1280x720 0x5f +#define VCLK_1280x768_2 0x60 +#define VCLK_1280x768_3 0x61 /* (unused?) */ +#define VCLK_CUSTOM_315 0x62 +#define VCLK_1280x720_2 0x63 +#define VCLK_720x480 0x67 +#define VCLK_720x576 0x68 +#define VCLK_768x576 0x68 +#define VCLK_848x480 0x65 +#define VCLK_856x480 0x66 +#define VCLK_800x480 0x65 +#define VCLK_1024x576 0x51 +#define VCLK_1152x864 0x64 +#define VCLK_1360x768 0x58 +#define VCLK_1280x800_315 0x6c +#define VCLK_1280x854 0x76 + +#define TVCLKBASE_300 0x21 /* Indices on TV clocks in VCLKData table (300) */ +#define TVCLKBASE_315 0x3a /* Indices on TV clocks in (VB)VCLKData table (315) */ +#define TVVCLKDIV2 0x00 /* Index relative to TVCLKBASE */ +#define TVVCLK 0x01 /* Index relative to TVCLKBASE */ +#define HiTVVCLKDIV2 0x02 /* Index relative to TVCLKBASE */ +#define HiTVVCLK 0x03 /* Index relative to TVCLKBASE */ +#define HiTVSimuVCLK 0x04 /* Index relative to TVCLKBASE */ +#define HiTVTextVCLK 0x05 /* Index relative to TVCLKBASE */ +#define YPbPr750pVCLK 0x25 /* Index relative to TVCLKBASE; was 0x0f NOT relative */ + +/* ------------------------------ */ + +#define SetSCARTOutput 0x01 + +#define HotPlugFunction 0x08 + +#define StStructSize 0x06 + +#define SIS_VIDEO_CAPTURE 0x00 - 0x30 +#define SIS_VIDEO_PLAYBACK 0x02 - 0x30 +#define SIS_CRT2_PORT_04 0x04 - 0x30 +#define SIS_CRT2_PORT_10 0x10 - 0x30 +#define SIS_CRT2_PORT_12 0x12 - 0x30 +#define SIS_CRT2_PORT_14 0x14 - 0x30 + +#define ADR_CRT2PtrData 0x20E +#define offset_Zurac 0x210 /* TW: Trumpion Zurac data pointer */ +#define ADR_LVDSDesPtrData 0x212 +#define ADR_LVDSCRT1DataPtr 0x214 +#define ADR_CHTVVCLKPtr 0x216 +#define ADR_CHTVRegDataPtr 0x218 + +#define LCDDataLen 8 +#define HiTVDataLen 12 +#define TVDataLen 16 + +#define LVDSDataLen 6 +#define LVDSDesDataLen 3 +#define ActiveNonExpanding 0x40 +#define ActiveNonExpandingShift 6 +#define ActivePAL 0x20 +#define ActivePALShift 5 +#define ModeSwitchStatus 0x0F +#define SoftTVType 0x40 +#define SoftSettingAddr 0x52 +#define ModeSettingAddr 0x53 + +#define _PanelType00 0x00 +#define _PanelType01 0x08 +#define _PanelType02 0x10 +#define _PanelType03 0x18 +#define _PanelType04 0x20 +#define _PanelType05 0x28 +#define _PanelType06 0x30 +#define _PanelType07 0x38 +#define _PanelType08 0x40 +#define _PanelType09 0x48 +#define _PanelType0A 0x50 +#define _PanelType0B 0x58 +#define _PanelType0C 0x60 +#define _PanelType0D 0x68 +#define _PanelType0E 0x70 +#define _PanelType0F 0x78 + +#define PRIMARY_VGA 0 /* 1: SiS is primary vga 0:SiS is secondary vga */ + +#define BIOSIDCodeAddr 0x235 /* Offsets to ptrs in BIOS image */ +#define OEMUtilIDCodeAddr 0x237 +#define VBModeIDTableAddr 0x239 +#define OEMTVPtrAddr 0x241 +#define PhaseTableAddr 0x243 +#define NTSCFilterTableAddr 0x245 +#define PALFilterTableAddr 0x247 +#define OEMLCDPtr_1Addr 0x249 +#define OEMLCDPtr_2Addr 0x24B +#define LCDHPosTable_1Addr 0x24D +#define LCDHPosTable_2Addr 0x24F +#define LCDVPosTable_1Addr 0x251 +#define LCDVPosTable_2Addr 0x253 +#define OEMLCDPIDTableAddr 0x255 + +#define VBModeStructSize 5 +#define PhaseTableSize 4 +#define FilterTableSize 4 +#define LCDHPosTableSize 7 +#define LCDVPosTableSize 5 +#define OEMLVDSPIDTableSize 4 +#define LVDSHPosTableSize 4 +#define LVDSVPosTableSize 6 + +#define VB_ModeID 0 +#define VB_TVTableIndex 1 +#define VB_LCDTableIndex 2 +#define VB_LCDHIndex 3 +#define VB_LCDVIndex 4 + +#define OEMLCDEnable 0x0001 +#define OEMLCDDelayEnable 0x0002 +#define OEMLCDPOSEnable 0x0004 +#define OEMTVEnable 0x0100 +#define OEMTVDelayEnable 0x0200 +#define OEMTVFlickerEnable 0x0400 +#define OEMTVPhaseEnable 0x0800 +#define OEMTVFilterEnable 0x1000 + +#define OEMLCDPanelIDSupport 0x0080 + +/* + ============================================================= + for 315 series (old data layout) + ============================================================= +*/ +#define SoftDRAMType 0x80 +#define SoftSetting_OFFSET 0x52 +#define SR07_OFFSET 0x7C +#define SR15_OFFSET 0x7D +#define SR16_OFFSET 0x81 +#define SR17_OFFSET 0x85 +#define SR19_OFFSET 0x8D +#define SR1F_OFFSET 0x99 +#define SR21_OFFSET 0x9A +#define SR22_OFFSET 0x9B +#define SR23_OFFSET 0x9C +#define SR24_OFFSET 0x9D +#define SR25_OFFSET 0x9E +#define SR31_OFFSET 0x9F +#define SR32_OFFSET 0xA0 +#define SR33_OFFSET 0xA1 + +#define CR40_OFFSET 0xA2 +#define SR25_1_OFFSET 0xF6 +#define CR49_OFFSET 0xF7 + +#define VB310Data_1_2_Offset 0xB6 +#define VB310Data_4_D_Offset 0xB7 +#define VB310Data_4_E_Offset 0xB8 +#define VB310Data_4_10_Offset 0xBB + +#define RGBSenseDataOffset 0xBD +#define YCSenseDataOffset 0xBF +#define VideoSenseDataOffset 0xC1 +#define OutputSelectOffset 0xF3 + +#define ECLK_MCLK_DISTANCE 0x14 +#define VBIOSTablePointerStart 0x100 +#define StandTablePtrOffset VBIOSTablePointerStart+0x02 +#define EModeIDTablePtrOffset VBIOSTablePointerStart+0x04 +#define CRT1TablePtrOffset VBIOSTablePointerStart+0x06 +#define ScreenOffsetPtrOffset VBIOSTablePointerStart+0x08 +#define VCLKDataPtrOffset VBIOSTablePointerStart+0x0A +#define MCLKDataPtrOffset VBIOSTablePointerStart+0x0E +#define CRT2PtrDataPtrOffset VBIOSTablePointerStart+0x10 +#define TVAntiFlickPtrOffset VBIOSTablePointerStart+0x12 +#define TVDelayPtr1Offset VBIOSTablePointerStart+0x14 +#define TVPhaseIncrPtr1Offset VBIOSTablePointerStart+0x16 +#define TVYFilterPtr1Offset VBIOSTablePointerStart+0x18 +#define LCDDelayPtr1Offset VBIOSTablePointerStart+0x20 +#define TVEdgePtr1Offset VBIOSTablePointerStart+0x24 +#define CRT2Delay1Offset VBIOSTablePointerStart+0x28 + +#endif diff --git a/drivers/video/fbdev/sis/initextlfb.c b/drivers/video/fbdev/sis/initextlfb.c new file mode 100644 index 0000000..3ab18f5 --- /dev/null +++ b/drivers/video/fbdev/sis/initextlfb.c @@ -0,0 +1,231 @@ +/* + * SiS 300/540/630[S]/730[S] + * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX] + * XGI V3XT/V5/V8, Z7 + * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 + * + * Linux kernel specific extensions to init.c/init301.c + * + * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + */ + +#include "initdef.h" +#include "vgatypes.h" +#include "vstruct.h" + +#include <linux/types.h> +#include <linux/fb.h> + +int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, + unsigned char modeno, unsigned char rateindex); +int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, + unsigned char rateindex, struct fb_var_screeninfo *var); +bool sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, + int *htotal, int *vtotal, unsigned char rateindex); + +extern bool SiSInitPtr(struct SiS_Private *SiS_Pr); +extern bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, + unsigned short *ModeIdIndex); +extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, + int xres, int yres, struct fb_var_screeninfo *var, bool writeres); + +int +sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno, + unsigned char rateindex) +{ + unsigned short ModeNo = modeno; + unsigned short ModeIdIndex = 0, ClockIndex = 0; + unsigned short RRTI = 0; + int Clock; + + if(!SiSInitPtr(SiS_Pr)) return 65000; + + if(rateindex > 0) rateindex--; + +#ifdef CONFIG_FB_SIS_315 + switch(ModeNo) { + case 0x5a: ModeNo = 0x50; break; + case 0x5b: ModeNo = 0x56; + } +#endif + + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) { + printk(KERN_ERR "Could not find mode %x\n", ModeNo); + return 65000; + } + + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { + if(SiS_Pr->SiS_UseWide == 1) { + /* Wide screen: Ignore rateindex */ + ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_WIDE; + } else { + RRTI += rateindex; + ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_NORM; + } + } else { + RRTI += rateindex; + ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK; + } + + Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000; + + return Clock; +} + +int +sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, + unsigned char rateindex, struct fb_var_screeninfo *var) +{ + unsigned short ModeNo = modeno; + unsigned short ModeIdIndex = 0, index = 0, RRTI = 0; + int j; + + if(!SiSInitPtr(SiS_Pr)) return 0; + + if(rateindex > 0) rateindex--; + +#ifdef CONFIG_FB_SIS_315 + switch(ModeNo) { + case 0x5a: ModeNo = 0x50; break; + case 0x5b: ModeNo = 0x56; + } +#endif + + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0; + + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { + if(SiS_Pr->SiS_UseWide == 1) { + /* Wide screen: Ignore rateindex */ + index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE; + } else { + RRTI += rateindex; + index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM; + } + } else { + RRTI += rateindex; + index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC; + } + + SiS_Generic_ConvertCRData(SiS_Pr, + (unsigned char *)&SiS_Pr->SiS_CRT1Table[index].CR[0], + SiS_Pr->SiS_RefIndex[RRTI].XRes, + SiS_Pr->SiS_RefIndex[RRTI].YRes, + var, false); + + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x8000) + var->sync &= ~FB_SYNC_VERT_HIGH_ACT; + else + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x4000) + var->sync &= ~FB_SYNC_HOR_HIGH_ACT; + else + var->sync |= FB_SYNC_HOR_HIGH_ACT; + + var->vmode = FB_VMODE_NONINTERLACED; + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x0080) + var->vmode = FB_VMODE_INTERLACED; + else { + j = 0; + while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) { + if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID == + SiS_Pr->SiS_RefIndex[RRTI].ModeID) { + if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) { + var->vmode = FB_VMODE_DOUBLE; + } + break; + } + j++; + } + } + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { +#if 0 /* Do this? */ + var->upper_margin <<= 1; + var->lower_margin <<= 1; + var->vsync_len <<= 1; +#endif + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + var->upper_margin >>= 1; + var->lower_margin >>= 1; + var->vsync_len >>= 1; + } + + return 1; +} + +bool +sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal, + int *vtotal, unsigned char rateindex) +{ + unsigned short ModeNo = modeno; + unsigned short ModeIdIndex = 0, CRT1Index = 0; + unsigned short RRTI = 0; + unsigned char sr_data, cr_data, cr_data2; + + if(!SiSInitPtr(SiS_Pr)) return false; + + if(rateindex > 0) rateindex--; + +#ifdef CONFIG_FB_SIS_315 + switch(ModeNo) { + case 0x5a: ModeNo = 0x50; break; + case 0x5b: ModeNo = 0x56; + } +#endif + + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false; + + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { + if(SiS_Pr->SiS_UseWide == 1) { + /* Wide screen: Ignore rateindex */ + CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE; + } else { + RRTI += rateindex; + CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM; + } + } else { + RRTI += rateindex; + CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC; + } + + sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; + cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0]; + *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8; + + sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; + cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6]; + cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; + *vtotal = ((cr_data & 0xFF) | + ((unsigned short)(cr_data2 & 0x01) << 8) | + ((unsigned short)(cr_data2 & 0x20) << 4) | + ((unsigned short)(sr_data & 0x01) << 10)) + 2; + + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & InterlaceMode) + *vtotal *= 2; + + return true; +} + + + diff --git a/drivers/video/fbdev/sis/oem300.h b/drivers/video/fbdev/sis/oem300.h new file mode 100644 index 0000000..b73f268 --- /dev/null +++ b/drivers/video/fbdev/sis/oem300.h @@ -0,0 +1,840 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * OEM Data for 300 series + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +static const unsigned char SiS300_OEMTVDelay301[8][4] = +{ + {0x08,0x08,0x08,0x08}, + {0x08,0x08,0x08,0x08}, + {0x08,0x08,0x08,0x08}, + {0x2c,0x2c,0x2c,0x2c}, + {0x08,0x08,0x08,0x08}, + {0x08,0x08,0x08,0x08}, + {0x08,0x08,0x08,0x08}, + {0x20,0x20,0x20,0x20} +}; + +static const unsigned char SiS300_OEMTVDelayLVDS[8][4] = +{ + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20} +}; + +static const unsigned char SiS300_OEMTVFlicker[8][4] = +{ + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00} +}; + +static const unsigned char SiS300_OEMLCDDelay2[64][4] = /* for 301/301b/302b/301LV/302LV */ +{ + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20} +}; + +static const unsigned char SiS300_OEMLCDDelay4[12][4] = +{ + {0x2c,0x2c,0x2c,0x2c}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x2c,0x2c,0x2c,0x2c}, + {0x2c,0x2c,0x2c,0x2c}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x24,0x24,0x24,0x24}, + {0x24,0x24,0x24,0x24}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x24,0x24,0x24,0x24} +}; + +static const unsigned char SiS300_OEMLCDDelay5[32][4] = +{ + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, +}; + +static const unsigned char SiS300_OEMLCDDelay3[64][4] = /* For LVDS */ +{ + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20}, + {0x20,0x20,0x20,0x20} +}; + +static const unsigned char SiS300_Phase1[8][5][4] = +{ + { + {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + } +}; + +static const unsigned char SiS300_Phase2[8][5][4] = +{ + { + {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08}, + {0x21,0xed,0x8a,0x08} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + } +}; + +static const unsigned char SiS300_Filter1[10][16][4] = +{ + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x10,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xfc,0xfb,0x14,0x2a}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32}, + {0xf1,0xf7,0x1f,0x32} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18} + }, + { + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18} + }, +}; + +static const unsigned char SiS300_Filter2[10][9][7] = +{ + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + } +}; + +/* Custom data for Barco iQ Pro R300 */ +static const unsigned char barco_p1[2][9][7][3] = +{ + { + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x1e, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x16, 0x00 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 }, + { 0, 0, 0 } + }, + { + { 0, 0, 0 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x1e, 0x00 }, + { 0, 0, 0 } + }, + { + { 0x16, 0xd1, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x11, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x26, 0x00 } + }, + { + { 0x16, 0xd1, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x30, 0x00 }, + { 0, 0, 0 } + }, + { + { 0x16, 0x00, 0x00 }, + { 0x17, 0xa0, 0x00 }, + { 0x1a, 0xa0, 0x00 }, + { 0x1b, 0x2a, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0, 0, 0 } + }, + { + { 0x16, 0x00, 0x00 }, + { 0x17, 0xaa, 0x00 }, + { 0x1a, 0xa0, 0x00 }, + { 0x1b, 0x2a, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0, 0, 0 } + } + }, + { + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 } + }, + { + { 0, 0, 0 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 }, + }, + { + { 0, 0, 0 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x1e, 0x00 } + }, + { + { 0x16, 0xd1, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe6, 0x00 }, + { 0x1b, 0x11, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x26, 0x00 } + }, + { + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe0, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x30, 0x00 }, + { 0, 0, 0 } + }, + { + { 0, 0, 0 } + }, + { + { 0, 0, 0 } + } + } +}; + + + + + + diff --git a/drivers/video/fbdev/sis/oem310.h b/drivers/video/fbdev/sis/oem310.h new file mode 100644 index 0000000..8fce56e --- /dev/null +++ b/drivers/video/fbdev/sis/oem310.h @@ -0,0 +1,430 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * OEM Data for 315/330/340 series + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +static const unsigned char SiS310_LCDDelayCompensation_301[] = /* 301 */ +{ + 0x00,0x00,0x00, /* 800x600 */ + 0x0b,0x0b,0x0b, /* 1024x768 */ + 0x08,0x08,0x08, /* 1280x1024 */ + 0x00,0x00,0x00, /* 640x480 (unknown) */ + 0x00,0x00,0x00, /* 1024x600 (unknown) */ + 0x00,0x00,0x00, /* 1152x864 (unknown) */ + 0x08,0x08,0x08, /* 1280x960 (guessed) */ + 0x00,0x00,0x00, /* 1152x768 (unknown) */ + 0x08,0x08,0x08, /* 1400x1050 */ + 0x08,0x08,0x08, /* 1280x768 (guessed) */ + 0x00,0x00,0x00, /* 1600x1200 */ + 0x00,0x00,0x00, /* 320x480 (unknown) */ + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00 +}; + +/* This is contained in 650+301B BIOSes, but it is wrong - so we don't use it */ +static const unsigned char SiS310_LCDDelayCompensation_650301LV[] = /* 650 + 30xLV */ +{ + 0x01,0x01,0x01, /* 800x600 */ + 0x01,0x01,0x01, /* 1024x768 */ + 0x01,0x01,0x01, /* 1280x1024 */ + 0x01,0x01,0x01, /* 640x480 (unknown) */ + 0x01,0x01,0x01, /* 1024x600 (unknown) */ + 0x01,0x01,0x01, /* 1152x864 (unknown) */ + 0x01,0x01,0x01, /* 1280x960 (guessed) */ + 0x01,0x01,0x01, /* 1152x768 (unknown) */ + 0x01,0x01,0x01, /* 1400x1050 */ + 0x01,0x01,0x01, /* 1280x768 (guessed) */ + 0x01,0x01,0x01, /* 1600x1200 */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 +}; + +static const unsigned char SiS310_LCDDelayCompensation_651301LV[] = /* M650/651 301LV */ +{ + 0x33,0x33,0x33, /* 800x600 (guessed) - new: PanelType, not PanelRes ! */ + 0x33,0x33,0x33, /* 1024x768 */ + 0x33,0x33,0x33, /* 1280x1024 */ + 0x33,0x33,0x33, /* 640x480 (unknown) */ + 0x33,0x33,0x33, /* 1024x600 (unknown) */ + 0x33,0x33,0x33, /* 1152x864 (unknown) */ + 0x33,0x33,0x33, /* 1280x960 (guessed) */ + 0x33,0x33,0x33, /* 1152x768 (unknown) */ + 0x33,0x33,0x33, /* 1400x1050 */ + 0x33,0x33,0x33, /* 1280x768 (guessed) */ + 0x33,0x33,0x33, /* 1600x1200 */ + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33 +}; + +static const unsigned char SiS310_LCDDelayCompensation_651302LV[] = /* M650/651 302LV */ +{ + 0x33,0x33,0x33, /* 800x600 (guessed) */ + 0x33,0x33,0x33, /* 1024x768 */ + 0x33,0x33,0x33, /* 1280x1024 */ + 0x33,0x33,0x33, /* 640x480 (unknown) */ + 0x33,0x33,0x33, /* 1024x600 (unknown) */ + 0x33,0x33,0x33, /* 1152x864 (unknown) */ + 0x33,0x33,0x33, /* 1280x960 (guessed) */ + 0x33,0x33,0x33, /* 1152x768 (unknown) */ + 0x33,0x33,0x33, /* 1400x1050 */ + 0x33,0x33,0x33, /* 1280x768 (guessed) */ + 0x33,0x33,0x33, /* 1600x1200 */ + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33 +}; + +static const unsigned char SiS310_LCDDelayCompensation_3xx301B[] = /* 30xB */ +{ + 0x01,0x01,0x01, /* 800x600 */ + 0x0C,0x0C,0x0C, /* 1024x768 */ + 0x0C,0x0C,0x0C, /* 1280x1024 */ + 0x08,0x08,0x08, /* 640x480 */ + 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 +}; + +static const unsigned char SiS310_LCDDelayCompensation_3xx301LV[] = /* 315+30xLV */ +{ + 0x01,0x01,0x01, /* 800x600 */ + 0x04,0x04,0x04, /* 1024x768 (A531/BIOS 1.14.05f: 4 - works with 6 */ + 0x0C,0x0C,0x0C, /* 1280x1024 */ + 0x08,0x08,0x08, /* 640x480 */ + 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 +}; + +static const unsigned char SiS310_TVDelayCompensation_301[] = /* 301 */ +{ + 0x02,0x02, /* NTSC Enhanced, Standard */ + 0x02,0x02, /* PAL */ + 0x08,0x0b /* HiVision */ +}; + +static const unsigned char SiS310_TVDelayCompensation_301B[] = /* 30xB, 30xLV */ +{ + 0x03,0x03, + 0x03,0x03, + 0x03,0x03 +}; + +static const unsigned char SiS310_TVDelayCompensation_740301B[] = /* 740 + 30xB (30xLV?) */ +{ + 0x05,0x05, + 0x05,0x05, + 0x05,0x05 +}; + +static const unsigned char SiS310_TVDelayCompensation_651301LV[] = /* M650, 651, 301LV */ +{ + 0x33,0x33, + 0x33,0x33, + 0x33,0x33 +}; + +static const unsigned char SiS310_TVDelayCompensation_651302LV[] = /* M650, 651, 302LV */ +{ + 0x33,0x33, + 0x33,0x33, + 0x33,0x33 +}; + +static const unsigned char SiS_TVDelay661_301[] = /* 661, 301 */ +{ + 0x44,0x44, + 0x44,0x44, + 0x00,0x00, + 0x44,0x44, + 0x44,0x44, + 0x44,0x44 +}; + +static const unsigned char SiS_TVDelay661_301B[] = /* 661, 301B et al */ +{ + 0x44,0x44, + 0x44,0x44, + 0x00,0x00, + 0x44,0x44, + 0x44,0x44, + 0x44,0x44 +}; + +static const unsigned char SiS310_TVDelayCompensation_LVDS[] = /* LVDS */ +{ + 0x0a,0x0a, + 0x0a,0x0a, + 0x0a,0x0a +}; + +static const unsigned char SiS310_TVAntiFlick1[6][2] = +{ + {0x4,0x0}, + {0x4,0x8}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0} +}; + +static const unsigned char SiS310_TVEdge1[6][2] = +{ + {0x0,0x4}, + {0x0,0x4}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0} +}; + +static const unsigned char SiS310_TVYFilter1[5][8][4] = +{ + { + {0x00,0xf4,0x10,0x38}, /* NTSC */ + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xf1,0x04,0x1f,0x18}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xee,0x0c,0x22,0x08}, + {0xeb,0x15,0x25,0xf6} + }, + { + {0x00,0xf4,0x10,0x38}, /* PAL */ + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0x00,0xf4,0x10,0x38}, + {0xf1,0xf7,0x1f,0x32}, + {0xf3,0x00,0x1d,0x20}, + {0xfc,0xfb,0x14,0x2a} + }, + { + {0x00,0x00,0x00,0x00}, /* HiVision */ + {0x00,0xf4,0x10,0x38}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xee,0x0c,0x22,0x08} + }, + { + {0x00,0xf4,0x10,0x38}, /* PAL-M */ + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6} + }, + { + {0x00,0xf4,0x10,0x38}, /* PAL-N */ + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x10,0x18}, + {0xf7,0x06,0x19,0x14}, + {0x00,0xf4,0x10,0x38}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x04,0x25,0x18}, + {0xeb,0x15,0x25,0xf6} + } +}; + +static const unsigned char SiS310_TVYFilter2[5][9][7] = +{ + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* NTSC */ + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL */ + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, /* HiVision */ + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, + {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL-M */ + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL-N */ + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, + {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, + {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, + {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} + } +}; + +static const unsigned char SiS310_TVPhaseIncr1[3][2][4] = +{ + { + {0x21,0xed,0xba,0x08}, + {0x21,0xed,0xba,0x08} + }, + { + {0x2a,0x05,0xe3,0x00}, + {0x2a,0x05,0xe3,0x00} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + } +}; + +static const unsigned char SiS310_TVPhaseIncr2[3][2][4] = +{ + { + {0x21,0xf0,0x7b,0xd6}, + {0x21,0xf0,0x7b,0xd6} + }, + { + {0x2a,0x0a,0x41,0xe9}, + {0x2a,0x0a,0x41,0xe9} + }, + { + {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00} + } +}; + +/**************************************************************/ +/* CUSTOM TIMING DATA --------------------------------------- */ +/**************************************************************/ + +/* Inventec / Compaq Presario 3045US, 3017 */ + +static const struct SiS_LCDData SiS310_ExtCompaq1280x1024Data[] = +{ + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 32, 15,1696, 501,1696,1066}, + { 212, 75,1024, 621,1696,1066}, + { 4, 3,1696, 810,1696,1066}, + { 1, 1,1696,1066,1696,1066} +}; + +/* Asus A2xxxH _2 */ + +static const struct SiS_Part2PortTbl SiS310_CRT2Part2_Asus1024x768_3[] = +{ + {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x38,0x13,0x16,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} +}; + + + + diff --git a/drivers/video/fbdev/sis/sis.h b/drivers/video/fbdev/sis/sis.h new file mode 100644 index 0000000..1987f1b7 --- /dev/null +++ b/drivers/video/fbdev/sis/sis.h @@ -0,0 +1,586 @@ +/* + * SiS 300/540/630[S]/730[S], + * SiS 315[E|PRO]/550/[M]65x/[M]661[F|M]X/740/[M]741[GX]/330/[M]76x[GX], + * XGI V3XT/V5/V8, Z7 + * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3 + * + * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _SIS_H_ +#define _SIS_H_ + +#include <video/sisfb.h> + +#include "vgatypes.h" +#include "vstruct.h" + +#define VER_MAJOR 1 +#define VER_MINOR 8 +#define VER_LEVEL 9 + +#include <linux/spinlock.h> + +#ifdef CONFIG_COMPAT +#define SIS_NEW_CONFIG_COMPAT +#endif /* CONFIG_COMPAT */ + +#undef SISFBDEBUG + +#ifdef SISFBDEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) +#define TWDEBUG(x) printk(KERN_INFO x "\n"); +#else +#define DPRINTK(fmt, args...) +#define TWDEBUG(x) +#endif + +#define SISFAIL(x) do { printk(x "\n"); return -EINVAL; } while(0) + +/* To be included in pci_ids.h */ +#ifndef PCI_DEVICE_ID_SI_650_VGA +#define PCI_DEVICE_ID_SI_650_VGA 0x6325 +#endif +#ifndef PCI_DEVICE_ID_SI_650 +#define PCI_DEVICE_ID_SI_650 0x0650 +#endif +#ifndef PCI_DEVICE_ID_SI_651 +#define PCI_DEVICE_ID_SI_651 0x0651 +#endif +#ifndef PCI_DEVICE_ID_SI_740 +#define PCI_DEVICE_ID_SI_740 0x0740 +#endif +#ifndef PCI_DEVICE_ID_SI_330 +#define PCI_DEVICE_ID_SI_330 0x0330 +#endif +#ifndef PCI_DEVICE_ID_SI_660_VGA +#define PCI_DEVICE_ID_SI_660_VGA 0x6330 +#endif +#ifndef PCI_DEVICE_ID_SI_661 +#define PCI_DEVICE_ID_SI_661 0x0661 +#endif +#ifndef PCI_DEVICE_ID_SI_741 +#define PCI_DEVICE_ID_SI_741 0x0741 +#endif +#ifndef PCI_DEVICE_ID_SI_660 +#define PCI_DEVICE_ID_SI_660 0x0660 +#endif +#ifndef PCI_DEVICE_ID_SI_760 +#define PCI_DEVICE_ID_SI_760 0x0760 +#endif +#ifndef PCI_DEVICE_ID_SI_761 +#define PCI_DEVICE_ID_SI_761 0x0761 +#endif + +#ifndef PCI_VENDOR_ID_XGI +#define PCI_VENDOR_ID_XGI 0x18ca +#endif + +#ifndef PCI_DEVICE_ID_XGI_20 +#define PCI_DEVICE_ID_XGI_20 0x0020 +#endif + +#ifndef PCI_DEVICE_ID_XGI_40 +#define PCI_DEVICE_ID_XGI_40 0x0040 +#endif + +/* To be included in fb.h */ +#ifndef FB_ACCEL_SIS_GLAMOUR_2 +#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 65x, 740, 661, 741 */ +#endif +#ifndef FB_ACCEL_SIS_XABRE +#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre"), 76x */ +#endif +#ifndef FB_ACCEL_XGI_VOLARI_V +#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari Vx (V3XT, V5, V8) */ +#endif +#ifndef FB_ACCEL_XGI_VOLARI_Z +#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */ +#endif + +/* ivideo->caps */ +#define HW_CURSOR_CAP 0x80 +#define TURBO_QUEUE_CAP 0x40 +#define AGP_CMD_QUEUE_CAP 0x20 +#define VM_CMD_QUEUE_CAP 0x10 +#define MMIO_CMD_QUEUE_CAP 0x08 + +/* For 300 series */ +#define TURBO_QUEUE_AREA_SIZE (512 * 1024) /* 512K */ +#define HW_CURSOR_AREA_SIZE_300 4096 /* 4K */ + +/* For 315/Xabre series */ +#define COMMAND_QUEUE_AREA_SIZE (512 * 1024) /* 512K */ +#define COMMAND_QUEUE_AREA_SIZE_Z7 (128 * 1024) /* 128k for XGI Z7 */ +#define HW_CURSOR_AREA_SIZE_315 16384 /* 16K */ +#define COMMAND_QUEUE_THRESHOLD 0x1F + +#define SIS_OH_ALLOC_SIZE 4000 +#define SENTINEL 0x7fffffff + +#define SEQ_ADR 0x14 +#define SEQ_DATA 0x15 +#define DAC_ADR 0x18 +#define DAC_DATA 0x19 +#define CRTC_ADR 0x24 +#define CRTC_DATA 0x25 +#define DAC2_ADR (0x16-0x30) +#define DAC2_DATA (0x17-0x30) +#define VB_PART1_ADR (0x04-0x30) +#define VB_PART1_DATA (0x05-0x30) +#define VB_PART2_ADR (0x10-0x30) +#define VB_PART2_DATA (0x11-0x30) +#define VB_PART3_ADR (0x12-0x30) +#define VB_PART3_DATA (0x13-0x30) +#define VB_PART4_ADR (0x14-0x30) +#define VB_PART4_DATA (0x15-0x30) + +#define SISSR ivideo->SiS_Pr.SiS_P3c4 +#define SISCR ivideo->SiS_Pr.SiS_P3d4 +#define SISDACA ivideo->SiS_Pr.SiS_P3c8 +#define SISDACD ivideo->SiS_Pr.SiS_P3c9 +#define SISPART1 ivideo->SiS_Pr.SiS_Part1Port +#define SISPART2 ivideo->SiS_Pr.SiS_Part2Port +#define SISPART3 ivideo->SiS_Pr.SiS_Part3Port +#define SISPART4 ivideo->SiS_Pr.SiS_Part4Port +#define SISPART5 ivideo->SiS_Pr.SiS_Part5Port +#define SISDAC2A SISPART5 +#define SISDAC2D (SISPART5 + 1) +#define SISMISCR (ivideo->SiS_Pr.RelIO + 0x1c) +#define SISMISCW ivideo->SiS_Pr.SiS_P3c2 +#define SISINPSTAT (ivideo->SiS_Pr.RelIO + 0x2a) +#define SISPEL ivideo->SiS_Pr.SiS_P3c6 +#define SISVGAENABLE (ivideo->SiS_Pr.RelIO + 0x13) +#define SISVID (ivideo->SiS_Pr.RelIO + 0x02 - 0x30) +#define SISCAP (ivideo->SiS_Pr.RelIO + 0x00 - 0x30) + +#define IND_SIS_PASSWORD 0x05 /* SRs */ +#define IND_SIS_COLOR_MODE 0x06 +#define IND_SIS_RAMDAC_CONTROL 0x07 +#define IND_SIS_DRAM_SIZE 0x14 +#define IND_SIS_MODULE_ENABLE 0x1E +#define IND_SIS_PCI_ADDRESS_SET 0x20 +#define IND_SIS_TURBOQUEUE_ADR 0x26 +#define IND_SIS_TURBOQUEUE_SET 0x27 +#define IND_SIS_POWER_ON_TRAP 0x38 +#define IND_SIS_POWER_ON_TRAP2 0x39 +#define IND_SIS_CMDQUEUE_SET 0x26 +#define IND_SIS_CMDQUEUE_THRESHOLD 0x27 + +#define IND_SIS_AGP_IO_PAD 0x48 + +#define SIS_CRT2_WENABLE_300 0x24 /* Part1 */ +#define SIS_CRT2_WENABLE_315 0x2F + +#define SIS_PASSWORD 0x86 /* SR05 */ + +#define SIS_INTERLACED_MODE 0x20 /* SR06 */ +#define SIS_8BPP_COLOR_MODE 0x0 +#define SIS_15BPP_COLOR_MODE 0x1 +#define SIS_16BPP_COLOR_MODE 0x2 +#define SIS_32BPP_COLOR_MODE 0x4 + +#define SIS_ENABLE_2D 0x40 /* SR1E */ + +#define SIS_MEM_MAP_IO_ENABLE 0x01 /* SR20 */ +#define SIS_PCI_ADDR_ENABLE 0x80 + +#define SIS_AGP_CMDQUEUE_ENABLE 0x80 /* 315/330/340 series SR26 */ +#define SIS_VRAM_CMDQUEUE_ENABLE 0x40 +#define SIS_MMIO_CMD_ENABLE 0x20 +#define SIS_CMD_QUEUE_SIZE_512k 0x00 +#define SIS_CMD_QUEUE_SIZE_1M 0x04 +#define SIS_CMD_QUEUE_SIZE_2M 0x08 +#define SIS_CMD_QUEUE_SIZE_4M 0x0C +#define SIS_CMD_QUEUE_RESET 0x01 +#define SIS_CMD_AUTO_CORR 0x02 + +#define SIS_CMD_QUEUE_SIZE_Z7_64k 0x00 /* XGI Z7 */ +#define SIS_CMD_QUEUE_SIZE_Z7_128k 0x04 + +#define SIS_SIMULTANEOUS_VIEW_ENABLE 0x01 /* CR30 */ +#define SIS_MODE_SELECT_CRT2 0x02 +#define SIS_VB_OUTPUT_COMPOSITE 0x04 +#define SIS_VB_OUTPUT_SVIDEO 0x08 +#define SIS_VB_OUTPUT_SCART 0x10 +#define SIS_VB_OUTPUT_LCD 0x20 +#define SIS_VB_OUTPUT_CRT2 0x40 +#define SIS_VB_OUTPUT_HIVISION 0x80 + +#define SIS_VB_OUTPUT_DISABLE 0x20 /* CR31 */ +#define SIS_DRIVER_MODE 0x40 + +#define SIS_VB_COMPOSITE 0x01 /* CR32 */ +#define SIS_VB_SVIDEO 0x02 +#define SIS_VB_SCART 0x04 +#define SIS_VB_LCD 0x08 +#define SIS_VB_CRT2 0x10 +#define SIS_CRT1 0x20 +#define SIS_VB_HIVISION 0x40 +#define SIS_VB_YPBPR 0x80 +#define SIS_VB_TV (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | \ + SIS_VB_SCART | SIS_VB_HIVISION | SIS_VB_YPBPR) + +#define SIS_EXTERNAL_CHIP_MASK 0x0E /* CR37 (< SiS 660) */ +#define SIS_EXTERNAL_CHIP_SIS301 0x01 /* in CR37 << 1 ! */ +#define SIS_EXTERNAL_CHIP_LVDS 0x02 +#define SIS_EXTERNAL_CHIP_TRUMPION 0x03 +#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04 +#define SIS_EXTERNAL_CHIP_CHRONTEL 0x05 +#define SIS310_EXTERNAL_CHIP_LVDS 0x02 +#define SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03 + +#define SIS_AGP_2X 0x20 /* CR48 */ + +/* vbflags, private entries (others in sisfb.h) */ +#define VB_CONEXANT 0x00000800 /* 661 series only */ +#define VB_TRUMPION VB_CONEXANT /* 300 series only */ +#define VB_302ELV 0x00004000 +#define VB_301 0x00100000 /* Video bridge type */ +#define VB_301B 0x00200000 +#define VB_302B 0x00400000 +#define VB_30xBDH 0x00800000 /* 30xB DH version (w/o LCD support) */ +#define VB_LVDS 0x01000000 +#define VB_CHRONTEL 0x02000000 +#define VB_301LV 0x04000000 +#define VB_302LV 0x08000000 +#define VB_301C 0x10000000 + +#define VB_SISBRIDGE (VB_301|VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV|VB_302ELV) +#define VB_VIDEOBRIDGE (VB_SISBRIDGE | VB_LVDS | VB_CHRONTEL | VB_CONEXANT) + +/* vbflags2 (static stuff only!) */ +#define VB2_SISUMC 0x00000001 +#define VB2_301 0x00000002 /* Video bridge type */ +#define VB2_301B 0x00000004 +#define VB2_301C 0x00000008 +#define VB2_307T 0x00000010 +#define VB2_302B 0x00000800 +#define VB2_301LV 0x00001000 +#define VB2_302LV 0x00002000 +#define VB2_302ELV 0x00004000 +#define VB2_307LV 0x00008000 +#define VB2_30xBDH 0x08000000 /* 30xB DH version (w/o LCD support) */ +#define VB2_CONEXANT 0x10000000 +#define VB2_TRUMPION 0x20000000 +#define VB2_LVDS 0x40000000 +#define VB2_CHRONTEL 0x80000000 + +#define VB2_SISLVDSBRIDGE (VB2_301LV | VB2_302LV | VB2_302ELV | VB2_307LV) +#define VB2_SISTMDSBRIDGE (VB2_301 | VB2_301B | VB2_301C | VB2_302B | VB2_307T) +#define VB2_SISBRIDGE (VB2_SISLVDSBRIDGE | VB2_SISTMDSBRIDGE) + +#define VB2_SISTMDSLCDABRIDGE (VB2_301C | VB2_307T) +#define VB2_SISLCDABRIDGE (VB2_SISTMDSLCDABRIDGE | VB2_301LV | VB2_302LV | VB2_302ELV | VB2_307LV) + +#define VB2_SISHIVISIONBRIDGE (VB2_301 | VB2_301B | VB2_302B) +#define VB2_SISYPBPRBRIDGE (VB2_301C | VB2_307T | VB2_SISLVDSBRIDGE) +#define VB2_SISYPBPRARBRIDGE (VB2_301C | VB2_307T | VB2_307LV) +#define VB2_SISTAP4SCALER (VB2_301C | VB2_307T | VB2_302ELV | VB2_307LV) +#define VB2_SISTVBRIDGE (VB2_SISHIVISIONBRIDGE | VB2_SISYPBPRBRIDGE) + +#define VB2_SISVGA2BRIDGE (VB2_301 | VB2_301B | VB2_301C | VB2_302B | VB2_307T) + +#define VB2_VIDEOBRIDGE (VB2_SISBRIDGE | VB2_LVDS | VB2_CHRONTEL | VB2_CONEXANT) + +#define VB2_30xB (VB2_301B | VB2_301C | VB2_302B | VB2_307T) +#define VB2_30xBLV (VB2_30xB | VB2_SISLVDSBRIDGE) +#define VB2_30xC (VB2_301C | VB2_307T) +#define VB2_30xCLV (VB2_301C | VB2_307T | VB2_302ELV| VB2_307LV) +#define VB2_SISEMIBRIDGE (VB2_302LV | VB2_302ELV | VB2_307LV) +#define VB2_LCD162MHZBRIDGE (VB2_301C | VB2_307T) +#define VB2_LCDOVER1280BRIDGE (VB2_301C | VB2_307T | VB2_302LV | VB2_302ELV | VB2_307LV) +#define VB2_LCDOVER1600BRIDGE (VB2_307T | VB2_307LV) +#define VB2_RAMDAC202MHZBRIDGE (VB2_301C | VB2_307T) + +/* I/O port access functions */ + +void SiS_SetReg(SISIOADDRESS, u8, u8); +void SiS_SetRegByte(SISIOADDRESS, u8); +void SiS_SetRegShort(SISIOADDRESS, u16); +void SiS_SetRegLong(SISIOADDRESS, u32); +void SiS_SetRegANDOR(SISIOADDRESS, u8, u8, u8); +void SiS_SetRegAND(SISIOADDRESS, u8, u8); +void SiS_SetRegOR(SISIOADDRESS, u8, u8); +u8 SiS_GetReg(SISIOADDRESS, u8); +u8 SiS_GetRegByte(SISIOADDRESS); +u16 SiS_GetRegShort(SISIOADDRESS); +u32 SiS_GetRegLong(SISIOADDRESS); + +/* MMIO access macros */ +#define MMIO_IN8(base, offset) readb((base+offset)) +#define MMIO_IN16(base, offset) readw((base+offset)) +#define MMIO_IN32(base, offset) readl((base+offset)) + +#define MMIO_OUT8(base, offset, val) writeb(((u8)(val)), (base+offset)) +#define MMIO_OUT16(base, offset, val) writew(((u16)(val)), (base+offset)) +#define MMIO_OUT32(base, offset, val) writel(((u32)(val)), (base+offset)) + +/* Queue control MMIO registers */ +#define Q_BASE_ADDR 0x85C0 /* Base address of software queue */ +#define Q_WRITE_PTR 0x85C4 /* Current write pointer */ +#define Q_READ_PTR 0x85C8 /* Current read pointer */ +#define Q_STATUS 0x85CC /* queue status */ + +#define MMIO_QUEUE_PHYBASE Q_BASE_ADDR +#define MMIO_QUEUE_WRITEPORT Q_WRITE_PTR +#define MMIO_QUEUE_READPORT Q_READ_PTR + +#ifndef FB_BLANK_UNBLANK +#define FB_BLANK_UNBLANK 0 +#endif +#ifndef FB_BLANK_NORMAL +#define FB_BLANK_NORMAL 1 +#endif +#ifndef FB_BLANK_VSYNC_SUSPEND +#define FB_BLANK_VSYNC_SUSPEND 2 +#endif +#ifndef FB_BLANK_HSYNC_SUSPEND +#define FB_BLANK_HSYNC_SUSPEND 3 +#endif +#ifndef FB_BLANK_POWERDOWN +#define FB_BLANK_POWERDOWN 4 +#endif + +enum _SIS_LCD_TYPE { + LCD_INVALID = 0, + LCD_800x600, + LCD_1024x768, + LCD_1280x1024, + LCD_1280x960, + LCD_640x480, + LCD_1600x1200, + LCD_1920x1440, + LCD_2048x1536, + LCD_320x240, /* FSTN */ + LCD_1400x1050, + LCD_1152x864, + LCD_1152x768, + LCD_1280x768, + LCD_1024x600, + LCD_320x240_2, /* DSTN */ + LCD_320x240_3, /* DSTN */ + LCD_848x480, + LCD_1280x800, + LCD_1680x1050, + LCD_1280x720, + LCD_1280x854, + LCD_CUSTOM, + LCD_UNKNOWN +}; + +enum _SIS_CMDTYPE { + MMIO_CMD = 0, + AGP_CMD_QUEUE, + VM_CMD_QUEUE, +}; + +struct SIS_OH { + struct SIS_OH *poh_next; + struct SIS_OH *poh_prev; + u32 offset; + u32 size; +}; + +struct SIS_OHALLOC { + struct SIS_OHALLOC *poha_next; + struct SIS_OH aoh[1]; +}; + +struct SIS_HEAP { + struct SIS_OH oh_free; + struct SIS_OH oh_used; + struct SIS_OH *poh_freelist; + struct SIS_OHALLOC *poha_chain; + u32 max_freesize; + struct sis_video_info *vinfo; +}; + +/* Our "par" */ +struct sis_video_info { + int cardnumber; + struct fb_info *memyselfandi; + + struct SiS_Private SiS_Pr; + + struct sisfb_info sisfbinfo; /* For ioctl SISFB_GET_INFO */ + + struct fb_var_screeninfo default_var; + + struct fb_fix_screeninfo sisfb_fix; + u32 pseudo_palette[16]; + + struct sisfb_monitor { + u16 hmin; + u16 hmax; + u16 vmin; + u16 vmax; + u32 dclockmax; + u8 feature; + bool datavalid; + } sisfb_thismonitor; + + unsigned short chip_id; /* PCI ID of chip */ + unsigned short chip_vendor; /* PCI ID of vendor */ + char myid[40]; + + struct pci_dev *nbridge; + struct pci_dev *lpcdev; + + int mni; /* Mode number index */ + + unsigned long video_size; + unsigned long video_base; + unsigned long mmio_size; + unsigned long mmio_base; + unsigned long vga_base; + + unsigned long video_offset; + + unsigned long UMAsize, LFBsize; + + void __iomem *video_vbase; + void __iomem *mmio_vbase; + + unsigned char *bios_abase; + + int mtrr; + + u32 sisfb_mem; + + u32 sisfb_parm_mem; + int sisfb_accel; + int sisfb_ypan; + int sisfb_max; + int sisfb_userom; + int sisfb_useoem; + int sisfb_mode_idx; + int sisfb_parm_rate; + int sisfb_crt1off; + int sisfb_forcecrt1; + int sisfb_crt2type; + int sisfb_crt2flags; + int sisfb_dstn; + int sisfb_fstn; + int sisfb_tvplug; + int sisfb_tvstd; + int sisfb_nocrt2rate; + + u32 heapstart; /* offset */ + void __iomem *sisfb_heap_start; /* address */ + void __iomem *sisfb_heap_end; /* address */ + u32 sisfb_heap_size; + int havenoheap; + + struct SIS_HEAP sisfb_heap; /* This card's vram heap */ + + int video_bpp; + int video_cmap_len; + int video_width; + int video_height; + unsigned int refresh_rate; + + unsigned int chip; + unsigned int chip_real_id; + u8 revision_id; + int sisvga_enabled; /* PCI device was enabled */ + + int video_linelength; /* real pitch */ + int scrnpitchCRT1; /* pitch regarding interlace */ + + u16 DstColor; /* For 2d acceleration */ + u32 SiS310_AccelDepth; + u32 CommandReg; + int cmdqueuelength; /* Current (for accel) */ + u32 cmdQueueSize; /* Total size in KB */ + + spinlock_t lockaccel; /* Do not use outside of kernel! */ + + unsigned int pcibus; + unsigned int pcislot; + unsigned int pcifunc; + + int accel; + int engineok; + + u16 subsysvendor; + u16 subsysdevice; + + u32 vbflags; /* Replacing deprecated stuff from above */ + u32 currentvbflags; + u32 vbflags2; + + int lcdxres, lcdyres; + int lcddefmodeidx, tvdefmodeidx, defmodeidx; + u32 CRT2LCDType; /* defined in "SIS_LCD_TYPE" */ + u32 curFSTN, curDSTN; + + int current_bpp; + int current_width; + int current_height; + int current_htotal; + int current_vtotal; + int current_linelength; + __u32 current_pixclock; + int current_refresh_rate; + + unsigned int current_base; + + u8 mode_no; + u8 rate_idx; + int modechanged; + unsigned char modeprechange; + + u8 sisfb_lastrates[128]; + + int newrom; + int haveXGIROM; + int registered; + int warncount; + + int sisvga_engine; + int hwcursor_size; + int CRT2_write_enable; + u8 caps; + + u8 detectedpdc; + u8 detectedpdca; + u8 detectedlcda; + + void __iomem *hwcursor_vbase; + + int chronteltype; + int tvxpos, tvypos; + u8 p2_1f,p2_20,p2_2b,p2_42,p2_43,p2_01,p2_02; + int tvx, tvy; + + u8 sisfblocked; + + struct sisfb_info sisfb_infoblock; + + struct sisfb_cmd sisfb_command; + + u32 sisfb_id; + + u8 sisfb_can_post; + u8 sisfb_card_posted; + u8 sisfb_was_boot_device; + + struct sis_video_info *next; +}; + +#endif diff --git a/drivers/video/fbdev/sis/sis_accel.c b/drivers/video/fbdev/sis/sis_accel.c new file mode 100644 index 0000000..ceb434c --- /dev/null +++ b/drivers/video/fbdev/sis/sis_accel.c @@ -0,0 +1,423 @@ +/* + * SiS 300/540/630[S]/730[S], + * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX], + * XGI V3XT/V5/V8, Z7 + * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 + * + * 2D acceleration part + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Based on the XFree86/X.org driver which is + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * (see http://www.winischhofer.net/ + * for more information and updates) + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/fb.h> +#include <linux/ioport.h> +#include <linux/types.h> +#include <asm/io.h> + +#include "sis.h" +#include "sis_accel.h" + +static const u8 sisALUConv[] = +{ + 0x00, /* dest = 0; 0, GXclear, 0 */ + 0x88, /* dest &= src; DSa, GXand, 0x1 */ + 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */ + 0xCC, /* dest = src; S, GXcopy, 0x3 */ + 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */ + 0xAA, /* dest = dest; D, GXnoop, 0x5 */ + 0x66, /* dest = ^src; DSx, GXxor, 0x6 */ + 0xEE, /* dest |= src; DSo, GXor, 0x7 */ + 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */ + 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */ + 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ + 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */ + 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */ + 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */ + 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */ + 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ +}; +/* same ROP but with Pattern as Source */ +static const u8 sisPatALUConv[] = +{ + 0x00, /* dest = 0; 0, GXclear, 0 */ + 0xA0, /* dest &= src; DPa, GXand, 0x1 */ + 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */ + 0xF0, /* dest = src; P, GXcopy, 0x3 */ + 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */ + 0xAA, /* dest = dest; D, GXnoop, 0x5 */ + 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */ + 0xFA, /* dest |= src; DPo, GXor, 0x7 */ + 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */ + 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */ + 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ + 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */ + 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */ + 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */ + 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */ + 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ +}; + +static const int myrops[] = { + 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 +}; + +/* 300 series ----------------------------------------------------- */ +#ifdef CONFIG_FB_SIS_300 +static void +SiS300Sync(struct sis_video_info *ivideo) +{ + SiS300Idle +} + +static void +SiS300SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int xdir, int ydir, + int rop, int trans_color) +{ + SiS300SetupDSTColorDepth(ivideo->DstColor); + SiS300SetupSRCPitch(ivideo->video_linelength) + SiS300SetupDSTRect(ivideo->video_linelength, 0xffff) + + if(trans_color != -1) { + SiS300SetupROP(0x0A) + SiS300SetupSRCTrans(trans_color) + SiS300SetupCMDFlag(TRANSPARENT_BITBLT) + } else { + SiS300SetupROP(sisALUConv[rop]) + } + if(xdir > 0) { + SiS300SetupCMDFlag(X_INC) + } + if(ydir > 0) { + SiS300SetupCMDFlag(Y_INC) + } +} + +static void +SiS300SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, + int src_y, int dst_x, int dst_y, int width, int height) +{ + u32 srcbase = 0, dstbase = 0; + + if(src_y >= 2048) { + srcbase = ivideo->video_linelength * src_y; + src_y = 0; + } + if(dst_y >= 2048) { + dstbase = ivideo->video_linelength * dst_y; + dst_y = 0; + } + + SiS300SetupSRCBase(srcbase); + SiS300SetupDSTBase(dstbase); + + if(!(ivideo->CommandReg & X_INC)) { + src_x += width-1; + dst_x += width-1; + } + if(!(ivideo->CommandReg & Y_INC)) { + src_y += height-1; + dst_y += height-1; + } + SiS300SetupRect(width, height) + SiS300SetupSRCXY(src_x, src_y) + SiS300SetupDSTXY(dst_x, dst_y) + SiS300DoCMD +} + +static void +SiS300SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop) +{ + SiS300SetupPATFG(color) + SiS300SetupDSTRect(ivideo->video_linelength, 0xffff) + SiS300SetupDSTColorDepth(ivideo->DstColor); + SiS300SetupROP(sisPatALUConv[rop]) + SiS300SetupCMDFlag(PATFG) +} + +static void +SiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h) +{ + u32 dstbase = 0; + + if(y >= 2048) { + dstbase = ivideo->video_linelength * y; + y = 0; + } + SiS300SetupDSTBase(dstbase) + SiS300SetupDSTXY(x,y) + SiS300SetupRect(w,h) + SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT) + SiS300DoCMD +} +#endif + +/* 315/330/340 series ---------------------------------------------- */ + +#ifdef CONFIG_FB_SIS_315 +static void +SiS310Sync(struct sis_video_info *ivideo) +{ + SiS310Idle +} + +static void +SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int trans_color) +{ + SiS310SetupDSTColorDepth(ivideo->DstColor); + SiS310SetupSRCPitch(ivideo->video_linelength) + SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff) + if(trans_color != -1) { + SiS310SetupROP(0x0A) + SiS310SetupSRCTrans(trans_color) + SiS310SetupCMDFlag(TRANSPARENT_BITBLT) + } else { + SiS310SetupROP(sisALUConv[rop]) + /* Set command - not needed, both 0 */ + /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */ + } + SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth) + /* The chip is smart enough to know the direction */ +} + +static void +SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int src_y, + int dst_x, int dst_y, int width, int height) +{ + u32 srcbase = 0, dstbase = 0; + int mymin = min(src_y, dst_y); + int mymax = max(src_y, dst_y); + + /* Although the chip knows the direction to use + * if the source and destination areas overlap, + * that logic fails if we fiddle with the bitmap + * addresses. Therefore, we check if the source + * and destination blitting areas overlap and + * adapt the bitmap addresses synchronously + * if the coordinates exceed the valid range. + * The the areas do not overlap, we do our + * normal check. + */ + if((mymax - mymin) < height) { + if((src_y >= 2048) || (dst_y >= 2048)) { + srcbase = ivideo->video_linelength * mymin; + dstbase = ivideo->video_linelength * mymin; + src_y -= mymin; + dst_y -= mymin; + } + } else { + if(src_y >= 2048) { + srcbase = ivideo->video_linelength * src_y; + src_y = 0; + } + if(dst_y >= 2048) { + dstbase = ivideo->video_linelength * dst_y; + dst_y = 0; + } + } + + srcbase += ivideo->video_offset; + dstbase += ivideo->video_offset; + + SiS310SetupSRCBase(srcbase); + SiS310SetupDSTBase(dstbase); + SiS310SetupRect(width, height) + SiS310SetupSRCXY(src_x, src_y) + SiS310SetupDSTXY(dst_x, dst_y) + SiS310DoCMD +} + +static void +SiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop) +{ + SiS310SetupPATFG(color) + SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff) + SiS310SetupDSTColorDepth(ivideo->DstColor); + SiS310SetupROP(sisPatALUConv[rop]) + SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth) +} + +static void +SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h) +{ + u32 dstbase = 0; + + if(y >= 2048) { + dstbase = ivideo->video_linelength * y; + y = 0; + } + dstbase += ivideo->video_offset; + SiS310SetupDSTBase(dstbase) + SiS310SetupDSTXY(x,y) + SiS310SetupRect(w,h) + SiS310SetupCMDFlag(BITBLT) + SiS310DoCMD +} +#endif + +/* --------------------------------------------------------------------- */ + +/* The exported routines */ + +int sisfb_initaccel(struct sis_video_info *ivideo) +{ +#ifdef SISFB_USE_SPINLOCKS + spin_lock_init(&ivideo->lockaccel); +#endif + return 0; +} + +void sisfb_syncaccel(struct sis_video_info *ivideo) +{ + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + SiS300Sync(ivideo); +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + SiS310Sync(ivideo); +#endif + } +} + +int fbcon_sis_sync(struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + CRITFLAGS + + if((!ivideo->accel) || (!ivideo->engineok)) + return 0; + + CRITBEGIN + sisfb_syncaccel(ivideo); + CRITEND + + return 0; +} + +void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + u32 col = 0; + u32 vxres = info->var.xres_virtual; + u32 vyres = info->var.yres_virtual; + int width, height; + CRITFLAGS + + if(info->state != FBINFO_STATE_RUNNING) + return; + + if((!ivideo->accel) || (!ivideo->engineok)) { + cfb_fillrect(info, rect); + return; + } + + if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres) + return; + + /* Clipping */ + width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width; + height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height; + + switch(info->var.bits_per_pixel) { + case 8: col = rect->color; + break; + case 16: + case 32: col = ((u32 *)(info->pseudo_palette))[rect->color]; + break; + } + + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + CRITBEGIN + SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]); + SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); + CRITEND +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + CRITBEGIN + SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]); + SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); + CRITEND +#endif + } + + sisfb_syncaccel(ivideo); +} + +void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + u32 vxres = info->var.xres_virtual; + u32 vyres = info->var.yres_virtual; + int width = area->width; + int height = area->height; + CRITFLAGS + + if(info->state != FBINFO_STATE_RUNNING) + return; + + if((!ivideo->accel) || (!ivideo->engineok)) { + cfb_copyarea(info, area); + return; + } + + if(!width || !height || + area->sx >= vxres || area->sy >= vyres || + area->dx >= vxres || area->dy >= vyres) + return; + + /* Clipping */ + if((area->sx + width) > vxres) width = vxres - area->sx; + if((area->dx + width) > vxres) width = vxres - area->dx; + if((area->sy + height) > vyres) height = vyres - area->sy; + if((area->dy + height) > vyres) height = vyres - area->dy; + + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + int xdir, ydir; + + if(area->sx < area->dx) xdir = 0; + else xdir = 1; + if(area->sy < area->dy) ydir = 0; + else ydir = 1; + + CRITBEGIN + SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1); + SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, + area->dx, area->dy, width, height); + CRITEND +#endif + } else { +#ifdef CONFIG_FB_SIS_315 + CRITBEGIN + SiS310SetupForScreenToScreenCopy(ivideo, 3, -1); + SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, + area->dx, area->dy, width, height); + CRITEND +#endif + } + + sisfb_syncaccel(ivideo); +} diff --git a/drivers/video/fbdev/sis/sis_accel.h b/drivers/video/fbdev/sis/sis_accel.h new file mode 100644 index 0000000..30e03cd --- /dev/null +++ b/drivers/video/fbdev/sis/sis_accel.h @@ -0,0 +1,400 @@ +/* + * SiS 300/540/630[S]/730[S], + * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX], + * XGI V3XT/V5/V8, Z7 + * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 + * + * 2D acceleration part + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Based on the X driver's sis300_accel.h which is + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * and sis310_accel.h which is + * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * + * Author: Thomas Winischhofer <thomas@winischhofer.net>: + * (see http://www.winischhofer.net/ + * for more information and updates) + */ + +#ifndef _SISFB_ACCEL_H +#define _SISFB_ACCEL_H + +/* Guard accelerator accesses with spin_lock_irqsave? Works well without. */ +#undef SISFB_USE_SPINLOCKS + +#ifdef SISFB_USE_SPINLOCKS +#include <linux/spinlock.h> +#define CRITBEGIN spin_lock_irqsave(&ivideo->lockaccel, critflags); +#define CRITEND spin_unlock_irqrestore(&ivideo->lockaccel, critflags); +#define CRITFLAGS unsigned long critflags; +#else +#define CRITBEGIN +#define CRITEND +#define CRITFLAGS +#endif + +/* Definitions for the SIS engine communication. */ + +#define PATREGSIZE 384 /* Pattern register size. 384 bytes @ 0x8300 */ +#define BR(x) (0x8200 | (x) << 2) +#define PBR(x) (0x8300 | (x) << 2) + +/* SiS300 engine commands */ +#define BITBLT 0x00000000 /* Blit */ +#define COLOREXP 0x00000001 /* Color expand */ +#define ENCOLOREXP 0x00000002 /* Enhanced color expand */ +#define MULTIPLE_SCANLINE 0x00000003 /* ? */ +#define LINE 0x00000004 /* Draw line */ +#define TRAPAZOID_FILL 0x00000005 /* Fill trapezoid */ +#define TRANSPARENT_BITBLT 0x00000006 /* Transparent Blit */ + +/* Additional engine commands for 315 */ +#define ALPHA_BLEND 0x00000007 /* Alpha blend ? */ +#define A3D_FUNCTION 0x00000008 /* 3D command ? */ +#define CLEAR_Z_BUFFER 0x00000009 /* ? */ +#define GRADIENT_FILL 0x0000000A /* Gradient fill */ + +/* source select */ +#define SRCVIDEO 0x00000000 /* source is video RAM */ +#define SRCSYSTEM 0x00000010 /* source is system memory */ +#define SRCCPUBLITBUF SRCSYSTEM /* source is CPU-driven BitBuffer (for color expand) */ +#define SRCAGP 0x00000020 /* source is AGP memory (?) */ + +/* Pattern flags */ +#define PATFG 0x00000000 /* foreground color */ +#define PATPATREG 0x00000040 /* pattern in pattern buffer (0x8300) */ +#define PATMONO 0x00000080 /* mono pattern */ + +/* blitting direction (300 series only) */ +#define X_INC 0x00010000 +#define X_DEC 0x00000000 +#define Y_INC 0x00020000 +#define Y_DEC 0x00000000 + +/* Clipping flags */ +#define NOCLIP 0x00000000 +#define NOMERGECLIP 0x04000000 +#define CLIPENABLE 0x00040000 +#define CLIPWITHOUTMERGE 0x04040000 + +/* Transparency */ +#define OPAQUE 0x00000000 +#define TRANSPARENT 0x00100000 + +/* ? */ +#define DSTAGP 0x02000000 +#define DSTVIDEO 0x02000000 + +/* Subfunctions for Color/Enhanced Color Expansion (315 only) */ +#define COLOR_TO_MONO 0x00100000 +#define AA_TEXT 0x00200000 + +/* Some general registers for 315 series */ +#define SRC_ADDR 0x8200 +#define SRC_PITCH 0x8204 +#define AGP_BASE 0x8206 /* color-depth dependent value */ +#define SRC_Y 0x8208 +#define SRC_X 0x820A +#define DST_Y 0x820C +#define DST_X 0x820E +#define DST_ADDR 0x8210 +#define DST_PITCH 0x8214 +#define DST_HEIGHT 0x8216 +#define RECT_WIDTH 0x8218 +#define RECT_HEIGHT 0x821A +#define PAT_FGCOLOR 0x821C +#define PAT_BGCOLOR 0x8220 +#define SRC_FGCOLOR 0x8224 +#define SRC_BGCOLOR 0x8228 +#define MONO_MASK 0x822C +#define LEFT_CLIP 0x8234 +#define TOP_CLIP 0x8236 +#define RIGHT_CLIP 0x8238 +#define BOTTOM_CLIP 0x823A +#define COMMAND_READY 0x823C +#define FIRE_TRIGGER 0x8240 + +#define PATTERN_REG 0x8300 /* 384 bytes pattern buffer */ + +/* Transparent bitblit registers */ +#define TRANS_DST_KEY_HIGH PAT_FGCOLOR +#define TRANS_DST_KEY_LOW PAT_BGCOLOR +#define TRANS_SRC_KEY_HIGH SRC_FGCOLOR +#define TRANS_SRC_KEY_LOW SRC_BGCOLOR + +/* Store queue length in par */ +#define CmdQueLen ivideo->cmdqueuelength + +/* ------------- SiS 300 series -------------- */ + +/* BR(16) (0x8240): + + bit 31 2D engine: 1 is idle, + bit 30 3D engine: 1 is idle, + bit 29 Command queue: 1 is empty + bits 28:24: Current CPU driven BitBlt buffer stage bit[4:0] + bits 15:0: Current command queue length + +*/ + +#define SiS300Idle \ + { \ + while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \ + while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \ + while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \ + CmdQueLen = MMIO_IN16(ivideo->mmio_vbase, 0x8240); \ + } +/* (do three times, because 2D engine seems quite unsure about whether or not it's idle) */ + +#define SiS300SetupSRCBase(base) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(0), base);\ + CmdQueLen--; + +#define SiS300SetupSRCPitch(pitch) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT16(ivideo->mmio_vbase, BR(1), pitch);\ + CmdQueLen--; + +#define SiS300SetupSRCXY(x,y) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(2), (x)<<16 | (y) );\ + CmdQueLen--; + +#define SiS300SetupDSTBase(base) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(4), base);\ + CmdQueLen--; + +#define SiS300SetupDSTXY(x,y) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(3), (x)<<16 | (y) );\ + CmdQueLen--; + +#define SiS300SetupDSTRect(x,y) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(5), (y)<<16 | (x) );\ + CmdQueLen--; + +#define SiS300SetupDSTColorDepth(bpp) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT16(ivideo->mmio_vbase, BR(1)+2, bpp);\ + CmdQueLen--; + +#define SiS300SetupRect(w,h) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(6), (h)<<16 | (w) );\ + CmdQueLen--; + +#define SiS300SetupPATFG(color) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(7), color);\ + CmdQueLen--; + +#define SiS300SetupPATBG(color) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(8), color);\ + CmdQueLen--; + +#define SiS300SetupSRCFG(color) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(9), color);\ + CmdQueLen--; + +#define SiS300SetupSRCBG(color) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(10), color);\ + CmdQueLen--; + +/* 0x8224 src colorkey high */ +/* 0x8228 src colorkey low */ +/* 0x821c dest colorkey high */ +/* 0x8220 dest colorkey low */ +#define SiS300SetupSRCTrans(color) \ + if(CmdQueLen <= 1) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, 0x8224, color);\ + MMIO_OUT32(ivideo->mmio_vbase, 0x8228, color);\ + CmdQueLen -= 2; + +#define SiS300SetupDSTTrans(color) \ + if(CmdQueLen <= 1) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, 0x821C, color); \ + MMIO_OUT32(ivideo->mmio_vbase, 0x8220, color); \ + CmdQueLen -= 2; + +#define SiS300SetupMONOPAT(p0,p1) \ + if(CmdQueLen <= 1) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(11), p0);\ + MMIO_OUT32(ivideo->mmio_vbase, BR(12), p1);\ + CmdQueLen -= 2; + +#define SiS300SetupClipLT(left,top) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(13), ((left) & 0xFFFF) | (top)<<16 );\ + CmdQueLen--; + +#define SiS300SetupClipRB(right,bottom) \ + if(CmdQueLen <= 0) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(14), ((right) & 0xFFFF) | (bottom)<<16 );\ + CmdQueLen--; + +/* General */ +#define SiS300SetupROP(rop) \ + ivideo->CommandReg = (rop) << 8; + +#define SiS300SetupCMDFlag(flags) \ + ivideo->CommandReg |= (flags); + +#define SiS300DoCMD \ + if(CmdQueLen <= 1) SiS300Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, BR(15), ivideo->CommandReg); \ + MMIO_OUT32(ivideo->mmio_vbase, BR(16), 0);\ + CmdQueLen -= 2; + +/* -------------- SiS 315/330 series --------------- */ + +/* Q_STATUS: + bit 31 = 1: All engines idle and all queues empty + bit 30 = 1: Hardware Queue (=HW CQ, 2D queue, 3D queue) empty + bit 29 = 1: 2D engine is idle + bit 28 = 1: 3D engine is idle + bit 27 = 1: HW command queue empty + bit 26 = 1: 2D queue empty + bit 25 = 1: 3D queue empty + bit 24 = 1: SW command queue empty + bits 23:16: 2D counter 3 + bits 15:8: 2D counter 2 + bits 7:0: 2D counter 1 +*/ + +#define SiS310Idle \ + { \ + while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + CmdQueLen = 0; \ + } + +#define SiS310SetupSRCBase(base) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, SRC_ADDR, base);\ + CmdQueLen--; + +#define SiS310SetupSRCPitch(pitch) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT16(ivideo->mmio_vbase, SRC_PITCH, pitch);\ + CmdQueLen--; + +#define SiS310SetupSRCXY(x,y) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, SRC_Y, (x)<<16 | (y) );\ + CmdQueLen--; + +#define SiS310SetupDSTBase(base) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, DST_ADDR, base);\ + CmdQueLen--; + +#define SiS310SetupDSTXY(x,y) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, DST_Y, (x)<<16 | (y) );\ + CmdQueLen--; + +#define SiS310SetupDSTRect(x,y) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, DST_PITCH, (y)<<16 | (x) );\ + CmdQueLen--; + +#define SiS310SetupDSTColorDepth(bpp) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT16(ivideo->mmio_vbase, AGP_BASE, bpp);\ + CmdQueLen--; + +#define SiS310SetupRect(w,h) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, RECT_WIDTH, (h)<<16 | (w) );\ + CmdQueLen--; + +#define SiS310SetupPATFG(color) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, PAT_FGCOLOR, color);\ + CmdQueLen--; + +#define SiS310SetupPATBG(color) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, PAT_BGCOLOR, color);\ + CmdQueLen--; + +#define SiS310SetupSRCFG(color) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, SRC_FGCOLOR, color);\ + CmdQueLen--; + +#define SiS310SetupSRCBG(color) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, SRC_BGCOLOR, color);\ + CmdQueLen--; + +#define SiS310SetupSRCTrans(color) \ + if(CmdQueLen <= 1) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, TRANS_SRC_KEY_HIGH, color);\ + MMIO_OUT32(ivideo->mmio_vbase, TRANS_SRC_KEY_LOW, color);\ + CmdQueLen -= 2; + +#define SiS310SetupDSTTrans(color) \ + if(CmdQueLen <= 1) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, TRANS_DST_KEY_HIGH, color); \ + MMIO_OUT32(ivideo->mmio_vbase, TRANS_DST_KEY_LOW, color); \ + CmdQueLen -= 2; + +#define SiS310SetupMONOPAT(p0,p1) \ + if(CmdQueLen <= 1) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, MONO_MASK, p0);\ + MMIO_OUT32(ivideo->mmio_vbase, MONO_MASK+4, p1);\ + CmdQueLen -= 2; + +#define SiS310SetupClipLT(left,top) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, LEFT_CLIP, ((left) & 0xFFFF) | (top)<<16 );\ + CmdQueLen--; + +#define SiS310SetupClipRB(right,bottom) \ + if(CmdQueLen <= 0) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, RIGHT_CLIP, ((right) & 0xFFFF) | (bottom)<<16 );\ + CmdQueLen--; + +#define SiS310SetupROP(rop) \ + ivideo->CommandReg = (rop) << 8; + +#define SiS310SetupCMDFlag(flags) \ + ivideo->CommandReg |= (flags); + +#define SiS310DoCMD \ + if(CmdQueLen <= 1) SiS310Idle;\ + MMIO_OUT32(ivideo->mmio_vbase, COMMAND_READY, ivideo->CommandReg); \ + MMIO_OUT32(ivideo->mmio_vbase, FIRE_TRIGGER, 0); \ + CmdQueLen -= 2; + +int sisfb_initaccel(struct sis_video_info *ivideo); +void sisfb_syncaccel(struct sis_video_info *ivideo); + +int fbcon_sis_sync(struct fb_info *info); +void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area); + +#endif diff --git a/drivers/video/fbdev/sis/sis_main.c b/drivers/video/fbdev/sis/sis_main.c new file mode 100644 index 0000000..22ad028 --- /dev/null +++ b/drivers/video/fbdev/sis/sis_main.c @@ -0,0 +1,6844 @@ +/* + * SiS 300/540/630[S]/730[S], + * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX], + * XGI V3XT/V5/V8, Z7 + * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 + * + * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + * Author of (practically wiped) code base: + * SiS (www.sis.com) + * Copyright (C) 1999 Silicon Integrated Systems, Inc. + * + * See http://www.winischhofer.net/ for more information and updates + * + * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver, + * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/screen_info.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/capability.h> +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/uaccess.h> +#include <asm/io.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include "sis.h" +#include "sis_main.h" + +#if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315) +#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set +#warning sisfb will not work! +#endif + +static void sisfb_handle_command(struct sis_video_info *ivideo, + struct sisfb_cmd *sisfb_command); + +/* ------------------ Internal helper routines ----------------- */ + +static void __init +sisfb_setdefaultparms(void) +{ + sisfb_off = 0; + sisfb_parm_mem = 0; + sisfb_accel = -1; + sisfb_ypan = -1; + sisfb_max = -1; + sisfb_userom = -1; + sisfb_useoem = -1; + sisfb_mode_idx = -1; + sisfb_parm_rate = -1; + sisfb_crt1off = 0; + sisfb_forcecrt1 = -1; + sisfb_crt2type = -1; + sisfb_crt2flags = 0; + sisfb_pdc = 0xff; + sisfb_pdca = 0xff; + sisfb_scalelcd = -1; + sisfb_specialtiming = CUT_NONE; + sisfb_lvdshl = -1; + sisfb_dstn = 0; + sisfb_fstn = 0; + sisfb_tvplug = -1; + sisfb_tvstd = -1; + sisfb_tvxposoffset = 0; + sisfb_tvyposoffset = 0; + sisfb_nocrt2rate = 0; +#if !defined(__i386__) && !defined(__x86_64__) + sisfb_resetcard = 0; + sisfb_videoram = 0; +#endif +} + +/* ------------- Parameter parsing -------------- */ + +static void sisfb_search_vesamode(unsigned int vesamode, bool quiet) +{ + int i = 0, j = 0; + + /* We don't know the hardware specs yet and there is no ivideo */ + + if(vesamode == 0) { + if(!quiet) + printk(KERN_ERR "sisfb: Invalid mode. Using default.\n"); + + sisfb_mode_idx = DEFAULT_MODE; + + return; + } + + vesamode &= 0x1dff; /* Clean VESA mode number from other flags */ + + while(sisbios_mode[i++].mode_no[0] != 0) { + if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) || + (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) { + if(sisfb_fstn) { + if(sisbios_mode[i-1].mode_no[1] == 0x50 || + sisbios_mode[i-1].mode_no[1] == 0x56 || + sisbios_mode[i-1].mode_no[1] == 0x53) + continue; + } else { + if(sisbios_mode[i-1].mode_no[1] == 0x5a || + sisbios_mode[i-1].mode_no[1] == 0x5b) + continue; + } + sisfb_mode_idx = i - 1; + j = 1; + break; + } + } + if((!j) && !quiet) + printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode); +} + +static void sisfb_search_mode(char *name, bool quiet) +{ + unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0; + int i = 0; + char strbuf[16], strbuf1[20]; + char *nameptr = name; + + /* We don't know the hardware specs yet and there is no ivideo */ + + if(name == NULL) { + if(!quiet) + printk(KERN_ERR "sisfb: Internal error, using default mode.\n"); + + sisfb_mode_idx = DEFAULT_MODE; + return; + } + + if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) { + if(!quiet) + printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n"); + + sisfb_mode_idx = DEFAULT_MODE; + return; + } + + if(strlen(name) <= 19) { + strcpy(strbuf1, name); + for(i = 0; i < strlen(strbuf1); i++) { + if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' '; + } + + /* This does some fuzzy mode naming detection */ + if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) { + if((rate <= 32) || (depth > 32)) { + j = rate; rate = depth; depth = j; + } + sprintf(strbuf, "%ux%ux%u", xres, yres, depth); + nameptr = strbuf; + sisfb_parm_rate = rate; + } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) { + sprintf(strbuf, "%ux%ux%u", xres, yres, depth); + nameptr = strbuf; + } else { + xres = 0; + if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) { + sprintf(strbuf, "%ux%ux8", xres, yres); + nameptr = strbuf; + } else { + sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet); + return; + } + } + } + + i = 0; j = 0; + while(sisbios_mode[i].mode_no[0] != 0) { + if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) { + if(sisfb_fstn) { + if(sisbios_mode[i-1].mode_no[1] == 0x50 || + sisbios_mode[i-1].mode_no[1] == 0x56 || + sisbios_mode[i-1].mode_no[1] == 0x53) + continue; + } else { + if(sisbios_mode[i-1].mode_no[1] == 0x5a || + sisbios_mode[i-1].mode_no[1] == 0x5b) + continue; + } + sisfb_mode_idx = i - 1; + j = 1; + break; + } + } + + if((!j) && !quiet) + printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr); +} + +#ifndef MODULE +static void sisfb_get_vga_mode_from_kernel(void) +{ +#ifdef CONFIG_X86 + char mymode[32]; + int mydepth = screen_info.lfb_depth; + + if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return; + + if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) && + (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) && + (mydepth >= 8) && (mydepth <= 32) ) { + + if(mydepth == 24) mydepth = 32; + + sprintf(mymode, "%ux%ux%u", screen_info.lfb_width, + screen_info.lfb_height, + mydepth); + + printk(KERN_DEBUG + "sisfb: Using vga mode %s pre-set by kernel as default\n", + mymode); + + sisfb_search_mode(mymode, true); + } +#endif + return; +} +#endif + +static void __init +sisfb_search_crt2type(const char *name) +{ + int i = 0; + + /* We don't know the hardware specs yet and there is no ivideo */ + + if(name == NULL) return; + + while(sis_crt2type[i].type_no != -1) { + if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) { + sisfb_crt2type = sis_crt2type[i].type_no; + sisfb_tvplug = sis_crt2type[i].tvplug_no; + sisfb_crt2flags = sis_crt2type[i].flags; + break; + } + i++; + } + + sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0; + sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0; + + if(sisfb_crt2type < 0) + printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name); +} + +static void __init +sisfb_search_tvstd(const char *name) +{ + int i = 0; + + /* We don't know the hardware specs yet and there is no ivideo */ + + if(name == NULL) + return; + + while(sis_tvtype[i].type_no != -1) { + if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) { + sisfb_tvstd = sis_tvtype[i].type_no; + break; + } + i++; + } +} + +static void __init +sisfb_search_specialtiming(const char *name) +{ + int i = 0; + bool found = false; + + /* We don't know the hardware specs yet and there is no ivideo */ + + if(name == NULL) + return; + + if(!strnicmp(name, "none", 4)) { + sisfb_specialtiming = CUT_FORCENONE; + printk(KERN_DEBUG "sisfb: Special timing disabled\n"); + } else { + while(mycustomttable[i].chipID != 0) { + if(!strnicmp(name,mycustomttable[i].optionName, + strlen(mycustomttable[i].optionName))) { + sisfb_specialtiming = mycustomttable[i].SpecialID; + found = true; + printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n", + mycustomttable[i].vendorName, + mycustomttable[i].cardName, + mycustomttable[i].optionName); + break; + } + i++; + } + if(!found) { + printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:"); + printk(KERN_WARNING "\t\"none\" (to disable special timings)\n"); + i = 0; + while(mycustomttable[i].chipID != 0) { + printk(KERN_WARNING "\t\"%s\" (for %s %s)\n", + mycustomttable[i].optionName, + mycustomttable[i].vendorName, + mycustomttable[i].cardName); + i++; + } + } + } +} + +/* ----------- Various detection routines ----------- */ + +static void sisfb_detect_custom_timing(struct sis_video_info *ivideo) +{ + unsigned char *biosver = NULL; + unsigned char *biosdate = NULL; + bool footprint; + u32 chksum = 0; + int i, j; + + if(ivideo->SiS_Pr.UseROM) { + biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06; + biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c; + for(i = 0; i < 32768; i++) + chksum += ivideo->SiS_Pr.VirtualRomBase[i]; + } + + i = 0; + do { + if( (mycustomttable[i].chipID == ivideo->chip) && + ((!strlen(mycustomttable[i].biosversion)) || + (ivideo->SiS_Pr.UseROM && + (!strncmp(mycustomttable[i].biosversion, biosver, + strlen(mycustomttable[i].biosversion))))) && + ((!strlen(mycustomttable[i].biosdate)) || + (ivideo->SiS_Pr.UseROM && + (!strncmp(mycustomttable[i].biosdate, biosdate, + strlen(mycustomttable[i].biosdate))))) && + ((!mycustomttable[i].bioschksum) || + (ivideo->SiS_Pr.UseROM && + (mycustomttable[i].bioschksum == chksum))) && + (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) && + (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) { + footprint = true; + for(j = 0; j < 5; j++) { + if(mycustomttable[i].biosFootprintAddr[j]) { + if(ivideo->SiS_Pr.UseROM) { + if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] != + mycustomttable[i].biosFootprintData[j]) { + footprint = false; + } + } else + footprint = false; + } + } + if(footprint) { + ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID; + printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n", + mycustomttable[i].vendorName, + mycustomttable[i].cardName); + printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n", + mycustomttable[i].optionName); + break; + } + } + i++; + } while(mycustomttable[i].chipID); +} + +static bool sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) +{ + int i, j, xres, yres, refresh, index; + u32 emodes; + + if(buffer[0] != 0x00 || buffer[1] != 0xff || + buffer[2] != 0xff || buffer[3] != 0xff || + buffer[4] != 0xff || buffer[5] != 0xff || + buffer[6] != 0xff || buffer[7] != 0x00) { + printk(KERN_DEBUG "sisfb: Bad EDID header\n"); + return false; + } + + if(buffer[0x12] != 0x01) { + printk(KERN_INFO "sisfb: EDID version %d not supported\n", + buffer[0x12]); + return false; + } + + monitor->feature = buffer[0x18]; + + if(!(buffer[0x14] & 0x80)) { + if(!(buffer[0x14] & 0x08)) { + printk(KERN_INFO + "sisfb: WARNING: Monitor does not support separate syncs\n"); + } + } + + if(buffer[0x13] >= 0x01) { + /* EDID V1 rev 1 and 2: Search for monitor descriptor + * to extract ranges + */ + j = 0x36; + for(i=0; i<4; i++) { + if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 && + buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd && + buffer[j + 4] == 0x00) { + monitor->hmin = buffer[j + 7]; + monitor->hmax = buffer[j + 8]; + monitor->vmin = buffer[j + 5]; + monitor->vmax = buffer[j + 6]; + monitor->dclockmax = buffer[j + 9] * 10 * 1000; + monitor->datavalid = true; + break; + } + j += 18; + } + } + + if(!monitor->datavalid) { + /* Otherwise: Get a range from the list of supported + * Estabished Timings. This is not entirely accurate, + * because fixed frequency monitors are not supported + * that way. + */ + monitor->hmin = 65535; monitor->hmax = 0; + monitor->vmin = 65535; monitor->vmax = 0; + monitor->dclockmax = 0; + emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16); + for(i = 0; i < 13; i++) { + if(emodes & sisfb_ddcsmodes[i].mask) { + if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h; + if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1; + if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v; + if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v; + if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d; + } + } + index = 0x26; + for(i = 0; i < 8; i++) { + xres = (buffer[index] + 31) * 8; + switch(buffer[index + 1] & 0xc0) { + case 0xc0: yres = (xres * 9) / 16; break; + case 0x80: yres = (xres * 4) / 5; break; + case 0x40: yres = (xres * 3) / 4; break; + default: yres = xres; break; + } + refresh = (buffer[index + 1] & 0x3f) + 60; + if((xres >= 640) && (yres >= 480)) { + for(j = 0; j < 8; j++) { + if((xres == sisfb_ddcfmodes[j].x) && + (yres == sisfb_ddcfmodes[j].y) && + (refresh == sisfb_ddcfmodes[j].v)) { + if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h; + if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1; + if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v; + if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v; + if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d; + } + } + } + index += 2; + } + if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) { + monitor->datavalid = true; + } + } + + return monitor->datavalid; +} + +static void sisfb_handle_ddc(struct sis_video_info *ivideo, + struct sisfb_monitor *monitor, int crtno) +{ + unsigned short temp, i, realcrtno = crtno; + unsigned char buffer[256]; + + monitor->datavalid = false; + + if(crtno) { + if(ivideo->vbflags & CRT2_LCD) realcrtno = 1; + else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2; + else return; + } + + if((ivideo->sisfb_crt1off) && (!crtno)) + return; + + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, + realcrtno, 0, &buffer[0], ivideo->vbflags2); + if((!temp) || (temp == 0xffff)) { + printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1); + return; + } else { + printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1); + printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n", + crtno + 1, + (temp & 0x1a) ? "" : "[none of the supported]", + (temp & 0x02) ? "2 " : "", + (temp & 0x08) ? "D&P" : "", + (temp & 0x10) ? "FPDI-2" : ""); + if(temp & 0x02) { + i = 3; /* Number of retrys */ + do { + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, + realcrtno, 1, &buffer[0], ivideo->vbflags2); + } while((temp) && i--); + if(!temp) { + if(sisfb_interpret_edid(monitor, &buffer[0])) { + printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n", + monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax, + monitor->dclockmax / 1000); + } else { + printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1); + } + } else { + printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1); + } + } else { + printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n"); + } + } +} + +/* -------------- Mode validation --------------- */ + +static bool +sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, + int mode_idx, int rate_idx, int rate) +{ + int htotal, vtotal; + unsigned int dclock, hsync; + + if(!monitor->datavalid) + return true; + + if(mode_idx < 0) + return false; + + /* Skip for 320x200, 320x240, 640x400 */ + switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) { + case 0x59: + case 0x41: + case 0x4f: + case 0x50: + case 0x56: + case 0x53: + case 0x2f: + case 0x5d: + case 0x5e: + return true; +#ifdef CONFIG_FB_SIS_315 + case 0x5a: + case 0x5b: + if(ivideo->sisvga_engine == SIS_315_VGA) return true; +#endif + } + + if(rate < (monitor->vmin - 1)) + return false; + if(rate > (monitor->vmax + 1)) + return false; + + if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, + sisbios_mode[mode_idx].mode_no[ivideo->mni], + &htotal, &vtotal, rate_idx)) { + dclock = (htotal * vtotal * rate) / 1000; + if(dclock > (monitor->dclockmax + 1000)) + return false; + hsync = dclock / htotal; + if(hsync < (monitor->hmin - 1)) + return false; + if(hsync > (monitor->hmax + 1)) + return false; + } else { + return false; + } + return true; +} + +static int +sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags) +{ + u16 xres=0, yres, myres; + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(!(sisbios_mode[myindex].chipset & MD_SIS300)) + return -1 ; + } +#endif +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + if(!(sisbios_mode[myindex].chipset & MD_SIS315)) + return -1; + } +#endif + + myres = sisbios_mode[myindex].yres; + + switch(vbflags & VB_DISPTYPE_DISP2) { + + case CRT2_LCD: + xres = ivideo->lcdxres; yres = ivideo->lcdyres; + + if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) && + (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) { + if(sisbios_mode[myindex].xres > xres) + return -1; + if(myres > yres) + return -1; + } + + if(ivideo->sisfb_fstn) { + if(sisbios_mode[myindex].xres == 320) { + if(myres == 240) { + switch(sisbios_mode[myindex].mode_no[1]) { + case 0x50: myindex = MODE_FSTN_8; break; + case 0x56: myindex = MODE_FSTN_16; break; + case 0x53: return -1; + } + } + } + } + + if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, + sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn, + ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) { + return -1; + } + break; + + case CRT2_TV: + if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, + sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) { + return -1; + } + break; + + case CRT2_VGA: + if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, + sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) { + return -1; + } + break; + } + + return myindex; +} + +static u8 +sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx) +{ + int i = 0; + u16 xres = sisbios_mode[mode_idx].xres; + u16 yres = sisbios_mode[mode_idx].yres; + + ivideo->rate_idx = 0; + while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) { + if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) { + if(sisfb_vrate[i].refresh == rate) { + ivideo->rate_idx = sisfb_vrate[i].idx; + break; + } else if(sisfb_vrate[i].refresh > rate) { + if((sisfb_vrate[i].refresh - rate) <= 3) { + DPRINTK("sisfb: Adjusting rate from %d up to %d\n", + rate, sisfb_vrate[i].refresh); + ivideo->rate_idx = sisfb_vrate[i].idx; + ivideo->refresh_rate = sisfb_vrate[i].refresh; + } else if((sisfb_vrate[i].idx != 1) && + ((rate - sisfb_vrate[i-1].refresh) <= 2)) { + DPRINTK("sisfb: Adjusting rate from %d down to %d\n", + rate, sisfb_vrate[i-1].refresh); + ivideo->rate_idx = sisfb_vrate[i-1].idx; + ivideo->refresh_rate = sisfb_vrate[i-1].refresh; + } + break; + } else if((rate - sisfb_vrate[i].refresh) <= 2) { + DPRINTK("sisfb: Adjusting rate from %d down to %d\n", + rate, sisfb_vrate[i].refresh); + ivideo->rate_idx = sisfb_vrate[i].idx; + break; + } + } + i++; + } + if(ivideo->rate_idx > 0) { + return ivideo->rate_idx; + } else { + printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n", + rate, xres, yres); + return 0; + } +} + +static bool +sisfb_bridgeisslave(struct sis_video_info *ivideo) +{ + unsigned char P1_00; + + if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) + return false; + + P1_00 = SiS_GetReg(SISPART1, 0x00); + if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) || + ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) { + return true; + } else { + return false; + } +} + +static bool +sisfballowretracecrt1(struct sis_video_info *ivideo) +{ + u8 temp; + + temp = SiS_GetReg(SISCR, 0x17); + if(!(temp & 0x80)) + return false; + + temp = SiS_GetReg(SISSR, 0x1f); + if(temp & 0xc0) + return false; + + return true; +} + +static bool +sisfbcheckvretracecrt1(struct sis_video_info *ivideo) +{ + if(!sisfballowretracecrt1(ivideo)) + return false; + + if (SiS_GetRegByte(SISINPSTAT) & 0x08) + return true; + else + return false; +} + +static void +sisfbwaitretracecrt1(struct sis_video_info *ivideo) +{ + int watchdog; + + if(!sisfballowretracecrt1(ivideo)) + return; + + watchdog = 65536; + while ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog); + watchdog = 65536; + while ((SiS_GetRegByte(SISINPSTAT) & 0x08) && --watchdog); +} + +static bool +sisfbcheckvretracecrt2(struct sis_video_info *ivideo) +{ + unsigned char temp, reg; + + switch(ivideo->sisvga_engine) { + case SIS_300_VGA: reg = 0x25; break; + case SIS_315_VGA: reg = 0x30; break; + default: return false; + } + + temp = SiS_GetReg(SISPART1, reg); + if(temp & 0x02) + return true; + else + return false; +} + +static bool +sisfb_CheckVBRetrace(struct sis_video_info *ivideo) +{ + if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + if(!sisfb_bridgeisslave(ivideo)) { + return sisfbcheckvretracecrt2(ivideo); + } + } + return sisfbcheckvretracecrt1(ivideo); +} + +static u32 +sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount) +{ + u8 idx, reg1, reg2, reg3, reg4; + u32 ret = 0; + + (*vcount) = (*hcount) = 0; + + if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) { + + ret |= (FB_VBLANK_HAVE_VSYNC | + FB_VBLANK_HAVE_HBLANK | + FB_VBLANK_HAVE_VBLANK | + FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_HCOUNT); + switch(ivideo->sisvga_engine) { + case SIS_300_VGA: idx = 0x25; break; + default: + case SIS_315_VGA: idx = 0x30; break; + } + reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */ + reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */ + reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */ + reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 33 */ + if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING; + if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING; + if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING; + (*vcount) = reg3 | ((reg4 & 0x70) << 4); + (*hcount) = reg2 | ((reg4 & 0x0f) << 8); + + } else if(sisfballowretracecrt1(ivideo)) { + + ret |= (FB_VBLANK_HAVE_VSYNC | + FB_VBLANK_HAVE_VBLANK | + FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_HCOUNT); + reg1 = SiS_GetRegByte(SISINPSTAT); + if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING; + if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING; + reg1 = SiS_GetReg(SISCR, 0x20); + reg1 = SiS_GetReg(SISCR, 0x1b); + reg2 = SiS_GetReg(SISCR, 0x1c); + reg3 = SiS_GetReg(SISCR, 0x1d); + (*vcount) = reg2 | ((reg3 & 0x07) << 8); + (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3; + } + + return ret; +} + +static int +sisfb_myblank(struct sis_video_info *ivideo, int blank) +{ + u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13; + bool backlight = true; + + switch(blank) { + case FB_BLANK_UNBLANK: /* on */ + sr01 = 0x00; + sr11 = 0x00; + sr1f = 0x00; + cr63 = 0x00; + p2_0 = 0x20; + p1_13 = 0x00; + backlight = true; + break; + case FB_BLANK_NORMAL: /* blank */ + sr01 = 0x20; + sr11 = 0x00; + sr1f = 0x00; + cr63 = 0x00; + p2_0 = 0x20; + p1_13 = 0x00; + backlight = true; + break; + case FB_BLANK_VSYNC_SUSPEND: /* no vsync */ + sr01 = 0x20; + sr11 = 0x08; + sr1f = 0x80; + cr63 = 0x40; + p2_0 = 0x40; + p1_13 = 0x80; + backlight = false; + break; + case FB_BLANK_HSYNC_SUSPEND: /* no hsync */ + sr01 = 0x20; + sr11 = 0x08; + sr1f = 0x40; + cr63 = 0x40; + p2_0 = 0x80; + p1_13 = 0x40; + backlight = false; + break; + case FB_BLANK_POWERDOWN: /* off */ + sr01 = 0x20; + sr11 = 0x08; + sr1f = 0xc0; + cr63 = 0x40; + p2_0 = 0xc0; + p1_13 = 0xc0; + backlight = false; + break; + default: + return 1; + } + + if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) { + + if( (!ivideo->sisfb_thismonitor.datavalid) || + ((ivideo->sisfb_thismonitor.datavalid) && + (ivideo->sisfb_thismonitor.feature & 0xe0))) { + + if(ivideo->sisvga_engine == SIS_315_VGA) { + SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63); + } + + if(!(sisfb_bridgeisslave(ivideo))) { + SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01); + SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, sr1f); + } + } + + } + + if(ivideo->currentvbflags & CRT2_LCD) { + + if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) { + if(backlight) { + SiS_SiS30xBLOn(&ivideo->SiS_Pr); + } else { + SiS_SiS30xBLOff(&ivideo->SiS_Pr); + } + } else if(ivideo->sisvga_engine == SIS_315_VGA) { +#ifdef CONFIG_FB_SIS_315 + if(ivideo->vbflags2 & VB2_CHRONTEL) { + if(backlight) { + SiS_Chrontel701xBLOn(&ivideo->SiS_Pr); + } else { + SiS_Chrontel701xBLOff(&ivideo->SiS_Pr); + } + } +#endif + } + + if(((ivideo->sisvga_engine == SIS_300_VGA) && + (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) || + ((ivideo->sisvga_engine == SIS_315_VGA) && + ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) { + SiS_SetRegANDOR(SISSR, 0x11, ~0x0c, sr11); + } + + if(ivideo->sisvga_engine == SIS_300_VGA) { + if((ivideo->vbflags2 & VB2_30xB) && + (!(ivideo->vbflags2 & VB2_30xBDH))) { + SiS_SetRegANDOR(SISPART1, 0x13, 0x3f, p1_13); + } + } else if(ivideo->sisvga_engine == SIS_315_VGA) { + if((ivideo->vbflags2 & VB2_30xB) && + (!(ivideo->vbflags2 & VB2_30xBDH))) { + SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0); + } + } + + } else if(ivideo->currentvbflags & CRT2_VGA) { + + if(ivideo->vbflags2 & VB2_30xB) { + SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0); + } + + } + + return 0; +} + +/* ------------- Callbacks from init.c/init301.c -------------- */ + +#ifdef CONFIG_FB_SIS_300 +unsigned int +sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + u32 val = 0; + + pci_read_config_dword(ivideo->nbridge, reg, &val); + return (unsigned int)val; +} + +void +sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + + pci_write_config_dword(ivideo->nbridge, reg, (u32)val); +} + +unsigned int +sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + u32 val = 0; + + if(!ivideo->lpcdev) return 0; + + pci_read_config_dword(ivideo->lpcdev, reg, &val); + return (unsigned int)val; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +void +sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + + pci_write_config_byte(ivideo->nbridge, reg, (u8)val); +} + +unsigned int +sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + u16 val = 0; + + if(!ivideo->lpcdev) return 0; + + pci_read_config_word(ivideo->lpcdev, reg, &val); + return (unsigned int)val; +} +#endif + +/* ----------- FBDev related routines for all series ----------- */ + +static int +sisfb_get_cmap_len(const struct fb_var_screeninfo *var) +{ + return (var->bits_per_pixel == 8) ? 256 : 16; +} + +static void +sisfb_set_vparms(struct sis_video_info *ivideo) +{ + switch(ivideo->video_bpp) { + case 8: + ivideo->DstColor = 0x0000; + ivideo->SiS310_AccelDepth = 0x00000000; + ivideo->video_cmap_len = 256; + break; + case 16: + ivideo->DstColor = 0x8000; + ivideo->SiS310_AccelDepth = 0x00010000; + ivideo->video_cmap_len = 16; + break; + case 32: + ivideo->DstColor = 0xC000; + ivideo->SiS310_AccelDepth = 0x00020000; + ivideo->video_cmap_len = 16; + break; + default: + ivideo->video_cmap_len = 16; + printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp); + ivideo->accel = 0; + } +} + +static int +sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +{ + int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3)); + + if(maxyres > 32767) maxyres = 32767; + + return maxyres; +} + +static void +sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +{ + ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3); + ivideo->scrnpitchCRT1 = ivideo->video_linelength; + if(!(ivideo->currentvbflags & CRT1_LCDA)) { + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + ivideo->scrnpitchCRT1 <<= 1; + } + } +} + +static void +sisfb_set_pitch(struct sis_video_info *ivideo) +{ + bool isslavemode = false; + unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3; + unsigned short HDisplay2 = ivideo->video_linelength >> 3; + + if(sisfb_bridgeisslave(ivideo)) isslavemode = true; + + /* We need to set pitch for CRT1 if bridge is in slave mode, too */ + if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) { + SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF)); + SiS_SetRegANDOR(SISSR, 0x0E, 0xF0, (HDisplay1 >> 8)); + } + + /* We must not set the pitch for CRT2 if bridge is in slave mode */ + if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) { + SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01); + SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF)); + SiS_SetRegANDOR(SISPART1, 0x09, 0xF0, (HDisplay2 >> 8)); + } +} + +static void +sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +{ + ivideo->video_cmap_len = sisfb_get_cmap_len(var); + + switch(var->bits_per_pixel) { + case 8: + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 32: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + } +} + +static int +sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn) +{ + unsigned short modeno = ivideo->mode_no; + + /* >=2.6.12's fbcon clears the screen anyway */ + modeno |= 0x80; + + SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); + + sisfb_pre_setmode(ivideo); + + if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) { + printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no); + return -EINVAL; + } + + SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); + + sisfb_post_setmode(ivideo); + + return 0; +} + + +static int +sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + unsigned int htotal = 0, vtotal = 0; + unsigned int drate = 0, hrate = 0; + int found_mode = 0, ret; + int old_mode; + u32 pixclock; + + htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; + + vtotal = var->upper_margin + var->lower_margin + var->vsync_len; + + pixclock = var->pixclock; + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + vtotal += var->yres; + vtotal <<= 2; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else vtotal += var->yres; + + if(!(htotal) || !(vtotal)) { + DPRINTK("sisfb: Invalid 'var' information\n"); + return -EINVAL; + } + + if(pixclock && htotal && vtotal) { + drate = 1000000000 / pixclock; + hrate = (drate * 1000) / htotal; + ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal); + } else { + ivideo->refresh_rate = 60; + } + + old_mode = ivideo->sisfb_mode_idx; + ivideo->sisfb_mode_idx = 0; + + while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) && + (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) { + if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) && + (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) && + (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) { + ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]; + found_mode = 1; + break; + } + ivideo->sisfb_mode_idx++; + } + + if(found_mode) { + ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo, + ivideo->sisfb_mode_idx, ivideo->currentvbflags); + } else { + ivideo->sisfb_mode_idx = -1; + } + + if(ivideo->sisfb_mode_idx < 0) { + printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres, + var->yres, var->bits_per_pixel); + ivideo->sisfb_mode_idx = old_mode; + return -EINVAL; + } + + ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]; + + if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) { + ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx; + ivideo->refresh_rate = 60; + } + + if(isactive) { + /* If acceleration to be used? Need to know + * before pre/post_set_mode() + */ + ivideo->accel = 0; +#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN) +#ifdef STUPID_ACCELF_TEXT_SHIT + if(var->accel_flags & FB_ACCELF_TEXT) { + info->flags &= ~FBINFO_HWACCEL_DISABLED; + } else { + info->flags |= FBINFO_HWACCEL_DISABLED; + } +#endif + if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1; +#else + if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1; +#endif + + if((ret = sisfb_set_mode(ivideo, 1))) { + return ret; + } + + ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp; + ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres; + ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres; + + sisfb_calc_pitch(ivideo, var); + sisfb_set_pitch(ivideo); + + sisfb_set_vparms(ivideo); + + ivideo->current_width = ivideo->video_width; + ivideo->current_height = ivideo->video_height; + ivideo->current_bpp = ivideo->video_bpp; + ivideo->current_htotal = htotal; + ivideo->current_vtotal = vtotal; + ivideo->current_linelength = ivideo->video_linelength; + ivideo->current_pixclock = var->pixclock; + ivideo->current_refresh_rate = ivideo->refresh_rate; + ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate; + } + + return 0; +} + +static void +sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base) +{ + SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); + + SiS_SetReg(SISCR, 0x0D, base & 0xFF); + SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF); + SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF); + if(ivideo->sisvga_engine == SIS_315_VGA) { + SiS_SetRegANDOR(SISSR, 0x37, 0xFE, (base >> 24) & 0x01); + } +} + +static void +sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base) +{ + if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01); + SiS_SetReg(SISPART1, 0x06, (base & 0xFF)); + SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF)); + SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF)); + if(ivideo->sisvga_engine == SIS_315_VGA) { + SiS_SetRegANDOR(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7); + } + } +} + +static int +sisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info, + struct fb_var_screeninfo *var) +{ + ivideo->current_base = var->yoffset * info->var.xres_virtual + + var->xoffset; + + /* calculate base bpp dep. */ + switch (info->var.bits_per_pixel) { + case 32: + break; + case 16: + ivideo->current_base >>= 1; + break; + case 8: + default: + ivideo->current_base >>= 2; + break; + } + + ivideo->current_base += (ivideo->video_offset >> 2); + + sisfb_set_base_CRT1(ivideo, ivideo->current_base); + sisfb_set_base_CRT2(ivideo, ivideo->current_base); + + return 0; +} + +static int +sisfb_open(struct fb_info *info, int user) +{ + return 0; +} + +static int +sisfb_release(struct fb_info *info, int user) +{ + return 0; +} + +static int +sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + if(regno >= sisfb_get_cmap_len(&info->var)) + return 1; + + switch(info->var.bits_per_pixel) { + case 8: + SiS_SetRegByte(SISDACA, regno); + SiS_SetRegByte(SISDACD, (red >> 10)); + SiS_SetRegByte(SISDACD, (green >> 10)); + SiS_SetRegByte(SISDACD, (blue >> 10)); + if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + SiS_SetRegByte(SISDAC2A, regno); + SiS_SetRegByte(SISDAC2D, (red >> 8)); + SiS_SetRegByte(SISDAC2D, (green >> 8)); + SiS_SetRegByte(SISDAC2D, (blue >> 8)); + } + break; + case 16: + if (regno >= 16) + break; + + ((u32 *)(info->pseudo_palette))[regno] = + (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 32: + if (regno >= 16) + break; + + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(info->pseudo_palette))[regno] = + (red << 16) | (green << 8) | (blue); + break; + } + return 0; +} + +static int +sisfb_set_par(struct fb_info *info) +{ + int err; + + if((err = sisfb_do_set_var(&info->var, 1, info))) + return err; + + sisfb_get_fix(&info->fix, -1, info); + + return 0; +} + +static int +sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + unsigned int htotal = 0, vtotal = 0, myrateindex = 0; + unsigned int drate = 0, hrate = 0, maxyres; + int found_mode = 0; + int refresh_rate, search_idx, tidx; + bool recalc_clock = false; + u32 pixclock; + + htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; + + vtotal = var->upper_margin + var->lower_margin + var->vsync_len; + + pixclock = var->pixclock; + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + vtotal += var->yres; + vtotal <<= 2; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else + vtotal += var->yres; + + if(!(htotal) || !(vtotal)) { + SISFAIL("sisfb: no valid timing data"); + } + + search_idx = 0; + while( (sisbios_mode[search_idx].mode_no[0] != 0) && + (sisbios_mode[search_idx].xres <= var->xres) ) { + if( (sisbios_mode[search_idx].xres == var->xres) && + (sisbios_mode[search_idx].yres == var->yres) && + (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) { + if((tidx = sisfb_validate_mode(ivideo, search_idx, + ivideo->currentvbflags)) > 0) { + found_mode = 1; + search_idx = tidx; + break; + } + } + search_idx++; + } + + if(!found_mode) { + search_idx = 0; + while(sisbios_mode[search_idx].mode_no[0] != 0) { + if( (var->xres <= sisbios_mode[search_idx].xres) && + (var->yres <= sisbios_mode[search_idx].yres) && + (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) { + if((tidx = sisfb_validate_mode(ivideo,search_idx, + ivideo->currentvbflags)) > 0) { + found_mode = 1; + search_idx = tidx; + break; + } + } + search_idx++; + } + if(found_mode) { + printk(KERN_DEBUG + "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n", + var->xres, var->yres, var->bits_per_pixel, + sisbios_mode[search_idx].xres, + sisbios_mode[search_idx].yres, + var->bits_per_pixel); + var->xres = sisbios_mode[search_idx].xres; + var->yres = sisbios_mode[search_idx].yres; + } else { + printk(KERN_ERR + "sisfb: Failed to find supported mode near %dx%dx%d\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + } + + if( ((ivideo->vbflags2 & VB2_LVDS) || + ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) && + (var->bits_per_pixel == 8) ) { + /* Slave modes on LVDS and 301B-DH */ + refresh_rate = 60; + recalc_clock = true; + } else if( (ivideo->current_htotal == htotal) && + (ivideo->current_vtotal == vtotal) && + (ivideo->current_pixclock == pixclock) ) { + /* x=x & y=y & c=c -> assume depth change */ + drate = 1000000000 / pixclock; + hrate = (drate * 1000) / htotal; + refresh_rate = (unsigned int) (hrate * 2 / vtotal); + } else if( ( (ivideo->current_htotal != htotal) || + (ivideo->current_vtotal != vtotal) ) && + (ivideo->current_pixclock == var->pixclock) ) { + /* x!=x | y!=y & c=c -> invalid pixclock */ + if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) { + refresh_rate = + ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]; + } else if(ivideo->sisfb_parm_rate != -1) { + /* Sic, sisfb_parm_rate - want to know originally desired rate here */ + refresh_rate = ivideo->sisfb_parm_rate; + } else { + refresh_rate = 60; + } + recalc_clock = true; + } else if((pixclock) && (htotal) && (vtotal)) { + drate = 1000000000 / pixclock; + hrate = (drate * 1000) / htotal; + refresh_rate = (unsigned int) (hrate * 2 / vtotal); + } else if(ivideo->current_refresh_rate) { + refresh_rate = ivideo->current_refresh_rate; + recalc_clock = true; + } else { + refresh_rate = 60; + recalc_clock = true; + } + + myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx); + + /* Eventually recalculate timing and clock */ + if(recalc_clock) { + if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx; + var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, + sisbios_mode[search_idx].mode_no[ivideo->mni], + myrateindex)); + sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, + sisbios_mode[search_idx].mode_no[ivideo->mni], + myrateindex, var); + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + var->pixclock <<= 1; + } + } + + if(ivideo->sisfb_thismonitor.datavalid) { + if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx, + myrateindex, refresh_rate)) { + printk(KERN_INFO + "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); + } + } + + /* Adapt RGB settings */ + sisfb_bpp_to_var(ivideo, var); + + /* Sanity check for offsets */ + if(var->xoffset < 0) var->xoffset = 0; + if(var->yoffset < 0) var->yoffset = 0; + + if(var->xres > var->xres_virtual) + var->xres_virtual = var->xres; + + if(ivideo->sisfb_ypan) { + maxyres = sisfb_calc_maxyres(ivideo, var); + if(ivideo->sisfb_max) { + var->yres_virtual = maxyres; + } else { + if(var->yres_virtual > maxyres) { + var->yres_virtual = maxyres; + } + } + if(var->yres_virtual <= var->yres) { + var->yres_virtual = var->yres; + } + } else { + if(var->yres != var->yres_virtual) { + var->yres_virtual = var->yres; + } + var->xoffset = 0; + var->yoffset = 0; + } + + /* Truncate offsets to maximum if too high */ + if(var->xoffset > var->xres_virtual - var->xres) { + var->xoffset = var->xres_virtual - var->xres - 1; + } + + if(var->yoffset > var->yres_virtual - var->yres) { + var->yoffset = var->yres_virtual - var->yres - 1; + } + + /* Set everything else to 0 */ + var->red.msb_right = + var->green.msb_right = + var->blue.msb_right = + var->transp.offset = + var->transp.length = + var->transp.msb_right = 0; + + return 0; +} + +static int +sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + int err; + + if (var->vmode & FB_VMODE_YWRAP) + return -EINVAL; + + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + err = sisfb_pan_var(ivideo, info, var); + if (err < 0) + return err; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + return 0; +} + +static int +sisfb_blank(int blank, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + return sisfb_myblank(ivideo, blank); +} + +/* ----------- FBDev related routines for all series ---------- */ + +static int sisfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + struct sis_memreq sismemreq; + struct fb_vblank sisvbblank; + u32 gpu32 = 0; +#ifndef __user +#define __user +#endif + u32 __user *argp = (u32 __user *)arg; + + switch(cmd) { + case FBIO_ALLOC: + if(!capable(CAP_SYS_RAWIO)) + return -EPERM; + + if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) + return -EFAULT; + + sis_malloc(&sismemreq); + + if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) { + sis_free((u32)sismemreq.offset); + return -EFAULT; + } + break; + + case FBIO_FREE: + if(!capable(CAP_SYS_RAWIO)) + return -EPERM; + + if(get_user(gpu32, argp)) + return -EFAULT; + + sis_free(gpu32); + break; + + case FBIOGET_VBLANK: + + memset(&sisvbblank, 0, sizeof(struct fb_vblank)); + + sisvbblank.count = 0; + sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount); + + if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) + return -EFAULT; + + break; + + case SISFB_GET_INFO_SIZE: + return put_user(sizeof(struct sisfb_info), argp); + + case SISFB_GET_INFO_OLD: + if(ivideo->warncount++ < 10) + printk(KERN_INFO + "sisfb: Deprecated ioctl call received - update your application!\n"); + case SISFB_GET_INFO: /* For communication with X driver */ + ivideo->sisfb_infoblock.sisfb_id = SISFB_ID; + ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR; + ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR; + ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL; + ivideo->sisfb_infoblock.chip_id = ivideo->chip_id; + ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor; + ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024; + ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024; + if(ivideo->modechanged) { + ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no; + } else { + ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange; + } + ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps; + ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024; + ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus; + ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot; + ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc; + ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc; + ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca; + ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda; + ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags; + ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags; + ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler; + ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT; + ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0; + ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0; + ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30; + ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31; + ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32; + ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33; + ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32); + ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32); + ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024; + ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset; + ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN; + ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN; + ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2; + ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0; + ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0; + ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0; + + if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock, + sizeof(ivideo->sisfb_infoblock))) + return -EFAULT; + + break; + + case SISFB_GET_VBRSTATUS_OLD: + if(ivideo->warncount++ < 10) + printk(KERN_INFO + "sisfb: Deprecated ioctl call received - update your application!\n"); + case SISFB_GET_VBRSTATUS: + if(sisfb_CheckVBRetrace(ivideo)) + return put_user((u32)1, argp); + else + return put_user((u32)0, argp); + + case SISFB_GET_AUTOMAXIMIZE_OLD: + if(ivideo->warncount++ < 10) + printk(KERN_INFO + "sisfb: Deprecated ioctl call received - update your application!\n"); + case SISFB_GET_AUTOMAXIMIZE: + if(ivideo->sisfb_max) + return put_user((u32)1, argp); + else + return put_user((u32)0, argp); + + case SISFB_SET_AUTOMAXIMIZE_OLD: + if(ivideo->warncount++ < 10) + printk(KERN_INFO + "sisfb: Deprecated ioctl call received - update your application!\n"); + case SISFB_SET_AUTOMAXIMIZE: + if(get_user(gpu32, argp)) + return -EFAULT; + + ivideo->sisfb_max = (gpu32) ? 1 : 0; + break; + + case SISFB_SET_TVPOSOFFSET: + if(get_user(gpu32, argp)) + return -EFAULT; + + sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32); + sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32); + break; + + case SISFB_GET_TVPOSOFFSET: + return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)), + argp); + + case SISFB_COMMAND: + if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg, + sizeof(struct sisfb_cmd))) + return -EFAULT; + + sisfb_handle_command(ivideo, &ivideo->sisfb_command); + + if(copy_to_user((void __user *)arg, &ivideo->sisfb_command, + sizeof(struct sisfb_cmd))) + return -EFAULT; + + break; + + case SISFB_SET_LOCK: + if(get_user(gpu32, argp)) + return -EFAULT; + + ivideo->sisfblocked = (gpu32) ? 1 : 0; + break; + + default: +#ifdef SIS_NEW_CONFIG_COMPAT + return -ENOIOCTLCMD; +#else + return -EINVAL; +#endif + } + return 0; +} + +static int +sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + + strlcpy(fix->id, ivideo->myid, sizeof(fix->id)); + + mutex_lock(&info->mm_lock); + fix->smem_start = ivideo->video_base + ivideo->video_offset; + fix->smem_len = ivideo->sisfb_mem; + mutex_unlock(&info->mm_lock); + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0; + fix->ywrapstep = 0; + fix->line_length = ivideo->video_linelength; + fix->mmio_start = ivideo->mmio_base; + fix->mmio_len = ivideo->mmio_size; + if(ivideo->sisvga_engine == SIS_300_VGA) { + fix->accel = FB_ACCEL_SIS_GLAMOUR; + } else if((ivideo->chip == SIS_330) || + (ivideo->chip == SIS_760) || + (ivideo->chip == SIS_761)) { + fix->accel = FB_ACCEL_SIS_XABRE; + } else if(ivideo->chip == XGI_20) { + fix->accel = FB_ACCEL_XGI_VOLARI_Z; + } else if(ivideo->chip >= XGI_40) { + fix->accel = FB_ACCEL_XGI_VOLARI_V; + } else { + fix->accel = FB_ACCEL_SIS_GLAMOUR_2; + } + + return 0; +} + +/* ---------------- fb_ops structures ----------------- */ + +static struct fb_ops sisfb_ops = { + .owner = THIS_MODULE, + .fb_open = sisfb_open, + .fb_release = sisfb_release, + .fb_check_var = sisfb_check_var, + .fb_set_par = sisfb_set_par, + .fb_setcolreg = sisfb_setcolreg, + .fb_pan_display = sisfb_pan_display, + .fb_blank = sisfb_blank, + .fb_fillrect = fbcon_sis_fillrect, + .fb_copyarea = fbcon_sis_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_sync = fbcon_sis_sync, +#ifdef SIS_NEW_CONFIG_COMPAT + .fb_compat_ioctl= sisfb_ioctl, +#endif + .fb_ioctl = sisfb_ioctl +}; + +/* ---------------- Chip generation dependent routines ---------------- */ + +static struct pci_dev *sisfb_get_northbridge(int basechipid) +{ + struct pci_dev *pdev = NULL; + int nbridgenum, nbridgeidx, i; + static const unsigned short nbridgeids[] = { + PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */ + PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */ + PCI_DEVICE_ID_SI_730, + PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */ + PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */ + PCI_DEVICE_ID_SI_651, + PCI_DEVICE_ID_SI_740, + PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */ + PCI_DEVICE_ID_SI_741, + PCI_DEVICE_ID_SI_660, + PCI_DEVICE_ID_SI_760, + PCI_DEVICE_ID_SI_761 + }; + + switch(basechipid) { +#ifdef CONFIG_FB_SIS_300 + case SIS_540: nbridgeidx = 0; nbridgenum = 1; break; + case SIS_630: nbridgeidx = 1; nbridgenum = 2; break; +#endif +#ifdef CONFIG_FB_SIS_315 + case SIS_550: nbridgeidx = 3; nbridgenum = 1; break; + case SIS_650: nbridgeidx = 4; nbridgenum = 3; break; + case SIS_660: nbridgeidx = 7; nbridgenum = 5; break; +#endif + default: return NULL; + } + for(i = 0; i < nbridgenum; i++) { + if((pdev = pci_get_device(PCI_VENDOR_ID_SI, + nbridgeids[nbridgeidx+i], NULL))) + break; + } + return pdev; +} + +static int sisfb_get_dram_size(struct sis_video_info *ivideo) +{ +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) + u8 reg; +#endif + + ivideo->video_size = 0; + ivideo->UMAsize = ivideo->LFBsize = 0; + + switch(ivideo->chip) { +#ifdef CONFIG_FB_SIS_300 + case SIS_300: + reg = SiS_GetReg(SISSR, 0x14); + ivideo->video_size = ((reg & 0x3F) + 1) << 20; + break; + case SIS_540: + case SIS_630: + case SIS_730: + if(!ivideo->nbridge) + return -1; + pci_read_config_byte(ivideo->nbridge, 0x63, ®); + ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21); + break; +#endif +#ifdef CONFIG_FB_SIS_315 + case SIS_315H: + case SIS_315PRO: + case SIS_315: + reg = SiS_GetReg(SISSR, 0x14); + ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; + switch((reg >> 2) & 0x03) { + case 0x01: + case 0x03: + ivideo->video_size <<= 1; + break; + case 0x02: + ivideo->video_size += (ivideo->video_size/2); + } + break; + case SIS_330: + reg = SiS_GetReg(SISSR, 0x14); + ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; + if(reg & 0x0c) ivideo->video_size <<= 1; + break; + case SIS_550: + case SIS_650: + case SIS_740: + reg = SiS_GetReg(SISSR, 0x14); + ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20; + break; + case SIS_661: + case SIS_741: + reg = SiS_GetReg(SISCR, 0x79); + ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; + break; + case SIS_660: + case SIS_760: + case SIS_761: + reg = SiS_GetReg(SISCR, 0x79); + reg = (reg & 0xf0) >> 4; + if(reg) { + ivideo->video_size = (1 << reg) << 20; + ivideo->UMAsize = ivideo->video_size; + } + reg = SiS_GetReg(SISCR, 0x78); + reg &= 0x30; + if(reg) { + if(reg == 0x10) { + ivideo->LFBsize = (32 << 20); + } else { + ivideo->LFBsize = (64 << 20); + } + ivideo->video_size += ivideo->LFBsize; + } + break; + case SIS_340: + case XGI_20: + case XGI_40: + reg = SiS_GetReg(SISSR, 0x14); + ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; + if(ivideo->chip != XGI_20) { + reg = (reg & 0x0c) >> 2; + if(ivideo->revision_id == 2) { + if(reg & 0x01) reg = 0x02; + else reg = 0x00; + } + if(reg == 0x02) ivideo->video_size <<= 1; + else if(reg == 0x03) ivideo->video_size <<= 2; + } + break; +#endif + default: + return -1; + } + return 0; +} + +/* -------------- video bridge device detection --------------- */ + +static void sisfb_detect_VB_connect(struct sis_video_info *ivideo) +{ + u8 cr32, temp; + + /* No CRT2 on XGI Z7 */ + if(ivideo->chip == XGI_20) { + ivideo->sisfb_crt1off = 0; + return; + } + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + temp = SiS_GetReg(SISSR, 0x17); + if((temp & 0x0F) && (ivideo->chip != SIS_300)) { + /* PAL/NTSC is stored on SR16 on such machines */ + if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) { + temp = SiS_GetReg(SISSR, 0x16); + if(temp & 0x20) + ivideo->vbflags |= TV_PAL; + else + ivideo->vbflags |= TV_NTSC; + } + } + } +#endif + + cr32 = SiS_GetReg(SISCR, 0x32); + + if(cr32 & SIS_CRT1) { + ivideo->sisfb_crt1off = 0; + } else { + ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0; + } + + ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA); + + if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV; + if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD; + if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA; + + /* Check given parms for hardware compatibility. + * (Cannot do this in the search_xx routines since we don't + * know what hardware we are running on then) + */ + + if(ivideo->chip != SIS_550) { + ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0; + } + + if(ivideo->sisfb_tvplug != -1) { + if( (ivideo->sisvga_engine != SIS_315_VGA) || + (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) { + if(ivideo->sisfb_tvplug & TV_YPBPR) { + ivideo->sisfb_tvplug = -1; + printk(KERN_ERR "sisfb: YPbPr not supported\n"); + } + } + } + if(ivideo->sisfb_tvplug != -1) { + if( (ivideo->sisvga_engine != SIS_315_VGA) || + (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) { + if(ivideo->sisfb_tvplug & TV_HIVISION) { + ivideo->sisfb_tvplug = -1; + printk(KERN_ERR "sisfb: HiVision not supported\n"); + } + } + } + if(ivideo->sisfb_tvstd != -1) { + if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) && + (!((ivideo->sisvga_engine == SIS_315_VGA) && + (ivideo->vbflags2 & VB2_CHRONTEL))) ) { + if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) { + ivideo->sisfb_tvstd = -1; + printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n"); + } + } + } + + /* Detect/set TV plug & type */ + if(ivideo->sisfb_tvplug != -1) { + ivideo->vbflags |= ivideo->sisfb_tvplug; + } else { + if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */ + else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION; + else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART; + else { + if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO; + if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO; + } + } + + if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) { + if(ivideo->sisfb_tvstd != -1) { + ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ); + ivideo->vbflags |= ivideo->sisfb_tvstd; + } + if(ivideo->vbflags & TV_SCART) { + ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ); + ivideo->vbflags |= TV_PAL; + } + if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) { + if(ivideo->sisvga_engine == SIS_300_VGA) { + temp = SiS_GetReg(SISSR, 0x38); + if(temp & 0x01) ivideo->vbflags |= TV_PAL; + else ivideo->vbflags |= TV_NTSC; + } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) { + temp = SiS_GetReg(SISSR, 0x38); + if(temp & 0x01) ivideo->vbflags |= TV_PAL; + else ivideo->vbflags |= TV_NTSC; + } else { + temp = SiS_GetReg(SISCR, 0x79); + if(temp & 0x20) ivideo->vbflags |= TV_PAL; + else ivideo->vbflags |= TV_NTSC; + } + } + } + + /* Copy forceCRT1 option to CRT1off if option is given */ + if(ivideo->sisfb_forcecrt1 != -1) { + ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1; + } +} + +/* ------------------ Sensing routines ------------------ */ + +static bool sisfb_test_DDC1(struct sis_video_info *ivideo) +{ + unsigned short old; + int count = 48; + + old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr); + do { + if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break; + } while(count--); + return (count != -1); +} + +static void sisfb_sense_crt1(struct sis_video_info *ivideo) +{ + bool mustwait = false; + u8 sr1F, cr17; +#ifdef CONFIG_FB_SIS_315 + u8 cr63=0; +#endif + u16 temp = 0xffff; + int i; + + sr1F = SiS_GetReg(SISSR, 0x1F); + SiS_SetRegOR(SISSR, 0x1F, 0x04); + SiS_SetRegAND(SISSR, 0x1F, 0x3F); + if(sr1F & 0xc0) mustwait = true; + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63); + cr63 &= 0x40; + SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF); + } +#endif + + cr17 = SiS_GetReg(SISCR, 0x17); + cr17 &= 0x80; + if(!cr17) { + SiS_SetRegOR(SISCR, 0x17, 0x80); + mustwait = true; + SiS_SetReg(SISSR, 0x00, 0x01); + SiS_SetReg(SISSR, 0x00, 0x03); + } + + if(mustwait) { + for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo); + } + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->chip >= SIS_330) { + SiS_SetRegAND(SISCR, 0x32, ~0x20); + if(ivideo->chip >= SIS_340) { + SiS_SetReg(SISCR, 0x57, 0x4a); + } else { + SiS_SetReg(SISCR, 0x57, 0x5f); + } + SiS_SetRegOR(SISCR, 0x53, 0x02); + while ((SiS_GetRegByte(SISINPSTAT)) & 0x01) break; + while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break; + if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1; + SiS_SetRegAND(SISCR, 0x53, 0xfd); + SiS_SetRegAND(SISCR, 0x57, 0x00); + } +#endif + + if(temp == 0xffff) { + i = 3; + do { + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, + ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2); + } while(((temp == 0) || (temp == 0xffff)) && i--); + + if((temp == 0) || (temp == 0xffff)) { + if(sisfb_test_DDC1(ivideo)) temp = 1; + } + } + + if((temp) && (temp != 0xffff)) { + SiS_SetRegOR(SISCR, 0x32, 0x20); + } + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63); + } +#endif + + SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17); + + SiS_SetReg(SISSR, 0x1F, sr1F); +} + +/* Determine and detect attached devices on SiS30x */ +static void SiS_SenseLCD(struct sis_video_info *ivideo) +{ + unsigned char buffer[256]; + unsigned short temp, realcrtno, i; + u8 reg, cr37 = 0, paneltype = 0; + u16 xres, yres; + + ivideo->SiS_Pr.PanelSelfDetected = false; + + /* LCD detection only for TMDS bridges */ + if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE)) + return; + if(ivideo->vbflags2 & VB2_30xBDH) + return; + + /* If LCD already set up by BIOS, skip it */ + reg = SiS_GetReg(SISCR, 0x32); + if(reg & 0x08) + return; + + realcrtno = 1; + if(ivideo->SiS_Pr.DDCPortMixup) + realcrtno = 0; + + /* Check DDC capabilities */ + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, + realcrtno, 0, &buffer[0], ivideo->vbflags2); + + if((!temp) || (temp == 0xffff) || (!(temp & 0x02))) + return; + + /* Read DDC data */ + i = 3; /* Number of retrys */ + do { + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, + ivideo->sisvga_engine, realcrtno, 1, + &buffer[0], ivideo->vbflags2); + } while((temp) && i--); + + if(temp) + return; + + /* No digital device */ + if(!(buffer[0x14] & 0x80)) + return; + + /* First detailed timing preferred timing? */ + if(!(buffer[0x18] & 0x02)) + return; + + xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4); + yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4); + + switch(xres) { + case 1024: + if(yres == 768) + paneltype = 0x02; + break; + case 1280: + if(yres == 1024) + paneltype = 0x03; + break; + case 1600: + if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC)) + paneltype = 0x0b; + break; + } + + if(!paneltype) + return; + + if(buffer[0x23]) + cr37 |= 0x10; + + if((buffer[0x47] & 0x18) == 0x18) + cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20); + else + cr37 |= 0xc0; + + SiS_SetReg(SISCR, 0x36, paneltype); + cr37 &= 0xf1; + SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37); + SiS_SetRegOR(SISCR, 0x32, 0x08); + + ivideo->SiS_Pr.PanelSelfDetected = true; +} + +static int SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test) +{ + int temp, mytest, result, i, j; + + for(j = 0; j < 10; j++) { + result = 0; + for(i = 0; i < 3; i++) { + mytest = test; + SiS_SetReg(SISPART4, 0x11, (type & 0x00ff)); + temp = (type >> 8) | (mytest & 0x00ff); + SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500); + mytest >>= 8; + mytest &= 0x7f; + temp = SiS_GetReg(SISPART4, 0x03); + temp ^= 0x0e; + temp &= mytest; + if(temp == mytest) result++; +#if 1 + SiS_SetReg(SISPART4, 0x11, 0x00); + SiS_SetRegAND(SISPART4, 0x10, 0xe0); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000); +#endif + } + if((result == 0) || (result >= 2)) break; + } + return result; +} + +static void SiS_Sense30x(struct sis_video_info *ivideo) +{ + u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0; + u16 svhs=0, svhs_c=0; + u16 cvbs=0, cvbs_c=0; + u16 vga2=0, vga2_c=0; + int myflag, result; + char stdstr[] = "sisfb: Detected"; + char tvstr[] = "TV connected to"; + + if(ivideo->vbflags2 & VB2_301) { + svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1; + myflag = SiS_GetReg(SISPART4, 0x01); + if(myflag & 0x04) { + svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd; + } + } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) { + svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190; + } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) { + svhs = 0x0200; cvbs = 0x0100; + } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) { + svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190; + } else + return; + + vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804; + if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) { + svhs_c = 0x0408; cvbs_c = 0x0808; + } + + biosflag = 2; + if(ivideo->haveXGIROM) { + biosflag = ivideo->bios_abase[0x58] & 0x03; + } else if(ivideo->newrom) { + if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01; + } else if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->bios_abase) { + biosflag = ivideo->bios_abase[0xfe] & 0x03; + } + } + + if(ivideo->chip == SIS_300) { + myflag = SiS_GetReg(SISSR, 0x3b); + if(!(myflag & 0x01)) vga2 = vga2_c = 0; + } + + if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) { + vga2 = vga2_c = 0; + } + + backupSR_1e = SiS_GetReg(SISSR, 0x1e); + SiS_SetRegOR(SISSR, 0x1e, 0x20); + + backupP4_0d = SiS_GetReg(SISPART4, 0x0d); + if(ivideo->vbflags2 & VB2_30xC) { + SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01); + } else { + SiS_SetRegOR(SISPART4, 0x0d, 0x04); + } + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000); + + backupP2_00 = SiS_GetReg(SISPART2, 0x00); + SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc)); + + backupP2_4d = SiS_GetReg(SISPART2, 0x4d); + if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) { + SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10)); + } + + if(!(ivideo->vbflags2 & VB2_30xCLV)) { + SISDoSense(ivideo, 0, 0); + } + + SiS_SetRegAND(SISCR, 0x32, ~0x14); + + if(vga2_c || vga2) { + if(SISDoSense(ivideo, vga2, vga2_c)) { + if(biosflag & 0x01) { + printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr); + SiS_SetRegOR(SISCR, 0x32, 0x04); + } else { + printk(KERN_INFO "%s secondary VGA connection\n", stdstr); + SiS_SetRegOR(SISCR, 0x32, 0x10); + } + } + } + + SiS_SetRegAND(SISCR, 0x32, 0x3f); + + if(ivideo->vbflags2 & VB2_30xCLV) { + SiS_SetRegOR(SISPART4, 0x0d, 0x04); + } + + if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) { + SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10)); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000); + if((result = SISDoSense(ivideo, svhs, 0x0604))) { + if((result = SISDoSense(ivideo, cvbs, 0x0804))) { + printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr); + SiS_SetRegOR(SISCR, 0x32, 0x80); + } + } + SiS_SetReg(SISPART2, 0x4d, backupP2_4d); + } + + SiS_SetRegAND(SISCR, 0x32, ~0x03); + + if(!(ivideo->vbflags & TV_YPBPR)) { + if((result = SISDoSense(ivideo, svhs, svhs_c))) { + printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr); + SiS_SetRegOR(SISCR, 0x32, 0x02); + } + if((biosflag & 0x02) || (!result)) { + if(SISDoSense(ivideo, cvbs, cvbs_c)) { + printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr); + SiS_SetRegOR(SISCR, 0x32, 0x01); + } + } + } + + SISDoSense(ivideo, 0, 0); + + SiS_SetReg(SISPART2, 0x00, backupP2_00); + SiS_SetReg(SISPART4, 0x0d, backupP4_0d); + SiS_SetReg(SISSR, 0x1e, backupSR_1e); + + if(ivideo->vbflags2 & VB2_30xCLV) { + biosflag = SiS_GetReg(SISPART2, 0x00); + if(biosflag & 0x20) { + for(myflag = 2; myflag > 0; myflag--) { + biosflag ^= 0x20; + SiS_SetReg(SISPART2, 0x00, biosflag); + } + } + } + + SiS_SetReg(SISPART2, 0x00, backupP2_00); +} + +/* Determine and detect attached TV's on Chrontel */ +static void SiS_SenseCh(struct sis_video_info *ivideo) +{ +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) + u8 temp1, temp2; + char stdstr[] = "sisfb: Chrontel: Detected TV connected to"; +#endif +#ifdef CONFIG_FB_SIS_300 + unsigned char test[3]; + int i; +#endif + + if(ivideo->chip < SIS_315H) { + +#ifdef CONFIG_FB_SIS_300 + ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */ + SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */ + SiS_DDC2Delay(&ivideo->SiS_Pr, 1000); + temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25); + /* See Chrontel TB31 for explanation */ + temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e); + if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) { + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b); + SiS_DDC2Delay(&ivideo->SiS_Pr, 300); + } + temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25); + if(temp2 != temp1) temp1 = temp2; + + if((temp1 >= 0x22) && (temp1 <= 0x50)) { + /* Read power status */ + temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e); + if((temp1 & 0x03) != 0x03) { + /* Power all outputs */ + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b); + SiS_DDC2Delay(&ivideo->SiS_Pr, 300); + } + /* Sense connected TV devices */ + for(i = 0; i < 3; i++) { + SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10); + if(!(temp1 & 0x08)) test[i] = 0x02; + else if(!(temp1 & 0x02)) test[i] = 0x01; + else test[i] = 0; + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + } + + if(test[0] == test[1]) temp1 = test[0]; + else if(test[0] == test[2]) temp1 = test[0]; + else if(test[1] == test[2]) temp1 = test[1]; + else { + printk(KERN_INFO + "sisfb: TV detection unreliable - test results varied\n"); + temp1 = test[2]; + } + if(temp1 == 0x02) { + printk(KERN_INFO "%s SVIDEO output\n", stdstr); + ivideo->vbflags |= TV_SVIDEO; + SiS_SetRegOR(SISCR, 0x32, 0x02); + SiS_SetRegAND(SISCR, 0x32, ~0x05); + } else if (temp1 == 0x01) { + printk(KERN_INFO "%s CVBS output\n", stdstr); + ivideo->vbflags |= TV_AVIDEO; + SiS_SetRegOR(SISCR, 0x32, 0x01); + SiS_SetRegAND(SISCR, 0x32, ~0x06); + } else { + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8); + SiS_SetRegAND(SISCR, 0x32, ~0x07); + } + } else if(temp1 == 0) { + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8); + SiS_SetRegAND(SISCR, 0x32, ~0x07); + } + /* Set general purpose IO for Chrontel communication */ + SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00); +#endif + + } else { + +#ifdef CONFIG_FB_SIS_315 + ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */ + temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49); + SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20); + temp2 |= 0x01; + SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + temp2 ^= 0x01; + SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2); + SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); + temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20); + SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1); + temp1 = 0; + if(temp2 & 0x02) temp1 |= 0x01; + if(temp2 & 0x10) temp1 |= 0x01; + if(temp2 & 0x04) temp1 |= 0x02; + if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04; + switch(temp1) { + case 0x01: + printk(KERN_INFO "%s CVBS output\n", stdstr); + ivideo->vbflags |= TV_AVIDEO; + SiS_SetRegOR(SISCR, 0x32, 0x01); + SiS_SetRegAND(SISCR, 0x32, ~0x06); + break; + case 0x02: + printk(KERN_INFO "%s SVIDEO output\n", stdstr); + ivideo->vbflags |= TV_SVIDEO; + SiS_SetRegOR(SISCR, 0x32, 0x02); + SiS_SetRegAND(SISCR, 0x32, ~0x05); + break; + case 0x04: + printk(KERN_INFO "%s SCART output\n", stdstr); + SiS_SetRegOR(SISCR, 0x32, 0x04); + SiS_SetRegAND(SISCR, 0x32, ~0x03); + break; + default: + SiS_SetRegAND(SISCR, 0x32, ~0x07); + } +#endif + } +} + +static void sisfb_get_VB_type(struct sis_video_info *ivideo) +{ + char stdstr[] = "sisfb: Detected"; + char bridgestr[] = "video bridge"; + u8 vb_chipid; + u8 reg; + + /* No CRT2 on XGI Z7 */ + if(ivideo->chip == XGI_20) + return; + + vb_chipid = SiS_GetReg(SISPART4, 0x00); + switch(vb_chipid) { + case 0x01: + reg = SiS_GetReg(SISPART4, 0x01); + if(reg < 0xb0) { + ivideo->vbflags |= VB_301; /* Deprecated */ + ivideo->vbflags2 |= VB2_301; + printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr); + } else if(reg < 0xc0) { + ivideo->vbflags |= VB_301B; /* Deprecated */ + ivideo->vbflags2 |= VB2_301B; + reg = SiS_GetReg(SISPART4, 0x23); + if(!(reg & 0x02)) { + ivideo->vbflags |= VB_30xBDH; /* Deprecated */ + ivideo->vbflags2 |= VB2_30xBDH; + printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr); + } else { + printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr); + } + } else if(reg < 0xd0) { + ivideo->vbflags |= VB_301C; /* Deprecated */ + ivideo->vbflags2 |= VB2_301C; + printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr); + } else if(reg < 0xe0) { + ivideo->vbflags |= VB_301LV; /* Deprecated */ + ivideo->vbflags2 |= VB2_301LV; + printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr); + } else if(reg <= 0xe1) { + reg = SiS_GetReg(SISPART4, 0x39); + if(reg == 0xff) { + ivideo->vbflags |= VB_302LV; /* Deprecated */ + ivideo->vbflags2 |= VB2_302LV; + printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr); + } else { + ivideo->vbflags |= VB_301C; /* Deprecated */ + ivideo->vbflags2 |= VB2_301C; + printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr); +#if 0 + ivideo->vbflags |= VB_302ELV; /* Deprecated */ + ivideo->vbflags2 |= VB2_302ELV; + printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr); +#endif + } + } + break; + case 0x02: + ivideo->vbflags |= VB_302B; /* Deprecated */ + ivideo->vbflags2 |= VB2_302B; + printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr); + break; + } + + if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) { + reg = SiS_GetReg(SISCR, 0x37); + reg &= SIS_EXTERNAL_CHIP_MASK; + reg >>= 1; + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + switch(reg) { + case SIS_EXTERNAL_CHIP_LVDS: + ivideo->vbflags |= VB_LVDS; /* Deprecated */ + ivideo->vbflags2 |= VB2_LVDS; + break; + case SIS_EXTERNAL_CHIP_TRUMPION: + ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION); + break; + case SIS_EXTERNAL_CHIP_CHRONTEL: + ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */ + ivideo->vbflags2 |= VB2_CHRONTEL; + break; + case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL: + ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL); + break; + } + if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1; +#endif + } else if(ivideo->chip < SIS_661) { +#ifdef CONFIG_FB_SIS_315 + switch (reg) { + case SIS310_EXTERNAL_CHIP_LVDS: + ivideo->vbflags |= VB_LVDS; /* Deprecated */ + ivideo->vbflags2 |= VB2_LVDS; + break; + case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL: + ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL); + break; + } + if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2; +#endif + } else if(ivideo->chip >= SIS_661) { +#ifdef CONFIG_FB_SIS_315 + reg = SiS_GetReg(SISCR, 0x38); + reg >>= 5; + switch(reg) { + case 0x02: + ivideo->vbflags |= VB_LVDS; /* Deprecated */ + ivideo->vbflags2 |= VB2_LVDS; + break; + case 0x03: + ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL); + break; + case 0x04: + ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT); + break; + } + if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2; +#endif + } + if(ivideo->vbflags2 & VB2_LVDS) { + printk(KERN_INFO "%s LVDS transmitter\n", stdstr); + } + if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) { + printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr); + } + if(ivideo->vbflags2 & VB2_CHRONTEL) { + printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr); + } + if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) { + printk(KERN_INFO "%s Conexant external device\n", stdstr); + } + } + + if(ivideo->vbflags2 & VB2_SISBRIDGE) { + SiS_SenseLCD(ivideo); + SiS_Sense30x(ivideo); + } else if(ivideo->vbflags2 & VB2_CHRONTEL) { + SiS_SenseCh(ivideo); + } +} + +/* ---------- Engine initialization routines ------------ */ + +static void +sisfb_engine_init(struct sis_video_info *ivideo) +{ + + /* Initialize command queue (we use MMIO only) */ + + /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */ + + ivideo->caps &= ~(TURBO_QUEUE_CAP | + MMIO_CMD_QUEUE_CAP | + VM_CMD_QUEUE_CAP | + AGP_CMD_QUEUE_CAP); + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + u32 tqueue_pos; + u8 tq_state; + + tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024); + + tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET); + tq_state |= 0xf0; + tq_state &= 0xfc; + tq_state |= (u8)(tqueue_pos >> 8); + SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state); + + SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff)); + + ivideo->caps |= TURBO_QUEUE_CAP; + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + u32 tempq = 0, templ; + u8 temp; + + if(ivideo->chip == XGI_20) { + switch(ivideo->cmdQueueSize) { + case (64 * 1024): + temp = SIS_CMD_QUEUE_SIZE_Z7_64k; + break; + case (128 * 1024): + default: + temp = SIS_CMD_QUEUE_SIZE_Z7_128k; + } + } else { + switch(ivideo->cmdQueueSize) { + case (4 * 1024 * 1024): + temp = SIS_CMD_QUEUE_SIZE_4M; + break; + case (2 * 1024 * 1024): + temp = SIS_CMD_QUEUE_SIZE_2M; + break; + case (1 * 1024 * 1024): + temp = SIS_CMD_QUEUE_SIZE_1M; + break; + default: + case (512 * 1024): + temp = SIS_CMD_QUEUE_SIZE_512k; + } + } + + SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD); + SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET); + + if((ivideo->chip >= XGI_40) && ivideo->modechanged) { + /* Must disable dual pipe on XGI_40. Can't do + * this in MMIO mode, because it requires + * setting/clearing a bit in the MMIO fire trigger + * register. + */ + if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) { + + MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0); + + SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE)); + + tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR); + MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq); + + tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize); + MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq); + + writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq); + writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4); + writel(0x168F0000, ivideo->video_vbase + tempq + 8); + writel(0x168F0000, ivideo->video_vbase + tempq + 12); + + MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16)); + + sisfb_syncaccel(ivideo); + + SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET); + + } + } + + tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT); + MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq); + + temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR); + SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp); + + tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize); + MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq); + + ivideo->caps |= MMIO_CMD_QUEUE_CAP; + } +#endif + + ivideo->engineok = 1; +} + +static void sisfb_detect_lcd_type(struct sis_video_info *ivideo) +{ + u8 reg; + int i; + + reg = SiS_GetReg(SISCR, 0x36); + reg &= 0x0f; + if(ivideo->sisvga_engine == SIS_300_VGA) { + ivideo->CRT2LCDType = sis300paneltype[reg]; + } else if(ivideo->chip >= SIS_661) { + ivideo->CRT2LCDType = sis661paneltype[reg]; + } else { + ivideo->CRT2LCDType = sis310paneltype[reg]; + if((ivideo->chip == SIS_550) && (sisfb_fstn)) { + if((ivideo->CRT2LCDType != LCD_320x240_2) && + (ivideo->CRT2LCDType != LCD_320x240_3)) { + ivideo->CRT2LCDType = LCD_320x240; + } + } + } + + if(ivideo->CRT2LCDType == LCD_UNKNOWN) { + /* For broken BIOSes: Assume 1024x768, RGB18 */ + ivideo->CRT2LCDType = LCD_1024x768; + SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02); + SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01); + printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg); + } + + for(i = 0; i < SIS_LCD_NUMBER; i++) { + if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) { + ivideo->lcdxres = sis_lcd_data[i].xres; + ivideo->lcdyres = sis_lcd_data[i].yres; + ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx; + break; + } + } + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) { + ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; + ivideo->lcddefmodeidx = DEFAULT_MODE_1360; + } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) { + ivideo->lcdxres = 848; ivideo->lcdyres = 480; + ivideo->lcddefmodeidx = DEFAULT_MODE_848; + } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) { + ivideo->lcdxres = 856; ivideo->lcdyres = 480; + ivideo->lcddefmodeidx = DEFAULT_MODE_856; + } +#endif + + printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n", + ivideo->lcdxres, ivideo->lcdyres); +} + +static void sisfb_save_pdc_emi(struct sis_video_info *ivideo) +{ +#ifdef CONFIG_FB_SIS_300 + /* Save the current PanelDelayCompensation if the LCD is currently used */ + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) { + int tmp; + tmp = SiS_GetReg(SISCR, 0x30); + if(tmp & 0x20) { + /* Currently on LCD? If yes, read current pdc */ + ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13); + ivideo->detectedpdc &= 0x3c; + if(ivideo->SiS_Pr.PDC == -1) { + /* Let option override detection */ + ivideo->SiS_Pr.PDC = ivideo->detectedpdc; + } + printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n", + ivideo->detectedpdc); + } + if((ivideo->SiS_Pr.PDC != -1) && + (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) { + printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n", + ivideo->SiS_Pr.PDC); + } + } + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + + /* Try to find about LCDA */ + if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) { + int tmp; + tmp = SiS_GetReg(SISPART1, 0x13); + if(tmp & 0x04) { + ivideo->SiS_Pr.SiS_UseLCDA = true; + ivideo->detectedlcda = 0x03; + } + } + + /* Save PDC */ + if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) { + int tmp; + tmp = SiS_GetReg(SISCR, 0x30); + if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) { + /* Currently on LCD? If yes, read current pdc */ + u8 pdc; + pdc = SiS_GetReg(SISPART1, 0x2D); + ivideo->detectedpdc = (pdc & 0x0f) << 1; + ivideo->detectedpdca = (pdc & 0xf0) >> 3; + pdc = SiS_GetReg(SISPART1, 0x35); + ivideo->detectedpdc |= ((pdc >> 7) & 0x01); + pdc = SiS_GetReg(SISPART1, 0x20); + ivideo->detectedpdca |= ((pdc >> 6) & 0x01); + if(ivideo->newrom) { + /* New ROM invalidates other PDC resp. */ + if(ivideo->detectedlcda != 0xff) { + ivideo->detectedpdc = 0xff; + } else { + ivideo->detectedpdca = 0xff; + } + } + if(ivideo->SiS_Pr.PDC == -1) { + if(ivideo->detectedpdc != 0xff) { + ivideo->SiS_Pr.PDC = ivideo->detectedpdc; + } + } + if(ivideo->SiS_Pr.PDCA == -1) { + if(ivideo->detectedpdca != 0xff) { + ivideo->SiS_Pr.PDCA = ivideo->detectedpdca; + } + } + if(ivideo->detectedpdc != 0xff) { + printk(KERN_INFO + "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n", + ivideo->detectedpdc); + } + if(ivideo->detectedpdca != 0xff) { + printk(KERN_INFO + "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n", + ivideo->detectedpdca); + } + } + + /* Save EMI */ + if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) { + ivideo->SiS_Pr.EMI_30 = SiS_GetReg(SISPART4, 0x30); + ivideo->SiS_Pr.EMI_31 = SiS_GetReg(SISPART4, 0x31); + ivideo->SiS_Pr.EMI_32 = SiS_GetReg(SISPART4, 0x32); + ivideo->SiS_Pr.EMI_33 = SiS_GetReg(SISPART4, 0x33); + ivideo->SiS_Pr.HaveEMI = true; + if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) { + ivideo->SiS_Pr.HaveEMILCD = true; + } + } + } + + /* Let user override detected PDCs (all bridges) */ + if(ivideo->vbflags2 & VB2_30xBLV) { + if((ivideo->SiS_Pr.PDC != -1) && + (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) { + printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n", + ivideo->SiS_Pr.PDC); + } + if((ivideo->SiS_Pr.PDCA != -1) && + (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) { + printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n", + ivideo->SiS_Pr.PDCA); + } + } + + } +#endif +} + +/* -------------------- Memory manager routines ---------------------- */ + +static u32 sisfb_getheapstart(struct sis_video_info *ivideo) +{ + u32 ret = ivideo->sisfb_parm_mem * 1024; + u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize; + u32 def; + + /* Calculate heap start = end of memory for console + * + * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ + * C = console, D = heap, H = HWCursor, Q = cmd-queue + * + * On 76x in UMA+LFB mode, the layout is as follows: + * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ + * where the heap is the entire UMA area, eventually + * into the LFB area if the given mem parameter is + * higher than the size of the UMA memory. + * + * Basically given by "mem" parameter + * + * maximum = videosize - cmd_queue - hwcursor + * (results in a heap of size 0) + * default = SiS 300: depends on videosize + * SiS 315/330/340/XGI: 32k below max + */ + + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->video_size > 0x1000000) { + def = 0xc00000; + } else if(ivideo->video_size > 0x800000) { + def = 0x800000; + } else { + def = 0x400000; + } + } else if(ivideo->UMAsize && ivideo->LFBsize) { + ret = def = 0; + } else { + def = maxoffs - 0x8000; + } + + /* Use default for secondary card for now (FIXME) */ + if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0)) + ret = def; + + return ret; +} + +static u32 sisfb_getheapsize(struct sis_video_info *ivideo) +{ + u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize; + u32 ret = 0; + + if(ivideo->UMAsize && ivideo->LFBsize) { + if( (!ivideo->sisfb_parm_mem) || + ((ivideo->sisfb_parm_mem * 1024) > max) || + ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) { + ret = ivideo->UMAsize; + max -= ivideo->UMAsize; + } else { + ret = max - (ivideo->sisfb_parm_mem * 1024); + max = ivideo->sisfb_parm_mem * 1024; + } + ivideo->video_offset = ret; + ivideo->sisfb_mem = max; + } else { + ret = max - ivideo->heapstart; + ivideo->sisfb_mem = ivideo->heapstart; + } + + return ret; +} + +static int sisfb_heap_init(struct sis_video_info *ivideo) +{ + struct SIS_OH *poh; + + ivideo->video_offset = 0; + if(ivideo->sisfb_parm_mem) { + if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) || + (ivideo->sisfb_parm_mem > ivideo->video_size) ) { + ivideo->sisfb_parm_mem = 0; + } + } + + ivideo->heapstart = sisfb_getheapstart(ivideo); + ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo); + + ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart; + ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size; + + printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n", + (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024)); + + ivideo->sisfb_heap.vinfo = ivideo; + + ivideo->sisfb_heap.poha_chain = NULL; + ivideo->sisfb_heap.poh_freelist = NULL; + + poh = sisfb_poh_new_node(&ivideo->sisfb_heap); + if(poh == NULL) + return 1; + + poh->poh_next = &ivideo->sisfb_heap.oh_free; + poh->poh_prev = &ivideo->sisfb_heap.oh_free; + poh->size = ivideo->sisfb_heap_size; + poh->offset = ivideo->heapstart; + + ivideo->sisfb_heap.oh_free.poh_next = poh; + ivideo->sisfb_heap.oh_free.poh_prev = poh; + ivideo->sisfb_heap.oh_free.size = 0; + ivideo->sisfb_heap.max_freesize = poh->size; + + ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used; + ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used; + ivideo->sisfb_heap.oh_used.size = SENTINEL; + + if(ivideo->cardnumber == 0) { + /* For the first card, make this heap the "global" one + * for old DRM (which could handle only one card) + */ + sisfb_heap = &ivideo->sisfb_heap; + } + + return 0; +} + +static struct SIS_OH * +sisfb_poh_new_node(struct SIS_HEAP *memheap) +{ + struct SIS_OHALLOC *poha; + struct SIS_OH *poh; + unsigned long cOhs; + int i; + + if(memheap->poh_freelist == NULL) { + poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL); + if(!poha) + return NULL; + + poha->poha_next = memheap->poha_chain; + memheap->poha_chain = poha; + + cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1; + + poh = &poha->aoh[0]; + for(i = cOhs - 1; i != 0; i--) { + poh->poh_next = poh + 1; + poh = poh + 1; + } + + poh->poh_next = NULL; + memheap->poh_freelist = &poha->aoh[0]; + } + + poh = memheap->poh_freelist; + memheap->poh_freelist = poh->poh_next; + + return poh; +} + +static struct SIS_OH * +sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size) +{ + struct SIS_OH *pohThis; + struct SIS_OH *pohRoot; + int bAllocated = 0; + + if(size > memheap->max_freesize) { + DPRINTK("sisfb: Can't allocate %dk video memory\n", + (unsigned int) size / 1024); + return NULL; + } + + pohThis = memheap->oh_free.poh_next; + + while(pohThis != &memheap->oh_free) { + if(size <= pohThis->size) { + bAllocated = 1; + break; + } + pohThis = pohThis->poh_next; + } + + if(!bAllocated) { + DPRINTK("sisfb: Can't allocate %dk video memory\n", + (unsigned int) size / 1024); + return NULL; + } + + if(size == pohThis->size) { + pohRoot = pohThis; + sisfb_delete_node(pohThis); + } else { + pohRoot = sisfb_poh_new_node(memheap); + if(pohRoot == NULL) + return NULL; + + pohRoot->offset = pohThis->offset; + pohRoot->size = size; + + pohThis->offset += size; + pohThis->size -= size; + } + + memheap->max_freesize -= size; + + pohThis = &memheap->oh_used; + sisfb_insert_node(pohThis, pohRoot); + + return pohRoot; +} + +static void +sisfb_delete_node(struct SIS_OH *poh) +{ + poh->poh_prev->poh_next = poh->poh_next; + poh->poh_next->poh_prev = poh->poh_prev; +} + +static void +sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh) +{ + struct SIS_OH *pohTemp = pohList->poh_next; + + pohList->poh_next = poh; + pohTemp->poh_prev = poh; + + poh->poh_prev = pohList; + poh->poh_next = pohTemp; +} + +static struct SIS_OH * +sisfb_poh_free(struct SIS_HEAP *memheap, u32 base) +{ + struct SIS_OH *pohThis; + struct SIS_OH *poh_freed; + struct SIS_OH *poh_prev; + struct SIS_OH *poh_next; + u32 ulUpper; + u32 ulLower; + int foundNode = 0; + + poh_freed = memheap->oh_used.poh_next; + + while(poh_freed != &memheap->oh_used) { + if(poh_freed->offset == base) { + foundNode = 1; + break; + } + + poh_freed = poh_freed->poh_next; + } + + if(!foundNode) + return NULL; + + memheap->max_freesize += poh_freed->size; + + poh_prev = poh_next = NULL; + ulUpper = poh_freed->offset + poh_freed->size; + ulLower = poh_freed->offset; + + pohThis = memheap->oh_free.poh_next; + + while(pohThis != &memheap->oh_free) { + if(pohThis->offset == ulUpper) { + poh_next = pohThis; + } else if((pohThis->offset + pohThis->size) == ulLower) { + poh_prev = pohThis; + } + pohThis = pohThis->poh_next; + } + + sisfb_delete_node(poh_freed); + + if(poh_prev && poh_next) { + poh_prev->size += (poh_freed->size + poh_next->size); + sisfb_delete_node(poh_next); + sisfb_free_node(memheap, poh_freed); + sisfb_free_node(memheap, poh_next); + return poh_prev; + } + + if(poh_prev) { + poh_prev->size += poh_freed->size; + sisfb_free_node(memheap, poh_freed); + return poh_prev; + } + + if(poh_next) { + poh_next->size += poh_freed->size; + poh_next->offset = poh_freed->offset; + sisfb_free_node(memheap, poh_freed); + return poh_next; + } + + sisfb_insert_node(&memheap->oh_free, poh_freed); + + return poh_freed; +} + +static void +sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh) +{ + if(poh == NULL) + return; + + poh->poh_next = memheap->poh_freelist; + memheap->poh_freelist = poh; +} + +static void +sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req) +{ + struct SIS_OH *poh = NULL; + + if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap)) + poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size); + + if(poh == NULL) { + req->offset = req->size = 0; + DPRINTK("sisfb: Video RAM allocation failed\n"); + } else { + req->offset = poh->offset; + req->size = poh->size; + DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n", + (poh->offset + ivideo->video_vbase)); + } +} + +void +sis_malloc(struct sis_memreq *req) +{ + struct sis_video_info *ivideo = sisfb_heap->vinfo; + + if(&ivideo->sisfb_heap == sisfb_heap) + sis_int_malloc(ivideo, req); + else + req->offset = req->size = 0; +} + +void +sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + + sis_int_malloc(ivideo, req); +} + +/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */ + +static void +sis_int_free(struct sis_video_info *ivideo, u32 base) +{ + struct SIS_OH *poh; + + if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap)) + return; + + poh = sisfb_poh_free(&ivideo->sisfb_heap, base); + + if(poh == NULL) { + DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n", + (unsigned int) base); + } +} + +void +sis_free(u32 base) +{ + struct sis_video_info *ivideo = sisfb_heap->vinfo; + + sis_int_free(ivideo, base); +} + +void +sis_free_new(struct pci_dev *pdev, u32 base) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + + sis_int_free(ivideo, base); +} + +/* --------------------- SetMode routines ------------------------- */ + +static void +sisfb_check_engine_and_sync(struct sis_video_info *ivideo) +{ + u8 cr30, cr31; + + /* Check if MMIO and engines are enabled, + * and sync in case they are. Can't use + * ivideo->accel here, as this might have + * been changed before this is called. + */ + cr30 = SiS_GetReg(SISSR, IND_SIS_PCI_ADDRESS_SET); + cr31 = SiS_GetReg(SISSR, IND_SIS_MODULE_ENABLE); + /* MMIO and 2D/3D engine enabled? */ + if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) { +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + /* Don't care about TurboQueue. It's + * enough to know that the engines + * are enabled + */ + sisfb_syncaccel(ivideo); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + /* Check that any queue mode is + * enabled, and that the queue + * is not in the state of "reset" + */ + cr30 = SiS_GetReg(SISSR, 0x26); + if((cr30 & 0xe0) && (!(cr30 & 0x01))) { + sisfb_syncaccel(ivideo); + } + } +#endif + } +} + +static void +sisfb_pre_setmode(struct sis_video_info *ivideo) +{ + u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0; + int tvregnum = 0; + + ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2); + + SiS_SetReg(SISSR, 0x05, 0x86); + + cr31 = SiS_GetReg(SISCR, 0x31); + cr31 &= ~0x60; + cr31 |= 0x04; + + cr33 = ivideo->rate_idx & 0x0F; + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + if(ivideo->chip >= SIS_661) { + cr38 = SiS_GetReg(SISCR, 0x38); + cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */ + } else { + tvregnum = 0x38; + cr38 = SiS_GetReg(SISCR, tvregnum); + cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */ + } + } +#endif +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + tvregnum = 0x35; + cr38 = SiS_GetReg(SISCR, tvregnum); + } +#endif + + SiS_SetEnableDstn(&ivideo->SiS_Pr, false); + SiS_SetEnableFstn(&ivideo->SiS_Pr, false); + ivideo->curFSTN = ivideo->curDSTN = 0; + + switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + + case CRT2_TV: + cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */ + if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) { +#ifdef CONFIG_FB_SIS_315 + if(ivideo->chip >= SIS_661) { + cr38 |= 0x04; + if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20; + else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40; + else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60; + cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE; + cr35 &= ~0x01; + ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL)); + } else if(ivideo->sisvga_engine == SIS_315_VGA) { + cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr38 |= 0x08; + if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10; + else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20; + else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30; + cr31 &= ~0x01; + ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL)); + } +#endif + } else if((ivideo->vbflags & TV_HIVISION) && + (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) { + if(ivideo->chip >= SIS_661) { + cr38 |= 0x04; + cr35 |= 0x60; + } else { + cr30 |= 0x80; + } + cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE; + cr31 |= 0x01; + cr35 |= 0x01; + ivideo->currentvbflags |= TV_HIVISION; + } else if(ivideo->vbflags & TV_SCART) { + cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= 0x01; + cr35 |= 0x01; + ivideo->currentvbflags |= TV_SCART; + } else { + if(ivideo->vbflags & TV_SVIDEO) { + cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE); + ivideo->currentvbflags |= TV_SVIDEO; + } + if(ivideo->vbflags & TV_AVIDEO) { + cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE); + ivideo->currentvbflags |= TV_AVIDEO; + } + } + cr31 |= SIS_DRIVER_MODE; + + if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) { + if(ivideo->vbflags & TV_PAL) { + cr31 |= 0x01; cr35 |= 0x01; + ivideo->currentvbflags |= TV_PAL; + if(ivideo->vbflags & TV_PALM) { + cr38 |= 0x40; cr35 |= 0x04; + ivideo->currentvbflags |= TV_PALM; + } else if(ivideo->vbflags & TV_PALN) { + cr38 |= 0x80; cr35 |= 0x08; + ivideo->currentvbflags |= TV_PALN; + } + } else { + cr31 &= ~0x01; cr35 &= ~0x01; + ivideo->currentvbflags |= TV_NTSC; + if(ivideo->vbflags & TV_NTSCJ) { + cr38 |= 0x40; cr35 |= 0x02; + ivideo->currentvbflags |= TV_NTSCJ; + } + } + } + break; + + case CRT2_LCD: + cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= SIS_DRIVER_MODE; + SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn); + SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn); + ivideo->curFSTN = ivideo->sisfb_fstn; + ivideo->curDSTN = ivideo->sisfb_dstn; + break; + + case CRT2_VGA: + cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= SIS_DRIVER_MODE; + if(ivideo->sisfb_nocrt2rate) { + cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4); + } else { + cr33 |= ((ivideo->rate_idx & 0x0F) << 4); + } + break; + + default: /* disable CRT2 */ + cr30 = 0x00; + cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE); + } + + SiS_SetReg(SISCR, 0x30, cr30); + SiS_SetReg(SISCR, 0x33, cr33); + + if(ivideo->chip >= SIS_661) { +#ifdef CONFIG_FB_SIS_315 + cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */ + SiS_SetRegANDOR(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */ + cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */ + SiS_SetRegANDOR(SISCR, 0x38, 0xf8, cr38); +#endif + } else if(ivideo->chip != SIS_300) { + SiS_SetReg(SISCR, tvregnum, cr38); + } + SiS_SetReg(SISCR, 0x31, cr31); + + ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem; + + sisfb_check_engine_and_sync(ivideo); +} + +/* Fix SR11 for 661 and later */ +#ifdef CONFIG_FB_SIS_315 +static void +sisfb_fixup_SR11(struct sis_video_info *ivideo) +{ + u8 tmpreg; + + if(ivideo->chip >= SIS_661) { + tmpreg = SiS_GetReg(SISSR, 0x11); + if(tmpreg & 0x20) { + tmpreg = SiS_GetReg(SISSR, 0x3e); + tmpreg = (tmpreg + 1) & 0xff; + SiS_SetReg(SISSR, 0x3e, tmpreg); + tmpreg = SiS_GetReg(SISSR, 0x11); + } + if(tmpreg & 0xf0) { + SiS_SetRegAND(SISSR, 0x11, 0x0f); + } + } +} +#endif + +static void +sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val) +{ + if(val > 32) val = 32; + if(val < -32) val = -32; + ivideo->tvxpos = val; + + if(ivideo->sisfblocked) return; + if(!ivideo->modechanged) return; + + if(ivideo->currentvbflags & CRT2_TV) { + + if(ivideo->vbflags2 & VB2_CHRONTEL) { + + int x = ivideo->tvx; + + switch(ivideo->chronteltype) { + case 1: + x += val; + if(x < 0) x = 0; + SiS_SetReg(SISSR, 0x05, 0x86); + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff)); + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD); + break; + case 2: + /* Not supported by hardware */ + break; + } + + } else if(ivideo->vbflags2 & VB2_SISBRIDGE) { + + u8 p2_1f,p2_20,p2_2b,p2_42,p2_43; + unsigned short temp; + + p2_1f = ivideo->p2_1f; + p2_20 = ivideo->p2_20; + p2_2b = ivideo->p2_2b; + p2_42 = ivideo->p2_42; + p2_43 = ivideo->p2_43; + + temp = p2_1f | ((p2_20 & 0xf0) << 4); + temp += (val * 2); + p2_1f = temp & 0xff; + p2_20 = (temp & 0xf00) >> 4; + p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f; + temp = p2_43 | ((p2_42 & 0xf0) << 4); + temp += (val * 2); + p2_43 = temp & 0xff; + p2_42 = (temp & 0xf00) >> 4; + SiS_SetReg(SISPART2, 0x1f, p2_1f); + SiS_SetRegANDOR(SISPART2, 0x20, 0x0F, p2_20); + SiS_SetRegANDOR(SISPART2, 0x2b, 0xF0, p2_2b); + SiS_SetRegANDOR(SISPART2, 0x42, 0x0F, p2_42); + SiS_SetReg(SISPART2, 0x43, p2_43); + } + } +} + +static void +sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val) +{ + if(val > 32) val = 32; + if(val < -32) val = -32; + ivideo->tvypos = val; + + if(ivideo->sisfblocked) return; + if(!ivideo->modechanged) return; + + if(ivideo->currentvbflags & CRT2_TV) { + + if(ivideo->vbflags2 & VB2_CHRONTEL) { + + int y = ivideo->tvy; + + switch(ivideo->chronteltype) { + case 1: + y -= val; + if(y < 0) y = 0; + SiS_SetReg(SISSR, 0x05, 0x86); + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff)); + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE); + break; + case 2: + /* Not supported by hardware */ + break; + } + + } else if(ivideo->vbflags2 & VB2_SISBRIDGE) { + + char p2_01, p2_02; + val /= 2; + p2_01 = ivideo->p2_01; + p2_02 = ivideo->p2_02; + + p2_01 += val; + p2_02 += val; + if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) { + while((p2_01 <= 0) || (p2_02 <= 0)) { + p2_01 += 2; + p2_02 += 2; + } + } + SiS_SetReg(SISPART2, 0x01, p2_01); + SiS_SetReg(SISPART2, 0x02, p2_02); + } + } +} + +static void +sisfb_post_setmode(struct sis_video_info *ivideo) +{ + bool crt1isoff = false; + bool doit = true; +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) + u8 reg; +#endif +#ifdef CONFIG_FB_SIS_315 + u8 reg1; +#endif + + SiS_SetReg(SISSR, 0x05, 0x86); + +#ifdef CONFIG_FB_SIS_315 + sisfb_fixup_SR11(ivideo); +#endif + + /* Now we actually HAVE changed the display mode */ + ivideo->modechanged = 1; + + /* We can't switch off CRT1 if bridge is in slave mode */ + if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) { + if(sisfb_bridgeisslave(ivideo)) doit = false; + } else + ivideo->sisfb_crt1off = 0; + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + if((ivideo->sisfb_crt1off) && (doit)) { + crt1isoff = true; + reg = 0x00; + } else { + crt1isoff = false; + reg = 0x80; + } + SiS_SetRegANDOR(SISCR, 0x17, 0x7f, reg); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + if((ivideo->sisfb_crt1off) && (doit)) { + crt1isoff = true; + reg = 0x40; + reg1 = 0xc0; + } else { + crt1isoff = false; + reg = 0x00; + reg1 = 0x00; + } + SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg); + SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, reg1); + } +#endif + + if(crt1isoff) { + ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1; + ivideo->currentvbflags |= VB_SINGLE_MODE; + } else { + ivideo->currentvbflags |= VB_DISPTYPE_CRT1; + if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) { + ivideo->currentvbflags |= VB_MIRROR_MODE; + } else { + ivideo->currentvbflags |= VB_SINGLE_MODE; + } + } + + SiS_SetRegAND(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04); + + if(ivideo->currentvbflags & CRT2_TV) { + if(ivideo->vbflags2 & VB2_SISBRIDGE) { + ivideo->p2_1f = SiS_GetReg(SISPART2, 0x1f); + ivideo->p2_20 = SiS_GetReg(SISPART2, 0x20); + ivideo->p2_2b = SiS_GetReg(SISPART2, 0x2b); + ivideo->p2_42 = SiS_GetReg(SISPART2, 0x42); + ivideo->p2_43 = SiS_GetReg(SISPART2, 0x43); + ivideo->p2_01 = SiS_GetReg(SISPART2, 0x01); + ivideo->p2_02 = SiS_GetReg(SISPART2, 0x02); + } else if(ivideo->vbflags2 & VB2_CHRONTEL) { + if(ivideo->chronteltype == 1) { + ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a); + ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8); + ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b); + ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8); + } + } + } + + if(ivideo->tvxpos) { + sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos); + } + if(ivideo->tvypos) { + sisfb_set_TVyposoffset(ivideo, ivideo->tvypos); + } + + /* Eventually sync engines */ + sisfb_check_engine_and_sync(ivideo); + + /* (Re-)Initialize chip engines */ + if(ivideo->accel) { + sisfb_engine_init(ivideo); + } else { + ivideo->engineok = 0; + } +} + +static int +sisfb_reset_mode(struct sis_video_info *ivideo) +{ + if(sisfb_set_mode(ivideo, 0)) + return 1; + + sisfb_set_pitch(ivideo); + sisfb_set_base_CRT1(ivideo, ivideo->current_base); + sisfb_set_base_CRT2(ivideo, ivideo->current_base); + + return 0; +} + +static void +sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command) +{ + int mycrt1off; + + switch(sisfb_command->sisfb_cmd) { + case SISFB_CMD_GETVBFLAGS: + if(!ivideo->modechanged) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY; + } else { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK; + sisfb_command->sisfb_result[1] = ivideo->currentvbflags; + sisfb_command->sisfb_result[2] = ivideo->vbflags2; + } + break; + case SISFB_CMD_SWITCHCRT1: + /* arg[0]: 0 = off, 1 = on, 99 = query */ + if(!ivideo->modechanged) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY; + } else if(sisfb_command->sisfb_arg[0] == 99) { + /* Query */ + sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1; + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK; + } else if(ivideo->sisfblocked) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED; + } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) && + (sisfb_command->sisfb_arg[0] == 0)) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2; + } else { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK; + mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1; + if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) || + ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) { + ivideo->sisfb_crt1off = mycrt1off; + if(sisfb_reset_mode(ivideo)) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER; + } + } + sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1; + } + break; + /* more to come */ + default: + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN; + printk(KERN_ERR "sisfb: Unknown command 0x%x\n", + sisfb_command->sisfb_cmd); + } +} + +#ifndef MODULE +static int __init sisfb_setup(char *options) +{ + char *this_opt; + + sisfb_setdefaultparms(); + + if(!options || !(*options)) + return 0; + + while((this_opt = strsep(&options, ",")) != NULL) { + + if(!(*this_opt)) continue; + + if(!strnicmp(this_opt, "off", 3)) { + sisfb_off = 1; + } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) { + /* Need to check crt2 type first for fstn/dstn */ + sisfb_search_crt2type(this_opt + 14); + } else if(!strnicmp(this_opt, "tvmode:",7)) { + sisfb_search_tvstd(this_opt + 7); + } else if(!strnicmp(this_opt, "tvstandard:",11)) { + sisfb_search_tvstd(this_opt + 11); + } else if(!strnicmp(this_opt, "mode:", 5)) { + sisfb_search_mode(this_opt + 5, false); + } else if(!strnicmp(this_opt, "vesa:", 5)) { + sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false); + } else if(!strnicmp(this_opt, "rate:", 5)) { + sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0); + } else if(!strnicmp(this_opt, "forcecrt1:", 10)) { + sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0); + } else if(!strnicmp(this_opt, "mem:",4)) { + sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0); + } else if(!strnicmp(this_opt, "pdc:", 4)) { + sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0); + } else if(!strnicmp(this_opt, "pdc1:", 5)) { + sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0); + } else if(!strnicmp(this_opt, "noaccel", 7)) { + sisfb_accel = 0; + } else if(!strnicmp(this_opt, "accel", 5)) { + sisfb_accel = -1; + } else if(!strnicmp(this_opt, "noypan", 6)) { + sisfb_ypan = 0; + } else if(!strnicmp(this_opt, "ypan", 4)) { + sisfb_ypan = -1; + } else if(!strnicmp(this_opt, "nomax", 5)) { + sisfb_max = 0; + } else if(!strnicmp(this_opt, "max", 3)) { + sisfb_max = -1; + } else if(!strnicmp(this_opt, "userom:", 7)) { + sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0); + } else if(!strnicmp(this_opt, "useoem:", 7)) { + sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0); + } else if(!strnicmp(this_opt, "nocrt2rate", 10)) { + sisfb_nocrt2rate = 1; + } else if(!strnicmp(this_opt, "scalelcd:", 9)) { + unsigned long temp = 2; + temp = simple_strtoul(this_opt + 9, NULL, 0); + if((temp == 0) || (temp == 1)) { + sisfb_scalelcd = temp ^ 1; + } + } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) { + int temp = 0; + temp = (int)simple_strtol(this_opt + 13, NULL, 0); + if((temp >= -32) && (temp <= 32)) { + sisfb_tvxposoffset = temp; + } + } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) { + int temp = 0; + temp = (int)simple_strtol(this_opt + 13, NULL, 0); + if((temp >= -32) && (temp <= 32)) { + sisfb_tvyposoffset = temp; + } + } else if(!strnicmp(this_opt, "specialtiming:", 14)) { + sisfb_search_specialtiming(this_opt + 14); + } else if(!strnicmp(this_opt, "lvdshl:", 7)) { + int temp = 4; + temp = simple_strtoul(this_opt + 7, NULL, 0); + if((temp >= 0) && (temp <= 3)) { + sisfb_lvdshl = temp; + } + } else if(this_opt[0] >= '0' && this_opt[0] <= '9') { + sisfb_search_mode(this_opt, true); +#if !defined(__i386__) && !defined(__x86_64__) + } else if(!strnicmp(this_opt, "resetcard", 9)) { + sisfb_resetcard = 1; + } else if(!strnicmp(this_opt, "videoram:", 9)) { + sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0); +#endif + } else { + printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt); + } + + } + + return 0; +} +#endif + +static int sisfb_check_rom(void __iomem *rom_base, + struct sis_video_info *ivideo) +{ + void __iomem *rom; + int romptr; + + if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) + return 0; + + romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8)); + if(romptr > (0x10000 - 8)) + return 0; + + rom = rom_base + romptr; + + if((readb(rom) != 'P') || (readb(rom + 1) != 'C') || + (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) + return 0; + + if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor) + return 0; + + if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id) + return 0; + + return 1; +} + +static unsigned char *sisfb_find_rom(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + void __iomem *rom_base; + unsigned char *myrombase = NULL; + size_t romsize; + + /* First, try the official pci ROM functions (except + * on integrated chipsets which have no ROM). + */ + + if(!ivideo->nbridge) { + + if((rom_base = pci_map_rom(pdev, &romsize))) { + + if(sisfb_check_rom(rom_base, ivideo)) { + + if((myrombase = vmalloc(65536))) { + memcpy_fromio(myrombase, rom_base, + (romsize > 65536) ? 65536 : romsize); + } + } + pci_unmap_rom(pdev, rom_base); + } + } + + if(myrombase) return myrombase; + + /* Otherwise do it the conventional way. */ + +#if defined(__i386__) || defined(__x86_64__) + { + u32 temp; + + for (temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) { + + rom_base = ioremap(temp, 65536); + if (!rom_base) + continue; + + if (!sisfb_check_rom(rom_base, ivideo)) { + iounmap(rom_base); + continue; + } + + if ((myrombase = vmalloc(65536))) + memcpy_fromio(myrombase, rom_base, 65536); + + iounmap(rom_base); + break; + + } + + } +#endif + + return myrombase; +} + +static void sisfb_post_map_vram(struct sis_video_info *ivideo, + unsigned int *mapsize, unsigned int min) +{ + if (*mapsize < (min << 20)) + return; + + ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize)); + + if(!ivideo->video_vbase) { + printk(KERN_ERR + "sisfb: Unable to map maximum video RAM for size detection\n"); + (*mapsize) >>= 1; + while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) { + (*mapsize) >>= 1; + if((*mapsize) < (min << 20)) + break; + } + if(ivideo->video_vbase) { + printk(KERN_ERR + "sisfb: Video RAM size detection limited to %dMB\n", + (int)((*mapsize) >> 20)); + } + } +} + +#ifdef CONFIG_FB_SIS_300 +static int sisfb_post_300_buswidth(struct sis_video_info *ivideo) +{ + void __iomem *FBAddress = ivideo->video_vbase; + unsigned short temp; + unsigned char reg; + int i, j; + + SiS_SetRegAND(SISSR, 0x15, 0xFB); + SiS_SetRegOR(SISSR, 0x15, 0x04); + SiS_SetReg(SISSR, 0x13, 0x00); + SiS_SetReg(SISSR, 0x14, 0xBF); + + for(i = 0; i < 2; i++) { + temp = 0x1234; + for(j = 0; j < 4; j++) { + writew(temp, FBAddress); + if(readw(FBAddress) == temp) + break; + SiS_SetRegOR(SISSR, 0x3c, 0x01); + reg = SiS_GetReg(SISSR, 0x05); + reg = SiS_GetReg(SISSR, 0x05); + SiS_SetRegAND(SISSR, 0x3c, 0xfe); + reg = SiS_GetReg(SISSR, 0x05); + reg = SiS_GetReg(SISSR, 0x05); + temp++; + } + } + + writel(0x01234567L, FBAddress); + writel(0x456789ABL, (FBAddress + 4)); + writel(0x89ABCDEFL, (FBAddress + 8)); + writel(0xCDEF0123L, (FBAddress + 12)); + + reg = SiS_GetReg(SISSR, 0x3b); + if(reg & 0x01) { + if(readl((FBAddress + 12)) == 0xCDEF0123L) + return 4; /* Channel A 128bit */ + } + + if(readl((FBAddress + 4)) == 0x456789ABL) + return 2; /* Channel B 64bit */ + + return 1; /* 32bit */ +} + +static const unsigned short SiS_DRAMType[17][5] = { + {0x0C,0x0A,0x02,0x40,0x39}, + {0x0D,0x0A,0x01,0x40,0x48}, + {0x0C,0x09,0x02,0x20,0x35}, + {0x0D,0x09,0x01,0x20,0x44}, + {0x0C,0x08,0x02,0x10,0x31}, + {0x0D,0x08,0x01,0x10,0x40}, + {0x0C,0x0A,0x01,0x20,0x34}, + {0x0C,0x09,0x01,0x08,0x32}, + {0x0B,0x08,0x02,0x08,0x21}, + {0x0C,0x08,0x01,0x08,0x30}, + {0x0A,0x08,0x02,0x04,0x11}, + {0x0B,0x0A,0x01,0x10,0x28}, + {0x09,0x08,0x02,0x02,0x01}, + {0x0B,0x09,0x01,0x08,0x24}, + {0x0B,0x08,0x01,0x04,0x20}, + {0x0A,0x08,0x01,0x02,0x10}, + {0x09,0x08,0x01,0x01,0x00} +}; + +static int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, + int buswidth, int PseudoRankCapacity, + int PseudoAdrPinCount, unsigned int mapsize) +{ + void __iomem *FBAddr = ivideo->video_vbase; + unsigned short sr14; + unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid; + unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage; + + for(k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) { + + RankCapacity = buswidth * SiS_DRAMType[k][3]; + + if(RankCapacity != PseudoRankCapacity) + continue; + + if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount) + continue; + + BankNumHigh = RankCapacity * 16 * iteration - 1; + if(iteration == 3) { /* Rank No */ + BankNumMid = RankCapacity * 16 - 1; + } else { + BankNumMid = RankCapacity * 16 * iteration / 2 - 1; + } + + PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4; + PhysicalAdrHigh = BankNumHigh; + PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity; + PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh; + + SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */ + SiS_SetRegOR(SISSR, 0x15, 0x04); /* Test */ + sr14 = (SiS_DRAMType[k][3] * buswidth) - 1; + if(buswidth == 4) sr14 |= 0x80; + else if(buswidth == 2) sr14 |= 0x40; + SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]); + SiS_SetReg(SISSR, 0x14, sr14); + + BankNumHigh <<= 16; + BankNumMid <<= 16; + + if((BankNumHigh + PhysicalAdrHigh >= mapsize) || + (BankNumMid + PhysicalAdrHigh >= mapsize) || + (BankNumHigh + PhysicalAdrHalfPage >= mapsize) || + (BankNumHigh + PhysicalAdrOtherPage >= mapsize)) + continue; + + /* Write data */ + writew(((unsigned short)PhysicalAdrHigh), + (FBAddr + BankNumHigh + PhysicalAdrHigh)); + writew(((unsigned short)BankNumMid), + (FBAddr + BankNumMid + PhysicalAdrHigh)); + writew(((unsigned short)PhysicalAdrHalfPage), + (FBAddr + BankNumHigh + PhysicalAdrHalfPage)); + writew(((unsigned short)PhysicalAdrOtherPage), + (FBAddr + BankNumHigh + PhysicalAdrOtherPage)); + + /* Read data */ + if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh) + return 1; + } + + return 0; +} + +static void sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + int i, j, buswidth; + int PseudoRankCapacity, PseudoAdrPinCount; + + buswidth = sisfb_post_300_buswidth(ivideo); + + for(i = 6; i >= 0; i--) { + PseudoRankCapacity = 1 << i; + for(j = 4; j >= 1; j--) { + PseudoAdrPinCount = 15 - j; + if((PseudoRankCapacity * j) <= 64) { + if(sisfb_post_300_rwtest(ivideo, + j, + buswidth, + PseudoRankCapacity, + PseudoAdrPinCount, + mapsize)) + return; + } + } + } +} + +static void sisfb_post_sis300(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase; + u8 reg, v1, v2, v3, v4, v5, v6, v7, v8; + u16 index, rindex, memtype = 0; + unsigned int mapsize; + + if(!ivideo->SiS_Pr.UseROM) + bios = NULL; + + SiS_SetReg(SISSR, 0x05, 0x86); + + if(bios) { + if(bios[0x52] & 0x80) { + memtype = bios[0x52]; + } else { + memtype = SiS_GetReg(SISSR, 0x3a); + } + memtype &= 0x07; + } + + v3 = 0x80; v6 = 0x80; + if(ivideo->revision_id <= 0x13) { + v1 = 0x44; v2 = 0x42; + v4 = 0x44; v5 = 0x42; + } else { + v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */ + v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */ + if(bios) { + index = memtype * 5; + rindex = index + 0x54; + v1 = bios[rindex++]; + v2 = bios[rindex++]; + v3 = bios[rindex++]; + rindex = index + 0x7c; + v4 = bios[rindex++]; + v5 = bios[rindex++]; + v6 = bios[rindex++]; + } + } + SiS_SetReg(SISSR, 0x28, v1); + SiS_SetReg(SISSR, 0x29, v2); + SiS_SetReg(SISSR, 0x2a, v3); + SiS_SetReg(SISSR, 0x2e, v4); + SiS_SetReg(SISSR, 0x2f, v5); + SiS_SetReg(SISSR, 0x30, v6); + + v1 = 0x10; + if(bios) + v1 = bios[0xa4]; + SiS_SetReg(SISSR, 0x07, v1); /* DAC speed */ + + SiS_SetReg(SISSR, 0x11, 0x0f); /* DDC, power save */ + + v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a; + v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00; + if(bios) { + memtype += 0xa5; + v1 = bios[memtype]; + v2 = bios[memtype + 8]; + v3 = bios[memtype + 16]; + v4 = bios[memtype + 24]; + v5 = bios[memtype + 32]; + v6 = bios[memtype + 40]; + v7 = bios[memtype + 48]; + v8 = bios[memtype + 56]; + } + if(ivideo->revision_id >= 0x80) + v3 &= 0xfd; + SiS_SetReg(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */ + SiS_SetReg(SISSR, 0x16, v2); + SiS_SetReg(SISSR, 0x17, v3); + SiS_SetReg(SISSR, 0x18, v4); + SiS_SetReg(SISSR, 0x19, v5); + SiS_SetReg(SISSR, 0x1a, v6); + SiS_SetReg(SISSR, 0x1b, v7); + SiS_SetReg(SISSR, 0x1c, v8); /* ---- */ + SiS_SetRegAND(SISSR, 0x15, 0xfb); + SiS_SetRegOR(SISSR, 0x15, 0x04); + if(bios) { + if(bios[0x53] & 0x02) { + SiS_SetRegOR(SISSR, 0x19, 0x20); + } + } + v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */ + if(ivideo->revision_id >= 0x80) + v1 |= 0x01; + SiS_SetReg(SISSR, 0x1f, v1); + SiS_SetReg(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */ + v1 = 0xf6; v2 = 0x0d; v3 = 0x00; + if(bios) { + v1 = bios[0xe8]; + v2 = bios[0xe9]; + v3 = bios[0xea]; + } + SiS_SetReg(SISSR, 0x23, v1); + SiS_SetReg(SISSR, 0x24, v2); + SiS_SetReg(SISSR, 0x25, v3); + SiS_SetReg(SISSR, 0x21, 0x84); + SiS_SetReg(SISSR, 0x22, 0x00); + SiS_SetReg(SISCR, 0x37, 0x00); + SiS_SetRegOR(SISPART1, 0x24, 0x01); /* unlock crt2 */ + SiS_SetReg(SISPART1, 0x00, 0x00); + v1 = 0x40; v2 = 0x11; + if(bios) { + v1 = bios[0xec]; + v2 = bios[0xeb]; + } + SiS_SetReg(SISPART1, 0x02, v1); + + if(ivideo->revision_id >= 0x80) + v2 &= ~0x01; + + reg = SiS_GetReg(SISPART4, 0x00); + if((reg == 1) || (reg == 2)) { + SiS_SetReg(SISCR, 0x37, 0x02); + SiS_SetReg(SISPART2, 0x00, 0x1c); + v4 = 0x00; v5 = 0x00; v6 = 0x10; + if(ivideo->SiS_Pr.UseROM) { + v4 = bios[0xf5]; + v5 = bios[0xf6]; + v6 = bios[0xf7]; + } + SiS_SetReg(SISPART4, 0x0d, v4); + SiS_SetReg(SISPART4, 0x0e, v5); + SiS_SetReg(SISPART4, 0x10, v6); + SiS_SetReg(SISPART4, 0x0f, 0x3f); + reg = SiS_GetReg(SISPART4, 0x01); + if(reg >= 0xb0) { + reg = SiS_GetReg(SISPART4, 0x23); + reg &= 0x20; + reg <<= 1; + SiS_SetReg(SISPART4, 0x23, reg); + } + } else { + v2 &= ~0x10; + } + SiS_SetReg(SISSR, 0x32, v2); + + SiS_SetRegAND(SISPART1, 0x24, 0xfe); /* Lock CRT2 */ + + reg = SiS_GetReg(SISSR, 0x16); + reg &= 0xc3; + SiS_SetReg(SISCR, 0x35, reg); + SiS_SetReg(SISCR, 0x83, 0x00); +#if !defined(__i386__) && !defined(__x86_64__) + if(sisfb_videoram) { + SiS_SetReg(SISSR, 0x13, 0x28); /* ? */ + reg = ((sisfb_videoram >> 10) - 1) | 0x40; + SiS_SetReg(SISSR, 0x14, reg); + } else { +#endif + /* Need to map max FB size for finding out about RAM size */ + mapsize = ivideo->video_size; + sisfb_post_map_vram(ivideo, &mapsize, 4); + + if(ivideo->video_vbase) { + sisfb_post_300_ramsize(pdev, mapsize); + iounmap(ivideo->video_vbase); + } else { + printk(KERN_DEBUG + "sisfb: Failed to map memory for size detection, assuming 8MB\n"); + SiS_SetReg(SISSR, 0x13, 0x28); /* ? */ + SiS_SetReg(SISSR, 0x14, 0x47); /* 8MB, 64bit default */ + } +#if !defined(__i386__) && !defined(__x86_64__) + } +#endif + if(bios) { + v1 = bios[0xe6]; + v2 = bios[0xe7]; + } else { + reg = SiS_GetReg(SISSR, 0x3a); + if((reg & 0x30) == 0x30) { + v1 = 0x04; /* PCI */ + v2 = 0x92; + } else { + v1 = 0x14; /* AGP */ + v2 = 0xb2; + } + } + SiS_SetReg(SISSR, 0x21, v1); + SiS_SetReg(SISSR, 0x22, v2); + + /* Sense CRT1 */ + sisfb_sense_crt1(ivideo); + + /* Set default mode, don't clear screen */ + ivideo->SiS_Pr.SiS_UseOEM = false; + SiS_SetEnableDstn(&ivideo->SiS_Pr, false); + SiS_SetEnableFstn(&ivideo->SiS_Pr, false); + ivideo->curFSTN = ivideo->curDSTN = 0; + ivideo->SiS_Pr.VideoMemorySize = 8 << 20; + SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80); + + SiS_SetReg(SISSR, 0x05, 0x86); + + /* Display off */ + SiS_SetRegOR(SISSR, 0x01, 0x20); + + /* Save mode number in CR34 */ + SiS_SetReg(SISCR, 0x34, 0x2e); + + /* Let everyone know what the current mode is */ + ivideo->modeprechange = 0x2e; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +#if 0 +static void sisfb_post_sis315330(struct pci_dev *pdev) +{ + /* TODO */ +} +#endif + +static inline int sisfb_xgi_is21(struct sis_video_info *ivideo) +{ + return ivideo->chip_real_id == XGI_21; +} + +static void sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay) +{ + unsigned int i; + u8 reg; + + for(i = 0; i <= (delay * 10 * 36); i++) { + reg = SiS_GetReg(SISSR, 0x05); + reg++; + } +} + +static int sisfb_find_host_bridge(struct sis_video_info *ivideo, + struct pci_dev *mypdev, + unsigned short pcivendor) +{ + struct pci_dev *pdev = NULL; + unsigned short temp; + int ret = 0; + + while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) { + temp = pdev->vendor; + if(temp == pcivendor) { + ret = 1; + pci_dev_put(pdev); + break; + } + } + + return ret; +} + +static int sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta, + unsigned int enda, unsigned int mapsize) +{ + unsigned int pos; + int i; + + writel(0, ivideo->video_vbase); + + for(i = starta; i <= enda; i++) { + pos = 1 << i; + if(pos < mapsize) + writel(pos, ivideo->video_vbase + pos); + } + + sisfb_post_xgi_delay(ivideo, 150); + + if(readl(ivideo->video_vbase) != 0) + return 0; + + for(i = starta; i <= enda; i++) { + pos = 1 << i; + if(pos < mapsize) { + if(readl(ivideo->video_vbase + pos) != pos) + return 0; + } else + return 0; + } + + return 1; +} + +static int sisfb_post_xgi_ramsize(struct sis_video_info *ivideo) +{ + unsigned int buswidth, ranksize, channelab, mapsize; + int i, j, k, l, status; + u8 reg, sr14; + static const u8 dramsr13[12 * 5] = { + 0x02, 0x0e, 0x0b, 0x80, 0x5d, + 0x02, 0x0e, 0x0a, 0x40, 0x59, + 0x02, 0x0d, 0x0b, 0x40, 0x4d, + 0x02, 0x0e, 0x09, 0x20, 0x55, + 0x02, 0x0d, 0x0a, 0x20, 0x49, + 0x02, 0x0c, 0x0b, 0x20, 0x3d, + 0x02, 0x0e, 0x08, 0x10, 0x51, + 0x02, 0x0d, 0x09, 0x10, 0x45, + 0x02, 0x0c, 0x0a, 0x10, 0x39, + 0x02, 0x0d, 0x08, 0x08, 0x41, + 0x02, 0x0c, 0x09, 0x08, 0x35, + 0x02, 0x0c, 0x08, 0x04, 0x31 + }; + static const u8 dramsr13_4[4 * 5] = { + 0x02, 0x0d, 0x09, 0x40, 0x45, + 0x02, 0x0c, 0x09, 0x20, 0x35, + 0x02, 0x0c, 0x08, 0x10, 0x31, + 0x02, 0x0b, 0x08, 0x08, 0x21 + }; + + /* Enable linear mode, disable 0xa0000 address decoding */ + /* We disable a0000 address decoding, because + * - if running on x86, if the card is disabled, it means + * that another card is in the system. We don't want + * to interphere with that primary card's textmode. + * - if running on non-x86, there usually is no VGA window + * at a0000. + */ + SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04)); + + /* Need to map max FB size for finding out about RAM size */ + mapsize = ivideo->video_size; + sisfb_post_map_vram(ivideo, &mapsize, 32); + + if(!ivideo->video_vbase) { + printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n"); + SiS_SetReg(SISSR, 0x13, 0x35); + SiS_SetReg(SISSR, 0x14, 0x41); + /* TODO */ + return -ENOMEM; + } + + /* Non-interleaving */ + SiS_SetReg(SISSR, 0x15, 0x00); + /* No tiling */ + SiS_SetReg(SISSR, 0x1c, 0x00); + + if(ivideo->chip == XGI_20) { + + channelab = 1; + reg = SiS_GetReg(SISCR, 0x97); + if(!(reg & 0x01)) { /* Single 32/16 */ + buswidth = 32; + SiS_SetReg(SISSR, 0x13, 0xb1); + SiS_SetReg(SISSR, 0x14, 0x52); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x02; + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) + goto bail_out; + + SiS_SetReg(SISSR, 0x13, 0x31); + SiS_SetReg(SISSR, 0x14, 0x42); + sisfb_post_xgi_delay(ivideo, 1); + if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize)) + goto bail_out; + + buswidth = 16; + SiS_SetReg(SISSR, 0x13, 0xb1); + SiS_SetReg(SISSR, 0x14, 0x41); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x01; + if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize)) + goto bail_out; + else + SiS_SetReg(SISSR, 0x13, 0x31); + } else { /* Dual 16/8 */ + buswidth = 16; + SiS_SetReg(SISSR, 0x13, 0xb1); + SiS_SetReg(SISSR, 0x14, 0x41); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x01; + if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize)) + goto bail_out; + + SiS_SetReg(SISSR, 0x13, 0x31); + SiS_SetReg(SISSR, 0x14, 0x31); + sisfb_post_xgi_delay(ivideo, 1); + if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize)) + goto bail_out; + + buswidth = 8; + SiS_SetReg(SISSR, 0x13, 0xb1); + SiS_SetReg(SISSR, 0x14, 0x30); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x00; + if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize)) + goto bail_out; + else + SiS_SetReg(SISSR, 0x13, 0x31); + } + + } else { /* XGI_40 */ + + reg = SiS_GetReg(SISCR, 0x97); + if(!(reg & 0x10)) { + reg = SiS_GetReg(SISSR, 0x39); + reg >>= 1; + } + + if(reg & 0x01) { /* DDRII */ + buswidth = 32; + if(ivideo->revision_id == 2) { + channelab = 2; + SiS_SetReg(SISSR, 0x13, 0xa1); + SiS_SetReg(SISSR, 0x14, 0x44); + sr14 = 0x04; + sisfb_post_xgi_delay(ivideo, 1); + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) + goto bail_out; + + SiS_SetReg(SISSR, 0x13, 0x21); + SiS_SetReg(SISSR, 0x14, 0x34); + if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize)) + goto bail_out; + + channelab = 1; + SiS_SetReg(SISSR, 0x13, 0xa1); + SiS_SetReg(SISSR, 0x14, 0x40); + sr14 = 0x00; + if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize)) + goto bail_out; + + SiS_SetReg(SISSR, 0x13, 0x21); + SiS_SetReg(SISSR, 0x14, 0x30); + } else { + channelab = 3; + SiS_SetReg(SISSR, 0x13, 0xa1); + SiS_SetReg(SISSR, 0x14, 0x4c); + sr14 = 0x0c; + sisfb_post_xgi_delay(ivideo, 1); + if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize)) + goto bail_out; + + channelab = 2; + SiS_SetReg(SISSR, 0x14, 0x48); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x08; + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) + goto bail_out; + + SiS_SetReg(SISSR, 0x13, 0x21); + SiS_SetReg(SISSR, 0x14, 0x3c); + sr14 = 0x0c; + + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) { + channelab = 3; + } else { + channelab = 2; + SiS_SetReg(SISSR, 0x14, 0x38); + sr14 = 0x08; + } + } + sisfb_post_xgi_delay(ivideo, 1); + + } else { /* DDR */ + + buswidth = 64; + if(ivideo->revision_id == 2) { + channelab = 1; + SiS_SetReg(SISSR, 0x13, 0xa1); + SiS_SetReg(SISSR, 0x14, 0x52); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x02; + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) + goto bail_out; + + SiS_SetReg(SISSR, 0x13, 0x21); + SiS_SetReg(SISSR, 0x14, 0x42); + } else { + channelab = 2; + SiS_SetReg(SISSR, 0x13, 0xa1); + SiS_SetReg(SISSR, 0x14, 0x5a); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x0a; + if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize)) + goto bail_out; + + SiS_SetReg(SISSR, 0x13, 0x21); + SiS_SetReg(SISSR, 0x14, 0x4a); + } + sisfb_post_xgi_delay(ivideo, 1); + + } + } + +bail_out: + SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14); + sisfb_post_xgi_delay(ivideo, 1); + + j = (ivideo->chip == XGI_20) ? 5 : 9; + k = (ivideo->chip == XGI_20) ? 12 : 4; + status = -EIO; + + for(i = 0; i < k; i++) { + + reg = (ivideo->chip == XGI_20) ? + dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4]; + SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg); + sisfb_post_xgi_delay(ivideo, 50); + + ranksize = (ivideo->chip == XGI_20) ? + dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3]; + + reg = SiS_GetReg(SISSR, 0x13); + if(reg & 0x80) ranksize <<= 1; + + if(ivideo->chip == XGI_20) { + if(buswidth == 16) ranksize <<= 1; + else if(buswidth == 32) ranksize <<= 2; + } else { + if(buswidth == 64) ranksize <<= 1; + } + + reg = 0; + l = channelab; + if(l == 3) l = 4; + if((ranksize * l) <= 256) { + while((ranksize >>= 1)) reg += 0x10; + } + + if(!reg) continue; + + SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0)); + sisfb_post_xgi_delay(ivideo, 1); + + if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) { + status = 0; + break; + } + } + + iounmap(ivideo->video_vbase); + + return status; +} + +static void sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb) +{ + u8 v1, v2, v3; + int index; + static const u8 cs90[8 * 3] = { + 0x16, 0x01, 0x01, + 0x3e, 0x03, 0x01, + 0x7c, 0x08, 0x01, + 0x79, 0x06, 0x01, + 0x29, 0x01, 0x81, + 0x5c, 0x23, 0x01, + 0x5c, 0x23, 0x01, + 0x5c, 0x23, 0x01 + }; + static const u8 csb8[8 * 3] = { + 0x5c, 0x23, 0x01, + 0x29, 0x01, 0x01, + 0x7c, 0x08, 0x01, + 0x79, 0x06, 0x01, + 0x29, 0x01, 0x81, + 0x5c, 0x23, 0x01, + 0x5c, 0x23, 0x01, + 0x5c, 0x23, 0x01 + }; + + regb = 0; /* ! */ + + index = regb * 3; + v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2]; + if(ivideo->haveXGIROM) { + v1 = ivideo->bios_abase[0x90 + index]; + v2 = ivideo->bios_abase[0x90 + index + 1]; + v3 = ivideo->bios_abase[0x90 + index + 2]; + } + SiS_SetReg(SISSR, 0x28, v1); + SiS_SetReg(SISSR, 0x29, v2); + SiS_SetReg(SISSR, 0x2a, v3); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + index = regb * 3; + v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2]; + if(ivideo->haveXGIROM) { + v1 = ivideo->bios_abase[0xb8 + index]; + v2 = ivideo->bios_abase[0xb8 + index + 1]; + v3 = ivideo->bios_abase[0xb8 + index + 2]; + } + SiS_SetReg(SISSR, 0x2e, v1); + SiS_SetReg(SISSR, 0x2f, v2); + SiS_SetReg(SISSR, 0x30, v3); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); +} + +static void sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo, + u8 regb) +{ + unsigned char *bios = ivideo->bios_abase; + u8 v1; + + SiS_SetReg(SISSR, 0x28, 0x64); + SiS_SetReg(SISSR, 0x29, 0x63); + sisfb_post_xgi_delay(ivideo, 15); + SiS_SetReg(SISSR, 0x18, 0x00); + SiS_SetReg(SISSR, 0x19, 0x20); + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + SiS_SetReg(SISSR, 0x18, 0xc5); + SiS_SetReg(SISSR, 0x19, 0x23); + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + sisfb_post_xgi_delay(ivideo, 1); + SiS_SetReg(SISCR, 0x97, 0x11); + sisfb_post_xgi_setclocks(ivideo, regb); + sisfb_post_xgi_delay(ivideo, 0x46); + SiS_SetReg(SISSR, 0x18, 0xc5); + SiS_SetReg(SISSR, 0x19, 0x23); + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + sisfb_post_xgi_delay(ivideo, 1); + SiS_SetReg(SISSR, 0x1b, 0x04); + sisfb_post_xgi_delay(ivideo, 1); + SiS_SetReg(SISSR, 0x1b, 0x00); + sisfb_post_xgi_delay(ivideo, 1); + v1 = 0x31; + if (ivideo->haveXGIROM) { + v1 = bios[0xf0]; + } + SiS_SetReg(SISSR, 0x18, v1); + SiS_SetReg(SISSR, 0x19, 0x06); + SiS_SetReg(SISSR, 0x16, 0x04); + SiS_SetReg(SISSR, 0x16, 0x84); + sisfb_post_xgi_delay(ivideo, 1); +} + +static void sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo) +{ + sisfb_post_xgi_setclocks(ivideo, 1); + + SiS_SetReg(SISCR, 0x97, 0x11); + sisfb_post_xgi_delay(ivideo, 0x46); + + SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS2 */ + SiS_SetReg(SISSR, 0x19, 0x80); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + + SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS3 */ + SiS_SetReg(SISSR, 0x19, 0xc0); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + + SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS1 */ + SiS_SetReg(SISSR, 0x19, 0x40); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + + SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */ + SiS_SetReg(SISSR, 0x19, 0x02); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + sisfb_post_xgi_delay(ivideo, 1); + + SiS_SetReg(SISSR, 0x1b, 0x04); + sisfb_post_xgi_delay(ivideo, 1); + + SiS_SetReg(SISSR, 0x1b, 0x00); + sisfb_post_xgi_delay(ivideo, 1); + + SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */ + SiS_SetReg(SISSR, 0x19, 0x00); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + sisfb_post_xgi_delay(ivideo, 1); +} + +static void sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb) +{ + unsigned char *bios = ivideo->bios_abase; + static const u8 cs158[8] = { + 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs160[8] = { + 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs168[8] = { + 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + u8 reg; + u8 v1; + u8 v2; + u8 v3; + + SiS_SetReg(SISCR, 0xb0, 0x80); /* DDR2 dual frequency mode */ + SiS_SetReg(SISCR, 0x82, 0x77); + SiS_SetReg(SISCR, 0x86, 0x00); + reg = SiS_GetReg(SISCR, 0x86); + SiS_SetReg(SISCR, 0x86, 0x88); + reg = SiS_GetReg(SISCR, 0x86); + v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb]; + if (ivideo->haveXGIROM) { + v1 = bios[regb + 0x168]; + v2 = bios[regb + 0x160]; + v3 = bios[regb + 0x158]; + } + SiS_SetReg(SISCR, 0x86, v1); + SiS_SetReg(SISCR, 0x82, 0x77); + SiS_SetReg(SISCR, 0x85, 0x00); + reg = SiS_GetReg(SISCR, 0x85); + SiS_SetReg(SISCR, 0x85, 0x88); + reg = SiS_GetReg(SISCR, 0x85); + SiS_SetReg(SISCR, 0x85, v2); + SiS_SetReg(SISCR, 0x82, v3); + SiS_SetReg(SISCR, 0x98, 0x01); + SiS_SetReg(SISCR, 0x9a, 0x02); + if (sisfb_xgi_is21(ivideo)) + sisfb_post_xgi_ddr2_mrs_xg21(ivideo); + else + sisfb_post_xgi_ddr2_mrs_default(ivideo, regb); +} + +static u8 sisfb_post_xgi_ramtype(struct sis_video_info *ivideo) +{ + unsigned char *bios = ivideo->bios_abase; + u8 ramtype; + u8 reg; + u8 v1; + + ramtype = 0x00; v1 = 0x10; + if (ivideo->haveXGIROM) { + ramtype = bios[0x62]; + v1 = bios[0x1d2]; + } + if (!(ramtype & 0x80)) { + if (sisfb_xgi_is21(ivideo)) { + SiS_SetRegAND(SISCR, 0xb4, 0xfd); /* GPIO control */ + SiS_SetRegOR(SISCR, 0x4a, 0x80); /* GPIOH EN */ + reg = SiS_GetReg(SISCR, 0x48); + SiS_SetRegOR(SISCR, 0xb4, 0x02); + ramtype = reg & 0x01; /* GPIOH */ + } else if (ivideo->chip == XGI_20) { + SiS_SetReg(SISCR, 0x97, v1); + reg = SiS_GetReg(SISCR, 0x97); + if (reg & 0x10) { + ramtype = (reg & 0x01) << 1; + } + } else { + reg = SiS_GetReg(SISSR, 0x39); + ramtype = reg & 0x02; + if (!(ramtype)) { + reg = SiS_GetReg(SISSR, 0x3a); + ramtype = (reg >> 1) & 0x01; + } + } + } + ramtype &= 0x07; + + return ramtype; +} + +static int sisfb_post_xgi(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + unsigned char *bios = ivideo->bios_abase; + struct pci_dev *mypdev = NULL; + const u8 *ptr, *ptr2; + u8 v1, v2, v3, v4, v5, reg, ramtype; + u32 rega, regb, regd; + int i, j, k, index; + static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 }; + static const u8 cs76[2] = { 0xa3, 0xfb }; + static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 }; + static const u8 cs158[8] = { + 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs160[8] = { + 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs168[8] = { + 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs128[3 * 8] = { + 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs148[2 * 8] = { + 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs31a[8 * 4] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs33a[8 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs45a[8 * 2] = { + 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs170[7 * 8] = { + 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs1a8[3 * 8] = { + 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs100[2 * 8] = { + 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + /* VGA enable */ + reg = SiS_GetRegByte(SISVGAENABLE) | 0x01; + SiS_SetRegByte(SISVGAENABLE, reg); + + /* Misc */ + reg = SiS_GetRegByte(SISMISCR) | 0x01; + SiS_SetRegByte(SISMISCW, reg); + + /* Unlock SR */ + SiS_SetReg(SISSR, 0x05, 0x86); + reg = SiS_GetReg(SISSR, 0x05); + if(reg != 0xa1) + return 0; + + /* Clear some regs */ + for(i = 0; i < 0x22; i++) { + if(0x06 + i == 0x20) continue; + SiS_SetReg(SISSR, 0x06 + i, 0x00); + } + for(i = 0; i < 0x0b; i++) { + SiS_SetReg(SISSR, 0x31 + i, 0x00); + } + for(i = 0; i < 0x10; i++) { + SiS_SetReg(SISCR, 0x30 + i, 0x00); + } + + ptr = cs78; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x78]; + } + for(i = 0; i < 3; i++) { + SiS_SetReg(SISSR, 0x23 + i, ptr[i]); + } + + ptr = cs76; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x76]; + } + for(i = 0; i < 2; i++) { + SiS_SetReg(SISSR, 0x21 + i, ptr[i]); + } + + v1 = 0x18; v2 = 0x00; + if(ivideo->haveXGIROM) { + v1 = bios[0x74]; + v2 = bios[0x75]; + } + SiS_SetReg(SISSR, 0x07, v1); + SiS_SetReg(SISSR, 0x11, 0x0f); + SiS_SetReg(SISSR, 0x1f, v2); + /* PCI linear mode, RelIO enabled, A0000 decoding disabled */ + SiS_SetReg(SISSR, 0x20, 0x80 | 0x20 | 0x04); + SiS_SetReg(SISSR, 0x27, 0x74); + + ptr = cs7b; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x7b]; + } + for(i = 0; i < 3; i++) { + SiS_SetReg(SISSR, 0x31 + i, ptr[i]); + } + + if(ivideo->chip == XGI_40) { + if(ivideo->revision_id == 2) { + SiS_SetRegANDOR(SISSR, 0x3b, 0x3f, 0xc0); + } + SiS_SetReg(SISCR, 0x7d, 0xfe); + SiS_SetReg(SISCR, 0x7e, 0x0f); + } + if(ivideo->revision_id == 0) { /* 40 *and* 20? */ + SiS_SetRegAND(SISCR, 0x58, 0xd7); + reg = SiS_GetReg(SISCR, 0xcb); + if(reg & 0x20) { + SiS_SetRegANDOR(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */ + } + } + + reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00; + SiS_SetRegANDOR(SISCR, 0x38, 0x1f, reg); + + if(ivideo->chip == XGI_20) { + SiS_SetReg(SISSR, 0x36, 0x70); + } else { + SiS_SetReg(SISVID, 0x00, 0x86); + SiS_SetReg(SISVID, 0x32, 0x00); + SiS_SetReg(SISVID, 0x30, 0x00); + SiS_SetReg(SISVID, 0x32, 0x01); + SiS_SetReg(SISVID, 0x30, 0x00); + SiS_SetRegAND(SISVID, 0x2f, 0xdf); + SiS_SetRegAND(SISCAP, 0x00, 0x3f); + + SiS_SetReg(SISPART1, 0x2f, 0x01); + SiS_SetReg(SISPART1, 0x00, 0x00); + SiS_SetReg(SISPART1, 0x02, bios[0x7e]); + SiS_SetReg(SISPART1, 0x2e, 0x08); + SiS_SetRegAND(SISPART1, 0x35, 0x7f); + SiS_SetRegAND(SISPART1, 0x50, 0xfe); + + reg = SiS_GetReg(SISPART4, 0x00); + if(reg == 1 || reg == 2) { + SiS_SetReg(SISPART2, 0x00, 0x1c); + SiS_SetReg(SISPART4, 0x0d, bios[0x7f]); + SiS_SetReg(SISPART4, 0x0e, bios[0x80]); + SiS_SetReg(SISPART4, 0x10, bios[0x81]); + SiS_SetRegAND(SISPART4, 0x0f, 0x3f); + + reg = SiS_GetReg(SISPART4, 0x01); + if((reg & 0xf0) >= 0xb0) { + reg = SiS_GetReg(SISPART4, 0x23); + if(reg & 0x20) reg |= 0x40; + SiS_SetReg(SISPART4, 0x23, reg); + reg = (reg & 0x20) ? 0x02 : 0x00; + SiS_SetRegANDOR(SISPART1, 0x1e, 0xfd, reg); + } + } + + v1 = bios[0x77]; + + reg = SiS_GetReg(SISSR, 0x3b); + if(reg & 0x02) { + reg = SiS_GetReg(SISSR, 0x3a); + v2 = (reg & 0x30) >> 3; + if(!(v2 & 0x04)) v2 ^= 0x02; + reg = SiS_GetReg(SISSR, 0x39); + if(reg & 0x80) v2 |= 0x80; + v2 |= 0x01; + + if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) { + pci_dev_put(mypdev); + if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4)) + v2 &= 0xf9; + v2 |= 0x08; + v1 &= 0xfe; + } else { + mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL); + if(!mypdev) + mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL); + if(!mypdev) + mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL); + if(mypdev) { + pci_read_config_dword(mypdev, 0x94, ®d); + regd &= 0xfffffeff; + pci_write_config_dword(mypdev, 0x94, regd); + v1 &= 0xfe; + pci_dev_put(mypdev); + } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) { + v1 &= 0xfe; + } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) || + sisfb_find_host_bridge(ivideo, pdev, 0x1022) || + sisfb_find_host_bridge(ivideo, pdev, 0x700e) || + sisfb_find_host_bridge(ivideo, pdev, 0x10de)) { + if((v2 & 0x06) == 4) + v2 ^= 0x06; + v2 |= 0x08; + } + } + SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, v2); + } + SiS_SetReg(SISSR, 0x22, v1); + + if(ivideo->revision_id == 2) { + v1 = SiS_GetReg(SISSR, 0x3b); + v2 = SiS_GetReg(SISSR, 0x3a); + regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8); + if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) ) + SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01); + + if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) { + /* TODO: set CR5f &0xf1 | 0x01 for version 6570 + * of nforce 2 ROM + */ + if(0) + SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01); + pci_dev_put(mypdev); + } + } + + v1 = 0x30; + reg = SiS_GetReg(SISSR, 0x3b); + v2 = SiS_GetReg(SISCR, 0x5f); + if((!(reg & 0x02)) && (v2 & 0x0e)) + v1 |= 0x08; + SiS_SetReg(SISSR, 0x27, v1); + + if(bios[0x64] & 0x01) { + SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, bios[0x64]); + } + + v1 = bios[0x4f7]; + pci_read_config_dword(pdev, 0x50, ®d); + regd = (regd >> 20) & 0x0f; + if(regd == 1) { + v1 &= 0xfc; + SiS_SetRegOR(SISCR, 0x5f, 0x08); + } + SiS_SetReg(SISCR, 0x48, v1); + + SiS_SetRegANDOR(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb); + SiS_SetRegANDOR(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f); + SiS_SetRegANDOR(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f); + SiS_SetRegANDOR(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7); + SiS_SetRegANDOR(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f); + SiS_SetReg(SISCR, 0x70, bios[0x4fc]); + SiS_SetRegANDOR(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f); + SiS_SetReg(SISCR, 0x74, 0xd0); + SiS_SetRegANDOR(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30); + SiS_SetRegANDOR(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f); + SiS_SetRegANDOR(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f); + v1 = bios[0x501]; + if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) { + v1 = 0xf0; + pci_dev_put(mypdev); + } + SiS_SetReg(SISCR, 0x77, v1); + } + + /* RAM type: + * + * 0 == DDR1, 1 == DDR2, 2..7 == reserved? + * + * The code seems to written so that regb should equal ramtype, + * however, so far it has been hardcoded to 0. Enable other values only + * on XGI Z9, as it passes the POST, and add a warning for others. + */ + ramtype = sisfb_post_xgi_ramtype(ivideo); + if (!sisfb_xgi_is21(ivideo) && ramtype) { + dev_warn(&pdev->dev, + "RAM type something else than expected: %d\n", + ramtype); + regb = 0; + } else { + regb = ramtype; + } + + v1 = 0xff; + if(ivideo->haveXGIROM) { + v1 = bios[0x140 + regb]; + } + SiS_SetReg(SISCR, 0x6d, v1); + + ptr = cs128; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x128]; + } + for(i = 0, j = 0; i < 3; i++, j += 8) { + SiS_SetReg(SISCR, 0x68 + i, ptr[j + regb]); + } + + ptr = cs31a; + ptr2 = cs33a; + if(ivideo->haveXGIROM) { + index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6; + ptr = (const u8 *)&bios[index]; + ptr2 = (const u8 *)&bios[index + 0x20]; + } + for(i = 0; i < 2; i++) { + if(i == 0) { + regd = le32_to_cpu(((u32 *)ptr)[regb]); + rega = 0x6b; + } else { + regd = le32_to_cpu(((u32 *)ptr2)[regb]); + rega = 0x6e; + } + reg = 0x00; + for(j = 0; j < 16; j++) { + reg &= 0xf3; + if(regd & 0x01) reg |= 0x04; + if(regd & 0x02) reg |= 0x08; + regd >>= 2; + SiS_SetReg(SISCR, rega, reg); + reg = SiS_GetReg(SISCR, rega); + reg = SiS_GetReg(SISCR, rega); + reg += 0x10; + } + } + + SiS_SetRegAND(SISCR, 0x6e, 0xfc); + + ptr = NULL; + if(ivideo->haveXGIROM) { + index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6; + ptr = (const u8 *)&bios[index]; + } + for(i = 0; i < 4; i++) { + SiS_SetRegANDOR(SISCR, 0x6e, 0xfc, i); + reg = 0x00; + for(j = 0; j < 2; j++) { + regd = 0; + if(ptr) { + regd = le32_to_cpu(((u32 *)ptr)[regb * 8]); + ptr += 4; + } + /* reg = 0x00; */ + for(k = 0; k < 16; k++) { + reg &= 0xfc; + if(regd & 0x01) reg |= 0x01; + if(regd & 0x02) reg |= 0x02; + regd >>= 2; + SiS_SetReg(SISCR, 0x6f, reg); + reg = SiS_GetReg(SISCR, 0x6f); + reg = SiS_GetReg(SISCR, 0x6f); + reg += 0x08; + } + } + } + + ptr = cs148; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x148]; + } + for(i = 0, j = 0; i < 2; i++, j += 8) { + SiS_SetReg(SISCR, 0x80 + i, ptr[j + regb]); + } + + SiS_SetRegAND(SISCR, 0x89, 0x8f); + + ptr = cs45a; + if(ivideo->haveXGIROM) { + index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6; + ptr = (const u8 *)&bios[index]; + } + regd = le16_to_cpu(((const u16 *)ptr)[regb]); + reg = 0x80; + for(i = 0; i < 5; i++) { + reg &= 0xfc; + if(regd & 0x01) reg |= 0x01; + if(regd & 0x02) reg |= 0x02; + regd >>= 2; + SiS_SetReg(SISCR, 0x89, reg); + reg = SiS_GetReg(SISCR, 0x89); + reg = SiS_GetReg(SISCR, 0x89); + reg += 0x10; + } + + v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13; + if(ivideo->haveXGIROM) { + v1 = bios[0x118 + regb]; + v2 = bios[0xf8 + regb]; + v3 = bios[0x120 + regb]; + v4 = bios[0x1ca]; + } + SiS_SetReg(SISCR, 0x45, v1 & 0x0f); + SiS_SetReg(SISCR, 0x99, (v1 >> 4) & 0x07); + SiS_SetRegOR(SISCR, 0x40, v1 & 0x80); + SiS_SetReg(SISCR, 0x41, v2); + + ptr = cs170; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x170]; + } + for(i = 0, j = 0; i < 7; i++, j += 8) { + SiS_SetReg(SISCR, 0x90 + i, ptr[j + regb]); + } + + SiS_SetReg(SISCR, 0x59, v3); + + ptr = cs1a8; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x1a8]; + } + for(i = 0, j = 0; i < 3; i++, j += 8) { + SiS_SetReg(SISCR, 0xc3 + i, ptr[j + regb]); + } + + ptr = cs100; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x100]; + } + for(i = 0, j = 0; i < 2; i++, j += 8) { + SiS_SetReg(SISCR, 0x8a + i, ptr[j + regb]); + } + + SiS_SetReg(SISCR, 0xcf, v4); + + SiS_SetReg(SISCR, 0x83, 0x09); + SiS_SetReg(SISCR, 0x87, 0x00); + + if(ivideo->chip == XGI_40) { + if( (ivideo->revision_id == 1) || + (ivideo->revision_id == 2) ) { + SiS_SetReg(SISCR, 0x8c, 0x87); + } + } + + if (regb == 1) + SiS_SetReg(SISSR, 0x17, 0x80); /* DDR2 */ + else + SiS_SetReg(SISSR, 0x17, 0x00); /* DDR1 */ + SiS_SetReg(SISSR, 0x1a, 0x87); + + if(ivideo->chip == XGI_20) { + SiS_SetReg(SISSR, 0x15, 0x00); + SiS_SetReg(SISSR, 0x1c, 0x00); + } + + switch(ramtype) { + case 0: + sisfb_post_xgi_setclocks(ivideo, regb); + if((ivideo->chip == XGI_20) || + (ivideo->revision_id == 1) || + (ivideo->revision_id == 2)) { + v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb]; + if(ivideo->haveXGIROM) { + v1 = bios[regb + 0x158]; + v2 = bios[regb + 0x160]; + v3 = bios[regb + 0x168]; + } + SiS_SetReg(SISCR, 0x82, v1); + SiS_SetReg(SISCR, 0x85, v2); + SiS_SetReg(SISCR, 0x86, v3); + } else { + SiS_SetReg(SISCR, 0x82, 0x88); + SiS_SetReg(SISCR, 0x86, 0x00); + reg = SiS_GetReg(SISCR, 0x86); + SiS_SetReg(SISCR, 0x86, 0x88); + reg = SiS_GetReg(SISCR, 0x86); + SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]); + SiS_SetReg(SISCR, 0x82, 0x77); + SiS_SetReg(SISCR, 0x85, 0x00); + reg = SiS_GetReg(SISCR, 0x85); + SiS_SetReg(SISCR, 0x85, 0x88); + reg = SiS_GetReg(SISCR, 0x85); + SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]); + SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]); + } + if(ivideo->chip == XGI_40) { + SiS_SetReg(SISCR, 0x97, 0x00); + } + SiS_SetReg(SISCR, 0x98, 0x01); + SiS_SetReg(SISCR, 0x9a, 0x02); + + SiS_SetReg(SISSR, 0x18, 0x01); + if((ivideo->chip == XGI_20) || + (ivideo->revision_id == 2)) { + SiS_SetReg(SISSR, 0x19, 0x40); + } else { + SiS_SetReg(SISSR, 0x19, 0x20); + } + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) { + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + SiS_SetReg(SISSR, 0x18, 0x00); + if((ivideo->chip == XGI_20) || + (ivideo->revision_id == 2)) { + SiS_SetReg(SISSR, 0x19, 0x40); + } else { + SiS_SetReg(SISSR, 0x19, 0x20); + } + } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) { + /* SiS_SetReg(SISSR, 0x16, 0x0c); */ /* ? */ + } + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + sisfb_post_xgi_delay(ivideo, 4); + v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83; + if(ivideo->haveXGIROM) { + v1 = bios[0xf0]; + index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e; + v2 = bios[index]; + v3 = bios[index + 1]; + v4 = bios[index + 2]; + v5 = bios[index + 3]; + } + SiS_SetReg(SISSR, 0x18, v1); + SiS_SetReg(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01)); + SiS_SetReg(SISSR, 0x16, v2); + SiS_SetReg(SISSR, 0x16, v3); + sisfb_post_xgi_delay(ivideo, 0x43); + SiS_SetReg(SISSR, 0x1b, 0x03); + sisfb_post_xgi_delay(ivideo, 0x22); + SiS_SetReg(SISSR, 0x18, v1); + SiS_SetReg(SISSR, 0x19, 0x00); + SiS_SetReg(SISSR, 0x16, v4); + SiS_SetReg(SISSR, 0x16, v5); + SiS_SetReg(SISSR, 0x1b, 0x00); + break; + case 1: + sisfb_post_xgi_ddr2(ivideo, regb); + break; + default: + sisfb_post_xgi_setclocks(ivideo, regb); + if((ivideo->chip == XGI_40) && + ((ivideo->revision_id == 1) || + (ivideo->revision_id == 2))) { + SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]); + SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]); + SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]); + } else { + SiS_SetReg(SISCR, 0x82, 0x88); + SiS_SetReg(SISCR, 0x86, 0x00); + reg = SiS_GetReg(SISCR, 0x86); + SiS_SetReg(SISCR, 0x86, 0x88); + SiS_SetReg(SISCR, 0x82, 0x77); + SiS_SetReg(SISCR, 0x85, 0x00); + reg = SiS_GetReg(SISCR, 0x85); + SiS_SetReg(SISCR, 0x85, 0x88); + reg = SiS_GetReg(SISCR, 0x85); + v1 = cs160[regb]; v2 = cs158[regb]; + if(ivideo->haveXGIROM) { + v1 = bios[regb + 0x160]; + v2 = bios[regb + 0x158]; + } + SiS_SetReg(SISCR, 0x85, v1); + SiS_SetReg(SISCR, 0x82, v2); + } + if(ivideo->chip == XGI_40) { + SiS_SetReg(SISCR, 0x97, 0x11); + } + if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) { + SiS_SetReg(SISCR, 0x98, 0x01); + } else { + SiS_SetReg(SISCR, 0x98, 0x03); + } + SiS_SetReg(SISCR, 0x9a, 0x02); + + if(ivideo->chip == XGI_40) { + SiS_SetReg(SISSR, 0x18, 0x01); + } else { + SiS_SetReg(SISSR, 0x18, 0x00); + } + SiS_SetReg(SISSR, 0x19, 0x40); + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) { + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + SiS_SetReg(SISSR, 0x18, 0x00); + SiS_SetReg(SISSR, 0x19, 0x40); + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + } + sisfb_post_xgi_delay(ivideo, 4); + v1 = 0x31; + if(ivideo->haveXGIROM) { + v1 = bios[0xf0]; + } + SiS_SetReg(SISSR, 0x18, v1); + SiS_SetReg(SISSR, 0x19, 0x01); + if(ivideo->chip == XGI_40) { + SiS_SetReg(SISSR, 0x16, bios[0x53e]); + SiS_SetReg(SISSR, 0x16, bios[0x53f]); + } else { + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + } + sisfb_post_xgi_delay(ivideo, 0x43); + if(ivideo->chip == XGI_40) { + SiS_SetReg(SISSR, 0x1b, 0x01); + } else { + SiS_SetReg(SISSR, 0x1b, 0x03); + } + sisfb_post_xgi_delay(ivideo, 0x22); + SiS_SetReg(SISSR, 0x18, v1); + SiS_SetReg(SISSR, 0x19, 0x00); + if(ivideo->chip == XGI_40) { + SiS_SetReg(SISSR, 0x16, bios[0x540]); + SiS_SetReg(SISSR, 0x16, bios[0x541]); + } else { + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + } + SiS_SetReg(SISSR, 0x1b, 0x00); + } + + regb = 0; /* ! */ + v1 = 0x03; + if(ivideo->haveXGIROM) { + v1 = bios[0x110 + regb]; + } + SiS_SetReg(SISSR, 0x1b, v1); + + /* RAM size */ + v1 = 0x00; v2 = 0x00; + if(ivideo->haveXGIROM) { + v1 = bios[0x62]; + v2 = bios[0x63]; + } + regb = 0; /* ! */ + regd = 1 << regb; + if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) { + + SiS_SetReg(SISSR, 0x13, bios[regb + 0xe0]); + SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]); + + } else { + int err; + + /* Set default mode, don't clear screen */ + ivideo->SiS_Pr.SiS_UseOEM = false; + SiS_SetEnableDstn(&ivideo->SiS_Pr, false); + SiS_SetEnableFstn(&ivideo->SiS_Pr, false); + ivideo->curFSTN = ivideo->curDSTN = 0; + ivideo->SiS_Pr.VideoMemorySize = 8 << 20; + SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80); + + SiS_SetReg(SISSR, 0x05, 0x86); + + /* Disable read-cache */ + SiS_SetRegAND(SISSR, 0x21, 0xdf); + err = sisfb_post_xgi_ramsize(ivideo); + /* Enable read-cache */ + SiS_SetRegOR(SISSR, 0x21, 0x20); + + if (err) { + dev_err(&pdev->dev, + "%s: RAM size detection failed: %d\n", + __func__, err); + return 0; + } + } + +#if 0 + printk(KERN_DEBUG "-----------------\n"); + for(i = 0; i < 0xff; i++) { + reg = SiS_GetReg(SISCR, i); + printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg); + } + for(i = 0; i < 0x40; i++) { + reg = SiS_GetReg(SISSR, i); + printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg); + } + printk(KERN_DEBUG "-----------------\n"); +#endif + + /* Sense CRT1 */ + if(ivideo->chip == XGI_20) { + SiS_SetRegOR(SISCR, 0x32, 0x20); + } else { + reg = SiS_GetReg(SISPART4, 0x00); + if((reg == 1) || (reg == 2)) { + sisfb_sense_crt1(ivideo); + } else { + SiS_SetRegOR(SISCR, 0x32, 0x20); + } + } + + /* Set default mode, don't clear screen */ + ivideo->SiS_Pr.SiS_UseOEM = false; + SiS_SetEnableDstn(&ivideo->SiS_Pr, false); + SiS_SetEnableFstn(&ivideo->SiS_Pr, false); + ivideo->curFSTN = ivideo->curDSTN = 0; + SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80); + + SiS_SetReg(SISSR, 0x05, 0x86); + + /* Display off */ + SiS_SetRegOR(SISSR, 0x01, 0x20); + + /* Save mode number in CR34 */ + SiS_SetReg(SISCR, 0x34, 0x2e); + + /* Let everyone know what the current mode is */ + ivideo->modeprechange = 0x2e; + + if(ivideo->chip == XGI_40) { + reg = SiS_GetReg(SISCR, 0xca); + v1 = SiS_GetReg(SISCR, 0xcc); + if((reg & 0x10) && (!(v1 & 0x04))) { + printk(KERN_ERR + "sisfb: Please connect power to the card.\n"); + return 0; + } + } + + return 1; +} +#endif + +static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data]; + struct sis_video_info *ivideo = NULL; + struct fb_info *sis_fb_info = NULL; + u16 reg16; + u8 reg; + int i, ret; + + if(sisfb_off) + return -ENXIO; + + sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev); + if(!sis_fb_info) + return -ENOMEM; + + ivideo = (struct sis_video_info *)sis_fb_info->par; + ivideo->memyselfandi = sis_fb_info; + + ivideo->sisfb_id = SISFB_ID; + + if(card_list == NULL) { + ivideo->cardnumber = 0; + } else { + struct sis_video_info *countvideo = card_list; + ivideo->cardnumber = 1; + while((countvideo = countvideo->next) != NULL) + ivideo->cardnumber++; + } + + strncpy(ivideo->myid, chipinfo->chip_name, 30); + + ivideo->warncount = 0; + ivideo->chip_id = pdev->device; + ivideo->chip_vendor = pdev->vendor; + ivideo->revision_id = pdev->revision; + ivideo->SiS_Pr.ChipRevision = ivideo->revision_id; + pci_read_config_word(pdev, PCI_COMMAND, ®16); + ivideo->sisvga_enabled = reg16 & 0x01; + ivideo->pcibus = pdev->bus->number; + ivideo->pcislot = PCI_SLOT(pdev->devfn); + ivideo->pcifunc = PCI_FUNC(pdev->devfn); + ivideo->subsysvendor = pdev->subsystem_vendor; + ivideo->subsysdevice = pdev->subsystem_device; + +#ifndef MODULE + if(sisfb_mode_idx == -1) { + sisfb_get_vga_mode_from_kernel(); + } +#endif + + ivideo->chip = chipinfo->chip; + ivideo->chip_real_id = chipinfo->chip; + ivideo->sisvga_engine = chipinfo->vgaengine; + ivideo->hwcursor_size = chipinfo->hwcursor_size; + ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable; + ivideo->mni = chipinfo->mni; + + ivideo->detectedpdc = 0xff; + ivideo->detectedpdca = 0xff; + ivideo->detectedlcda = 0xff; + + ivideo->sisfb_thismonitor.datavalid = false; + + ivideo->current_base = 0; + + ivideo->engineok = 0; + + ivideo->sisfb_was_boot_device = 0; + + if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) { + if(ivideo->sisvga_enabled) + ivideo->sisfb_was_boot_device = 1; + else { + printk(KERN_DEBUG "sisfb: PCI device is disabled, " + "but marked as boot video device ???\n"); + printk(KERN_DEBUG "sisfb: I will not accept this " + "as the primary VGA device\n"); + } + } + + ivideo->sisfb_parm_mem = sisfb_parm_mem; + ivideo->sisfb_accel = sisfb_accel; + ivideo->sisfb_ypan = sisfb_ypan; + ivideo->sisfb_max = sisfb_max; + ivideo->sisfb_userom = sisfb_userom; + ivideo->sisfb_useoem = sisfb_useoem; + ivideo->sisfb_mode_idx = sisfb_mode_idx; + ivideo->sisfb_parm_rate = sisfb_parm_rate; + ivideo->sisfb_crt1off = sisfb_crt1off; + ivideo->sisfb_forcecrt1 = sisfb_forcecrt1; + ivideo->sisfb_crt2type = sisfb_crt2type; + ivideo->sisfb_crt2flags = sisfb_crt2flags; + /* pdc(a), scalelcd, special timing, lvdshl handled below */ + ivideo->sisfb_dstn = sisfb_dstn; + ivideo->sisfb_fstn = sisfb_fstn; + ivideo->sisfb_tvplug = sisfb_tvplug; + ivideo->sisfb_tvstd = sisfb_tvstd; + ivideo->tvxpos = sisfb_tvxposoffset; + ivideo->tvypos = sisfb_tvyposoffset; + ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate; + ivideo->refresh_rate = 0; + if(ivideo->sisfb_parm_rate != -1) { + ivideo->refresh_rate = ivideo->sisfb_parm_rate; + } + + ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd; + ivideo->SiS_Pr.CenterScreen = -1; + ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming; + ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl; + + ivideo->SiS_Pr.SiS_Backup70xx = 0xff; + ivideo->SiS_Pr.SiS_CHOverScan = -1; + ivideo->SiS_Pr.SiS_ChSW = false; + ivideo->SiS_Pr.SiS_UseLCDA = false; + ivideo->SiS_Pr.HaveEMI = false; + ivideo->SiS_Pr.HaveEMILCD = false; + ivideo->SiS_Pr.OverruleEMI = false; + ivideo->SiS_Pr.SiS_SensibleSR11 = false; + ivideo->SiS_Pr.SiS_MyCR63 = 0x63; + ivideo->SiS_Pr.PDC = -1; + ivideo->SiS_Pr.PDCA = -1; + ivideo->SiS_Pr.DDCPortMixup = false; +#ifdef CONFIG_FB_SIS_315 + if(ivideo->chip >= SIS_330) { + ivideo->SiS_Pr.SiS_MyCR63 = 0x53; + if(ivideo->chip >= SIS_661) { + ivideo->SiS_Pr.SiS_SensibleSR11 = true; + } + } +#endif + + memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var)); + + pci_set_drvdata(pdev, ivideo); + + /* Patch special cases */ + if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) { + switch(ivideo->nbridge->device) { +#ifdef CONFIG_FB_SIS_300 + case PCI_DEVICE_ID_SI_730: + ivideo->chip = SIS_730; + strcpy(ivideo->myid, "SiS 730"); + break; +#endif +#ifdef CONFIG_FB_SIS_315 + case PCI_DEVICE_ID_SI_651: + /* ivideo->chip is ok */ + strcpy(ivideo->myid, "SiS 651"); + break; + case PCI_DEVICE_ID_SI_740: + ivideo->chip = SIS_740; + strcpy(ivideo->myid, "SiS 740"); + break; + case PCI_DEVICE_ID_SI_661: + ivideo->chip = SIS_661; + strcpy(ivideo->myid, "SiS 661"); + break; + case PCI_DEVICE_ID_SI_741: + ivideo->chip = SIS_741; + strcpy(ivideo->myid, "SiS 741"); + break; + case PCI_DEVICE_ID_SI_760: + ivideo->chip = SIS_760; + strcpy(ivideo->myid, "SiS 760"); + break; + case PCI_DEVICE_ID_SI_761: + ivideo->chip = SIS_761; + strcpy(ivideo->myid, "SiS 761"); + break; +#endif + default: + break; + } + } + + ivideo->SiS_Pr.ChipType = ivideo->chip; + + ivideo->SiS_Pr.ivideo = (void *)ivideo; + +#ifdef CONFIG_FB_SIS_315 + if((ivideo->SiS_Pr.ChipType == SIS_315PRO) || + (ivideo->SiS_Pr.ChipType == SIS_315)) { + ivideo->SiS_Pr.ChipType = SIS_315H; + } +#endif + + if(!ivideo->sisvga_enabled) { + if(pci_enable_device(pdev)) { + if(ivideo->nbridge) pci_dev_put(ivideo->nbridge); + framebuffer_release(sis_fb_info); + return -EIO; + } + } + + ivideo->video_base = pci_resource_start(pdev, 0); + ivideo->video_size = pci_resource_len(pdev, 0); + ivideo->mmio_base = pci_resource_start(pdev, 1); + ivideo->mmio_size = pci_resource_len(pdev, 1); + ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30; + ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO; + + SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress); + +#ifdef CONFIG_FB_SIS_300 + /* Find PCI systems for Chrontel/GPIO communication setup */ + if(ivideo->chip == SIS_630) { + i = 0; + do { + if(mychswtable[i].subsysVendor == ivideo->subsysvendor && + mychswtable[i].subsysCard == ivideo->subsysdevice) { + ivideo->SiS_Pr.SiS_ChSW = true; + printk(KERN_DEBUG "sisfb: Identified [%s %s] " + "requiring Chrontel/GPIO setup\n", + mychswtable[i].vendorName, + mychswtable[i].cardName); + ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL); + break; + } + i++; + } while(mychswtable[i].subsysVendor != 0); + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if((ivideo->chip == SIS_760) && (ivideo->nbridge)) { + ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3)); + } +#endif + + SiS_SetReg(SISSR, 0x05, 0x86); + + if( (!ivideo->sisvga_enabled) +#if !defined(__i386__) && !defined(__x86_64__) + || (sisfb_resetcard) +#endif + ) { + for(i = 0x30; i <= 0x3f; i++) { + SiS_SetReg(SISCR, i, 0x00); + } + } + + /* Find out about current video mode */ + ivideo->modeprechange = 0x03; + reg = SiS_GetReg(SISCR, 0x34); + if(reg & 0x7f) { + ivideo->modeprechange = reg & 0x7f; + } else if(ivideo->sisvga_enabled) { +#if defined(__i386__) || defined(__x86_64__) + unsigned char __iomem *tt = ioremap(0x400, 0x100); + if(tt) { + ivideo->modeprechange = readb(tt + 0x49); + iounmap(tt); + } +#endif + } + + /* Search and copy ROM image */ + ivideo->bios_abase = NULL; + ivideo->SiS_Pr.VirtualRomBase = NULL; + ivideo->SiS_Pr.UseROM = false; + ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false; + if(ivideo->sisfb_userom) { + ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev); + ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase; + ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase); + printk(KERN_INFO "sisfb: Video ROM %sfound\n", + ivideo->SiS_Pr.UseROM ? "" : "not "); + if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) { + ivideo->SiS_Pr.UseROM = false; + ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true; + if( (ivideo->revision_id == 2) && + (!(ivideo->bios_abase[0x1d1] & 0x01)) ) { + ivideo->SiS_Pr.DDCPortMixup = true; + } + } + } else { + printk(KERN_INFO "sisfb: Video ROM usage disabled\n"); + } + + /* Find systems for special custom timing */ + if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) { + sisfb_detect_custom_timing(ivideo); + } + +#ifdef CONFIG_FB_SIS_315 + if (ivideo->chip == XGI_20) { + /* Check if our Z7 chip is actually Z9 */ + SiS_SetRegOR(SISCR, 0x4a, 0x40); /* GPIOG EN */ + reg = SiS_GetReg(SISCR, 0x48); + if (reg & 0x02) { /* GPIOG */ + ivideo->chip_real_id = XGI_21; + dev_info(&pdev->dev, "Z9 detected\n"); + } + } +#endif + + /* POST card in case this has not been done by the BIOS */ + if( (!ivideo->sisvga_enabled) +#if !defined(__i386__) && !defined(__x86_64__) + || (sisfb_resetcard) +#endif + ) { +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->chip == SIS_300) { + sisfb_post_sis300(pdev); + ivideo->sisfb_can_post = 1; + } + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + int result = 1; + /* if((ivideo->chip == SIS_315H) || + (ivideo->chip == SIS_315) || + (ivideo->chip == SIS_315PRO) || + (ivideo->chip == SIS_330)) { + sisfb_post_sis315330(pdev); + } else */ if(ivideo->chip == XGI_20) { + result = sisfb_post_xgi(pdev); + ivideo->sisfb_can_post = 1; + } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) { + result = sisfb_post_xgi(pdev); + ivideo->sisfb_can_post = 1; + } else { + printk(KERN_INFO "sisfb: Card is not " + "POSTed and sisfb can't do this either.\n"); + } + if(!result) { + printk(KERN_ERR "sisfb: Failed to POST card\n"); + ret = -ENODEV; + goto error_3; + } + } +#endif + } + + ivideo->sisfb_card_posted = 1; + + /* Find out about RAM size */ + if(sisfb_get_dram_size(ivideo)) { + printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n"); + ret = -ENODEV; + goto error_3; + } + + + /* Enable PCI addressing and MMIO */ + if((ivideo->sisfb_mode_idx < 0) || + ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) { + /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */ + SiS_SetRegOR(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE)); + /* Enable 2D accelerator engine */ + SiS_SetRegOR(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D); + } + + if(sisfb_pdc != 0xff) { + if(ivideo->sisvga_engine == SIS_300_VGA) + sisfb_pdc &= 0x3c; + else + sisfb_pdc &= 0x1f; + ivideo->SiS_Pr.PDC = sisfb_pdc; + } +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + if(sisfb_pdca != 0xff) + ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f; + } +#endif + + if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) { + printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n", + (int)(ivideo->video_size >> 20)); + printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n"); + ret = -ENODEV; + goto error_3; + } + + if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) { + printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n"); + ret = -ENODEV; + goto error_2; + } + + ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size); + ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase; + if(!ivideo->video_vbase) { + printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n"); + ret = -ENODEV; + goto error_1; + } + + ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size); + if(!ivideo->mmio_vbase) { + printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n"); + ret = -ENODEV; +error_0: iounmap(ivideo->video_vbase); +error_1: release_mem_region(ivideo->video_base, ivideo->video_size); +error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size); +error_3: vfree(ivideo->bios_abase); + if(ivideo->lpcdev) + pci_dev_put(ivideo->lpcdev); + if(ivideo->nbridge) + pci_dev_put(ivideo->nbridge); + if(!ivideo->sisvga_enabled) + pci_disable_device(pdev); + framebuffer_release(sis_fb_info); + return ret; + } + + printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n", + ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024); + + if(ivideo->video_offset) { + printk(KERN_INFO "sisfb: Viewport offset %ldk\n", + ivideo->video_offset / 1024); + } + + printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n", + ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024); + + + /* Determine the size of the command queue */ + if(ivideo->sisvga_engine == SIS_300_VGA) { + ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE; + } else { + if(ivideo->chip == XGI_20) { + ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7; + } else { + ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE; + } + } + + /* Engines are no longer initialized here; this is + * now done after the first mode-switch (if the + * submitted var has its acceleration flags set). + */ + + /* Calculate the base of the (unused) hw cursor */ + ivideo->hwcursor_vbase = ivideo->video_vbase + + ivideo->video_size + - ivideo->cmdQueueSize + - ivideo->hwcursor_size; + ivideo->caps |= HW_CURSOR_CAP; + + /* Initialize offscreen memory manager */ + if((ivideo->havenoheap = sisfb_heap_init(ivideo))) { + printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n"); + } + + /* Used for clearing the screen only, therefore respect our mem limit */ + ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset; + ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem; + + ivideo->mtrr = -1; + + ivideo->vbflags = 0; + ivideo->lcddefmodeidx = DEFAULT_LCDMODE; + ivideo->tvdefmodeidx = DEFAULT_TVMODE; + ivideo->defmodeidx = DEFAULT_MODE; + + ivideo->newrom = 0; + if(ivideo->chip < XGI_20) { + if(ivideo->bios_abase) { + ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr); + } + } + + if((ivideo->sisfb_mode_idx < 0) || + ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) { + + sisfb_sense_crt1(ivideo); + + sisfb_get_VB_type(ivideo); + + if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) { + sisfb_detect_VB_connect(ivideo); + } + + ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD); + + /* Decide on which CRT2 device to use */ + if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) { + if(ivideo->sisfb_crt2type != -1) { + if((ivideo->sisfb_crt2type == CRT2_LCD) && + (ivideo->vbflags & CRT2_LCD)) { + ivideo->currentvbflags |= CRT2_LCD; + } else if(ivideo->sisfb_crt2type != CRT2_LCD) { + ivideo->currentvbflags |= ivideo->sisfb_crt2type; + } + } else { + /* Chrontel 700x TV detection often unreliable, therefore + * use a different default order on such machines + */ + if((ivideo->sisvga_engine == SIS_300_VGA) && + (ivideo->vbflags2 & VB2_CHRONTEL)) { + if(ivideo->vbflags & CRT2_LCD) + ivideo->currentvbflags |= CRT2_LCD; + else if(ivideo->vbflags & CRT2_TV) + ivideo->currentvbflags |= CRT2_TV; + else if(ivideo->vbflags & CRT2_VGA) + ivideo->currentvbflags |= CRT2_VGA; + } else { + if(ivideo->vbflags & CRT2_TV) + ivideo->currentvbflags |= CRT2_TV; + else if(ivideo->vbflags & CRT2_LCD) + ivideo->currentvbflags |= CRT2_LCD; + else if(ivideo->vbflags & CRT2_VGA) + ivideo->currentvbflags |= CRT2_VGA; + } + } + } + + if(ivideo->vbflags & CRT2_LCD) { + sisfb_detect_lcd_type(ivideo); + } + + sisfb_save_pdc_emi(ivideo); + + if(!ivideo->sisfb_crt1off) { + sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0); + } else { + if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) && + (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) { + sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1); + } + } + + if(ivideo->sisfb_mode_idx >= 0) { + int bu = ivideo->sisfb_mode_idx; + ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo, + ivideo->sisfb_mode_idx, ivideo->currentvbflags); + if(bu != ivideo->sisfb_mode_idx) { + printk(KERN_ERR "Mode %dx%dx%d failed validation\n", + sisbios_mode[bu].xres, + sisbios_mode[bu].yres, + sisbios_mode[bu].bpp); + } + } + + if(ivideo->sisfb_mode_idx < 0) { + switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + case CRT2_LCD: + ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx; + break; + case CRT2_TV: + ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx; + break; + default: + ivideo->sisfb_mode_idx = ivideo->defmodeidx; + break; + } + } + + ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]; + + if(ivideo->refresh_rate != 0) { + sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, + ivideo->sisfb_mode_idx); + } + + if(ivideo->rate_idx == 0) { + ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx; + ivideo->refresh_rate = 60; + } + + if(ivideo->sisfb_thismonitor.datavalid) { + if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, + ivideo->sisfb_mode_idx, + ivideo->rate_idx, + ivideo->refresh_rate)) { + printk(KERN_INFO "sisfb: WARNING: Refresh rate " + "exceeds monitor specs!\n"); + } + } + + ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp; + ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres; + ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres; + + sisfb_set_vparms(ivideo); + + printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n", + ivideo->video_width, ivideo->video_height, ivideo->video_bpp, + ivideo->refresh_rate); + + /* Set up the default var according to chosen default display mode */ + ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width; + ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height; + ivideo->default_var.bits_per_pixel = ivideo->video_bpp; + + sisfb_bpp_to_var(ivideo, &ivideo->default_var); + + ivideo->default_var.pixclock = (u32) (1000000000 / + sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx)); + + if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no, + ivideo->rate_idx, &ivideo->default_var)) { + if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + ivideo->default_var.pixclock <<= 1; + } + } + + if(ivideo->sisfb_ypan) { + /* Maximize regardless of sisfb_max at startup */ + ivideo->default_var.yres_virtual = + sisfb_calc_maxyres(ivideo, &ivideo->default_var); + if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) { + ivideo->default_var.yres_virtual = ivideo->default_var.yres; + } + } + + sisfb_calc_pitch(ivideo, &ivideo->default_var); + + ivideo->accel = 0; + if(ivideo->sisfb_accel) { + ivideo->accel = -1; +#ifdef STUPID_ACCELF_TEXT_SHIT + ivideo->default_var.accel_flags |= FB_ACCELF_TEXT; +#endif + } + sisfb_initaccel(ivideo); + +#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN) + sis_fb_info->flags = FBINFO_DEFAULT | + FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_XPAN | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT | + ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED); +#else + sis_fb_info->flags = FBINFO_FLAG_DEFAULT; +#endif + sis_fb_info->var = ivideo->default_var; + sis_fb_info->fix = ivideo->sisfb_fix; + sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset; + sis_fb_info->fbops = &sisfb_ops; + sis_fb_info->pseudo_palette = ivideo->pseudo_palette; + + fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0); + + printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags); + +#ifdef CONFIG_MTRR + ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size, + MTRR_TYPE_WRCOMB, 1); + if(ivideo->mtrr < 0) { + printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n"); + } +#endif + + if(register_framebuffer(sis_fb_info) < 0) { + printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n"); + ret = -EINVAL; + iounmap(ivideo->mmio_vbase); + goto error_0; + } + + ivideo->registered = 1; + + /* Enlist us */ + ivideo->next = card_list; + card_list = ivideo; + + printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n", + ivideo->sisfb_accel ? "enabled" : "disabled", + ivideo->sisfb_ypan ? + (ivideo->sisfb_max ? "enabled (auto-max)" : + "enabled (no auto-max)") : + "disabled"); + + + fb_info(sis_fb_info, "%s frame buffer device version %d.%d.%d\n", + ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL); + + printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n"); + + } /* if mode = "none" */ + + return 0; +} + +/*****************************************************/ +/* PCI DEVICE HANDLING */ +/*****************************************************/ + +static void sisfb_remove(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + struct fb_info *sis_fb_info = ivideo->memyselfandi; + int registered = ivideo->registered; + int modechanged = ivideo->modechanged; + + /* Unmap */ + iounmap(ivideo->mmio_vbase); + iounmap(ivideo->video_vbase); + + /* Release mem regions */ + release_mem_region(ivideo->video_base, ivideo->video_size); + release_mem_region(ivideo->mmio_base, ivideo->mmio_size); + + vfree(ivideo->bios_abase); + + if(ivideo->lpcdev) + pci_dev_put(ivideo->lpcdev); + + if(ivideo->nbridge) + pci_dev_put(ivideo->nbridge); + +#ifdef CONFIG_MTRR + /* Release MTRR region */ + if(ivideo->mtrr >= 0) + mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size); +#endif + + /* If device was disabled when starting, disable + * it when quitting. + */ + if(!ivideo->sisvga_enabled) + pci_disable_device(pdev); + + /* Unregister the framebuffer */ + if(ivideo->registered) { + unregister_framebuffer(sis_fb_info); + framebuffer_release(sis_fb_info); + } + + /* OK, our ivideo is gone for good from here. */ + + /* TODO: Restore the initial mode + * This sounds easy but is as good as impossible + * on many machines with SiS chip and video bridge + * since text modes are always set up differently + * from machine to machine. Depends on the type + * of integration between chipset and bridge. + */ + if(registered && modechanged) + printk(KERN_INFO + "sisfb: Restoring of text mode not supported yet\n"); +}; + +static struct pci_driver sisfb_driver = { + .name = "sisfb", + .id_table = sisfb_pci_table, + .probe = sisfb_probe, + .remove = sisfb_remove, +}; + +static int __init sisfb_init(void) +{ +#ifndef MODULE + char *options = NULL; + + if(fb_get_options("sisfb", &options)) + return -ENODEV; + + sisfb_setup(options); +#endif + return pci_register_driver(&sisfb_driver); +} + +#ifndef MODULE +module_init(sisfb_init); +#endif + +/*****************************************************/ +/* MODULE */ +/*****************************************************/ + +#ifdef MODULE + +static char *mode = NULL; +static int vesa = -1; +static unsigned int rate = 0; +static unsigned int crt1off = 1; +static unsigned int mem = 0; +static char *forcecrt2type = NULL; +static int forcecrt1 = -1; +static int pdc = -1; +static int pdc1 = -1; +static int noaccel = -1; +static int noypan = -1; +static int nomax = -1; +static int userom = -1; +static int useoem = -1; +static char *tvstandard = NULL; +static int nocrt2rate = 0; +static int scalelcd = -1; +static char *specialtiming = NULL; +static int lvdshl = -1; +static int tvxposoffset = 0, tvyposoffset = 0; +#if !defined(__i386__) && !defined(__x86_64__) +static int resetcard = 0; +static int videoram = 0; +#endif + +static int __init sisfb_init_module(void) +{ + sisfb_setdefaultparms(); + + if(rate) + sisfb_parm_rate = rate; + + if((scalelcd == 0) || (scalelcd == 1)) + sisfb_scalelcd = scalelcd ^ 1; + + /* Need to check crt2 type first for fstn/dstn */ + + if(forcecrt2type) + sisfb_search_crt2type(forcecrt2type); + + if(tvstandard) + sisfb_search_tvstd(tvstandard); + + if(mode) + sisfb_search_mode(mode, false); + else if(vesa != -1) + sisfb_search_vesamode(vesa, false); + + sisfb_crt1off = (crt1off == 0) ? 1 : 0; + + sisfb_forcecrt1 = forcecrt1; + if(forcecrt1 == 1) + sisfb_crt1off = 0; + else if(forcecrt1 == 0) + sisfb_crt1off = 1; + + if(noaccel == 1) + sisfb_accel = 0; + else if(noaccel == 0) + sisfb_accel = 1; + + if(noypan == 1) + sisfb_ypan = 0; + else if(noypan == 0) + sisfb_ypan = 1; + + if(nomax == 1) + sisfb_max = 0; + else if(nomax == 0) + sisfb_max = 1; + + if(mem) + sisfb_parm_mem = mem; + + if(userom != -1) + sisfb_userom = userom; + + if(useoem != -1) + sisfb_useoem = useoem; + + if(pdc != -1) + sisfb_pdc = (pdc & 0x7f); + + if(pdc1 != -1) + sisfb_pdca = (pdc1 & 0x1f); + + sisfb_nocrt2rate = nocrt2rate; + + if(specialtiming) + sisfb_search_specialtiming(specialtiming); + + if((lvdshl >= 0) && (lvdshl <= 3)) + sisfb_lvdshl = lvdshl; + + sisfb_tvxposoffset = tvxposoffset; + sisfb_tvyposoffset = tvyposoffset; + +#if !defined(__i386__) && !defined(__x86_64__) + sisfb_resetcard = (resetcard) ? 1 : 0; + if(videoram) + sisfb_videoram = videoram; +#endif + + return sisfb_init(); +} + +static void __exit sisfb_remove_module(void) +{ + pci_unregister_driver(&sisfb_driver); + printk(KERN_DEBUG "sisfb: Module unloaded\n"); +} + +module_init(sisfb_init_module); +module_exit(sisfb_remove_module); + +MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others"); + +module_param(mem, int, 0); +module_param(noaccel, int, 0); +module_param(noypan, int, 0); +module_param(nomax, int, 0); +module_param(userom, int, 0); +module_param(useoem, int, 0); +module_param(mode, charp, 0); +module_param(vesa, int, 0); +module_param(rate, int, 0); +module_param(forcecrt1, int, 0); +module_param(forcecrt2type, charp, 0); +module_param(scalelcd, int, 0); +module_param(pdc, int, 0); +module_param(pdc1, int, 0); +module_param(specialtiming, charp, 0); +module_param(lvdshl, int, 0); +module_param(tvstandard, charp, 0); +module_param(tvxposoffset, int, 0); +module_param(tvyposoffset, int, 0); +module_param(nocrt2rate, int, 0); +#if !defined(__i386__) && !defined(__x86_64__) +module_param(resetcard, int, 0); +module_param(videoram, int, 0); +#endif + +MODULE_PARM_DESC(mem, + "\nDetermines the beginning of the video memory heap in KB. This heap is used\n" + "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n" + "on the amount of video RAM available. If 8MB of video RAM or less is available,\n" + "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n" + "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n" + "The value is to be specified without 'KB'.\n"); + +MODULE_PARM_DESC(noaccel, + "\nIf set to anything other than 0, 2D acceleration will be disabled.\n" + "(default: 0)\n"); + +MODULE_PARM_DESC(noypan, + "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n" + "will be performed by redrawing the screen. (default: 0)\n"); + +MODULE_PARM_DESC(nomax, + "\nIf y-panning is enabled, sisfb will by default use the entire available video\n" + "memory for the virtual screen in order to optimize scrolling performance. If\n" + "this is set to anything other than 0, sisfb will not do this and thereby \n" + "enable the user to positively specify a virtual Y size of the screen using\n" + "fbset. (default: 0)\n"); + +MODULE_PARM_DESC(mode, + "\nSelects the desired default display mode in the format XxYxDepth,\n" + "eg. 1024x768x16. Other formats supported include XxY-Depth and\n" + "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n" + "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n"); + +MODULE_PARM_DESC(vesa, + "\nSelects the desired default display mode by VESA defined mode number, eg.\n" + "0x117 (default: 0x0103)\n"); + +MODULE_PARM_DESC(rate, + "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n" + "If the mode is specified in the format XxY-Depth@Rate, this parameter\n" + "will be ignored (default: 60)\n"); + +MODULE_PARM_DESC(forcecrt1, + "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n" + "connected. With this option, the detection can be overridden (1=CRT1 ON,\n" + "0=CRT1 OFF) (default: [autodetected])\n"); + +MODULE_PARM_DESC(forcecrt2type, + "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n" + "LCD, TV or secondary VGA. With this option, this autodetection can be\n" + "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n" + "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n" + "be used instead of TV to override the TV detection. Furthermore, on systems\n" + "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n" + "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n" + "depends on the very hardware in use. (default: [autodetected])\n"); + +MODULE_PARM_DESC(scalelcd, + "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n" + "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n" + "show black bars around the image, TMDS panels will probably do the scaling\n" + "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n"); + +MODULE_PARM_DESC(pdc, + "\nThis is for manually selecting the LCD panel delay compensation. The driver\n" + "should detect this correctly in most cases; however, sometimes this is not\n" + "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n" + "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n" + "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n" + "value from 0 to 31). (default: autodetected, if LCD is active during start)\n"); + +#ifdef CONFIG_FB_SIS_315 +MODULE_PARM_DESC(pdc1, + "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n" + "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n" + "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n" + "implemented yet.\n"); +#endif + +MODULE_PARM_DESC(specialtiming, + "\nPlease refer to documentation for more information on this option.\n"); + +MODULE_PARM_DESC(lvdshl, + "\nPlease refer to documentation for more information on this option.\n"); + +MODULE_PARM_DESC(tvstandard, + "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n" + "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n"); + +MODULE_PARM_DESC(tvxposoffset, + "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n" + "Default: 0\n"); + +MODULE_PARM_DESC(tvyposoffset, + "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n" + "Default: 0\n"); + +MODULE_PARM_DESC(nocrt2rate, + "\nSetting this to 1 will force the driver to use the default refresh rate for\n" + "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n"); + +#if !defined(__i386__) && !defined(__x86_64__) +#ifdef CONFIG_FB_SIS_300 +MODULE_PARM_DESC(resetcard, + "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n" + "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n" + "currently). Default: 0\n"); + +MODULE_PARM_DESC(videoram, + "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n" + "some non-x86 architectures where the memory auto detection fails. Only\n" + "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n"); +#endif +#endif + +#endif /* /MODULE */ + +/* _GPL only for new symbols. */ +EXPORT_SYMBOL(sis_malloc); +EXPORT_SYMBOL(sis_free); +EXPORT_SYMBOL_GPL(sis_malloc_new); +EXPORT_SYMBOL_GPL(sis_free_new); + + + diff --git a/drivers/video/fbdev/sis/sis_main.h b/drivers/video/fbdev/sis/sis_main.h new file mode 100644 index 0000000..32e23c2 --- /dev/null +++ b/drivers/video/fbdev/sis/sis_main.h @@ -0,0 +1,781 @@ +/* + * SiS 300/305/540/630(S)/730(S), + * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX], + * XGI V3XT/V5/V8, Z7 + * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3 + * + * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the named License, + * or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _SISFB_MAIN +#define _SISFB_MAIN + +#include "vstruct.h" +#include "sis.h" + +/* Fbcon stuff */ +static struct fb_var_screeninfo my_default_var = { + .xres = 0, + .yres = 0, + .xres_virtual = 0, + .yres_virtual = 0, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 0, + .grayscale = 0, + .red = {0, 8, 0}, + .green = {0, 8, 0}, + .blue = {0, 8, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 0, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, +}; + +#define MODE_INDEX_NONE 0 /* index for mode=none */ + +/* Boot-time parameters */ +static int sisfb_off = 0; +static int sisfb_parm_mem = 0; +static int sisfb_accel = -1; +static int sisfb_ypan = -1; +static int sisfb_max = -1; +static int sisfb_userom = 1; +static int sisfb_useoem = -1; +static int sisfb_mode_idx = -1; /* Use a default mode if we are inside the kernel */ +static int sisfb_parm_rate = -1; +static int sisfb_crt1off = 0; +static int sisfb_forcecrt1 = -1; +static int sisfb_crt2type = -1; /* CRT2 type (for overriding autodetection) */ +static int sisfb_crt2flags = 0; +static int sisfb_pdc = 0xff; +static int sisfb_pdca = 0xff; +static int sisfb_scalelcd = -1; +static int sisfb_specialtiming = CUT_NONE; +static int sisfb_lvdshl = -1; +static int sisfb_dstn = 0; +static int sisfb_fstn = 0; +static int sisfb_tvplug = -1; /* Tv plug type (for overriding autodetection) */ +static int sisfb_tvstd = -1; +static int sisfb_tvxposoffset = 0; +static int sisfb_tvyposoffset = 0; +static int sisfb_nocrt2rate = 0; +#if !defined(__i386__) && !defined(__x86_64__) +static int sisfb_resetcard = 0; +static int sisfb_videoram = 0; +#endif + +/* List of supported chips */ +static struct sisfb_chip_info { + int chip; + int vgaengine; + int mni; + int hwcursor_size; + int CRT2_write_enable; + const char *chip_name; +} sisfb_chip_info[] = { + { SIS_300, SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 300/305" }, + { SIS_540, SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 540" }, + { SIS_630, SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 630" }, + { SIS_315H, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315H" }, + { SIS_315, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315" }, + { SIS_315PRO, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315PRO" }, + { SIS_550, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 55x" }, + { SIS_650, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 650" }, + { SIS_330, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 330" }, + { SIS_660, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 660" }, + { XGI_20, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "XGI Z7" }, + { XGI_40, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "XGI V3XT/V5/V8" }, +}; + +static struct pci_device_id sisfb_pci_table[] = { +#ifdef CONFIG_FB_SIS_300 + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, +#endif +#ifdef CONFIG_FB_SIS_315 + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, + { PCI_VENDOR_ID_XGI,PCI_DEVICE_ID_XGI_20, PCI_ANY_ID, PCI_ANY_ID, 0, 0,10}, + { PCI_VENDOR_ID_XGI,PCI_DEVICE_ID_XGI_40, PCI_ANY_ID, PCI_ANY_ID, 0, 0,11}, +#endif + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, sisfb_pci_table); + +static struct sis_video_info *card_list = NULL; + +/* The memory heap is now handled card-wise, by using + sis_malloc_new/sis_free_new. However, the DRM does + not do this yet. Until it does, we keep a "global" + heap which is actually the first card's one. + */ +static struct SIS_HEAP *sisfb_heap; + +#define MD_SIS300 1 +#define MD_SIS315 2 + +/* Mode table */ +static const struct _sisbios_mode { + char name[15]; + u8 mode_no[2]; + u16 vesa_mode_no_1; /* "SiS defined" VESA mode number */ + u16 vesa_mode_no_2; /* Real VESA mode numbers */ + u16 xres; + u16 yres; + u16 bpp; + u16 rate_idx; + u16 cols; + u16 rows; + u8 chipset; +} sisbios_mode[] = { +/*0*/ {"none", {0xff,0xff}, 0x0000, 0x0000, 0, 0, 0, 0, 0, 0, MD_SIS300|MD_SIS315}, + {"320x200x8", {0x59,0x59}, 0x0138, 0x0000, 320, 200, 8, 1, 40, 12, MD_SIS300|MD_SIS315}, + {"320x200x16", {0x41,0x41}, 0x010e, 0x0000, 320, 200, 16, 1, 40, 12, MD_SIS300|MD_SIS315}, + {"320x200x24", {0x4f,0x4f}, 0x0000, 0x0000, 320, 200, 32, 1, 40, 12, MD_SIS300|MD_SIS315}, /* That's for people who mix up color- and fb depth */ + {"320x200x32", {0x4f,0x4f}, 0x0000, 0x0000, 320, 200, 32, 1, 40, 12, MD_SIS300|MD_SIS315}, + {"320x240x8", {0x50,0x50}, 0x0132, 0x0000, 320, 240, 8, 1, 40, 15, MD_SIS300|MD_SIS315}, + {"320x240x16", {0x56,0x56}, 0x0135, 0x0000, 320, 240, 16, 1, 40, 15, MD_SIS300|MD_SIS315}, + {"320x240x24", {0x53,0x53}, 0x0000, 0x0000, 320, 240, 32, 1, 40, 15, MD_SIS300|MD_SIS315}, + {"320x240x32", {0x53,0x53}, 0x0000, 0x0000, 320, 240, 32, 1, 40, 15, MD_SIS300|MD_SIS315}, +#define MODE_FSTN_8 9 +#define MODE_FSTN_16 10 + {"320x240x8", {0x5a,0x5a}, 0x0132, 0x0000, 320, 240, 8, 1, 40, 15, MD_SIS315}, /* FSTN */ +/*10*/ {"320x240x16", {0x5b,0x5b}, 0x0135, 0x0000, 320, 240, 16, 1, 40, 15, MD_SIS315}, /* FSTN */ + {"400x300x8", {0x51,0x51}, 0x0133, 0x0000, 400, 300, 8, 1, 50, 18, MD_SIS300|MD_SIS315}, + {"400x300x16", {0x57,0x57}, 0x0136, 0x0000, 400, 300, 16, 1, 50, 18, MD_SIS300|MD_SIS315}, + {"400x300x24", {0x54,0x54}, 0x0000, 0x0000, 400, 300, 32, 1, 50, 18, MD_SIS300|MD_SIS315}, + {"400x300x32", {0x54,0x54}, 0x0000, 0x0000, 400, 300, 32, 1, 50, 18, MD_SIS300|MD_SIS315}, + {"512x384x8", {0x52,0x52}, 0x0000, 0x0000, 512, 384, 8, 1, 64, 24, MD_SIS300|MD_SIS315}, + {"512x384x16", {0x58,0x58}, 0x0000, 0x0000, 512, 384, 16, 1, 64, 24, MD_SIS300|MD_SIS315}, + {"512x384x24", {0x5c,0x5c}, 0x0000, 0x0000, 512, 384, 32, 1, 64, 24, MD_SIS300|MD_SIS315}, + {"512x384x32", {0x5c,0x5c}, 0x0000, 0x0000, 512, 384, 32, 1, 64, 24, MD_SIS300|MD_SIS315}, + {"640x400x8", {0x2f,0x2f}, 0x0000, 0x0000, 640, 400, 8, 1, 80, 25, MD_SIS300|MD_SIS315}, +/*20*/ {"640x400x16", {0x5d,0x5d}, 0x0000, 0x0000, 640, 400, 16, 1, 80, 25, MD_SIS300|MD_SIS315}, + {"640x400x24", {0x5e,0x5e}, 0x0000, 0x0000, 640, 400, 32, 1, 80, 25, MD_SIS300|MD_SIS315}, + {"640x400x32", {0x5e,0x5e}, 0x0000, 0x0000, 640, 400, 32, 1, 80, 25, MD_SIS300|MD_SIS315}, + {"640x480x8", {0x2e,0x2e}, 0x0101, 0x0101, 640, 480, 8, 1, 80, 30, MD_SIS300|MD_SIS315}, + {"640x480x16", {0x44,0x44}, 0x0111, 0x0111, 640, 480, 16, 1, 80, 30, MD_SIS300|MD_SIS315}, + {"640x480x24", {0x62,0x62}, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, MD_SIS300|MD_SIS315}, + {"640x480x32", {0x62,0x62}, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, MD_SIS300|MD_SIS315}, + {"720x480x8", {0x31,0x31}, 0x0000, 0x0000, 720, 480, 8, 1, 90, 30, MD_SIS300|MD_SIS315}, + {"720x480x16", {0x33,0x33}, 0x0000, 0x0000, 720, 480, 16, 1, 90, 30, MD_SIS300|MD_SIS315}, + {"720x480x24", {0x35,0x35}, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, MD_SIS300|MD_SIS315}, +/*30*/ {"720x480x32", {0x35,0x35}, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, MD_SIS300|MD_SIS315}, + {"720x576x8", {0x32,0x32}, 0x0000, 0x0000, 720, 576, 8, 1, 90, 36, MD_SIS300|MD_SIS315}, + {"720x576x16", {0x34,0x34}, 0x0000, 0x0000, 720, 576, 16, 1, 90, 36, MD_SIS300|MD_SIS315}, + {"720x576x24", {0x36,0x36}, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, MD_SIS300|MD_SIS315}, + {"720x576x32", {0x36,0x36}, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, MD_SIS300|MD_SIS315}, + {"768x576x8", {0x5f,0x5f}, 0x0000, 0x0000, 768, 576, 8, 1, 96, 36, MD_SIS300|MD_SIS315}, + {"768x576x16", {0x60,0x60}, 0x0000, 0x0000, 768, 576, 16, 1, 96, 36, MD_SIS300|MD_SIS315}, + {"768x576x24", {0x61,0x61}, 0x0000, 0x0000, 768, 576, 32, 1, 96, 36, MD_SIS300|MD_SIS315}, + {"768x576x32", {0x61,0x61}, 0x0000, 0x0000, 768, 576, 32, 1, 96, 36, MD_SIS300|MD_SIS315}, + {"800x480x8", {0x70,0x70}, 0x0000, 0x0000, 800, 480, 8, 1, 100, 30, MD_SIS300|MD_SIS315}, +/*40*/ {"800x480x16", {0x7a,0x7a}, 0x0000, 0x0000, 800, 480, 16, 1, 100, 30, MD_SIS300|MD_SIS315}, + {"800x480x24", {0x76,0x76}, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_SIS300|MD_SIS315}, + {"800x480x32", {0x76,0x76}, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_SIS300|MD_SIS315}, +#define DEFAULT_MODE 43 /* index for 800x600x8 */ +#define DEFAULT_LCDMODE 43 /* index for 800x600x8 */ +#define DEFAULT_TVMODE 43 /* index for 800x600x8 */ + {"800x600x8", {0x30,0x30}, 0x0103, 0x0103, 800, 600, 8, 2, 100, 37, MD_SIS300|MD_SIS315}, + {"800x600x16", {0x47,0x47}, 0x0114, 0x0114, 800, 600, 16, 2, 100, 37, MD_SIS300|MD_SIS315}, + {"800x600x24", {0x63,0x63}, 0x013b, 0x0115, 800, 600, 32, 2, 100, 37, MD_SIS300|MD_SIS315}, + {"800x600x32", {0x63,0x63}, 0x013b, 0x0115, 800, 600, 32, 2, 100, 37, MD_SIS300|MD_SIS315}, + {"848x480x8", {0x39,0x39}, 0x0000, 0x0000, 848, 480, 8, 2, 106, 30, MD_SIS300|MD_SIS315}, +#define DEFAULT_MODE_848 48 + {"848x480x16", {0x3b,0x3b}, 0x0000, 0x0000, 848, 480, 16, 2, 106, 30, MD_SIS300|MD_SIS315}, + {"848x480x24", {0x3e,0x3e}, 0x0000, 0x0000, 848, 480, 32, 2, 106, 30, MD_SIS300|MD_SIS315}, +/*50*/ {"848x480x32", {0x3e,0x3e}, 0x0000, 0x0000, 848, 480, 32, 2, 106, 30, MD_SIS300|MD_SIS315}, + {"856x480x8", {0x3f,0x3f}, 0x0000, 0x0000, 856, 480, 8, 2, 107, 30, MD_SIS300|MD_SIS315}, +#define DEFAULT_MODE_856 52 + {"856x480x16", {0x42,0x42}, 0x0000, 0x0000, 856, 480, 16, 2, 107, 30, MD_SIS300|MD_SIS315}, + {"856x480x24", {0x45,0x45}, 0x0000, 0x0000, 856, 480, 32, 2, 107, 30, MD_SIS300|MD_SIS315}, + {"856x480x32", {0x45,0x45}, 0x0000, 0x0000, 856, 480, 32, 2, 107, 30, MD_SIS300|MD_SIS315}, + {"960x540x8", {0x1d,0x1d}, 0x0000, 0x0000, 960, 540, 8, 1, 120, 33, MD_SIS315}, + {"960x540x16", {0x1e,0x1e}, 0x0000, 0x0000, 960, 540, 16, 1, 120, 33, MD_SIS315}, + {"960x540x24", {0x1f,0x1f}, 0x0000, 0x0000, 960, 540, 32, 1, 120, 33, MD_SIS315}, + {"960x540x32", {0x1f,0x1f}, 0x0000, 0x0000, 960, 540, 32, 1, 120, 33, MD_SIS315}, + {"960x600x8", {0x20,0x20}, 0x0000, 0x0000, 960, 600, 8, 1, 120, 37, MD_SIS315}, +/*60*/ {"960x600x16", {0x21,0x21}, 0x0000, 0x0000, 960, 600, 16, 1, 120, 37, MD_SIS315}, + {"960x600x24", {0x22,0x22}, 0x0000, 0x0000, 960, 600, 32, 1, 120, 37, MD_SIS315}, + {"960x600x32", {0x22,0x22}, 0x0000, 0x0000, 960, 600, 32, 1, 120, 37, MD_SIS315}, + {"1024x576x8", {0x71,0x71}, 0x0000, 0x0000, 1024, 576, 8, 1, 128, 36, MD_SIS300|MD_SIS315}, + {"1024x576x16", {0x74,0x74}, 0x0000, 0x0000, 1024, 576, 16, 1, 128, 36, MD_SIS300|MD_SIS315}, + {"1024x576x24", {0x77,0x77}, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, MD_SIS300|MD_SIS315}, + {"1024x576x32", {0x77,0x77}, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, MD_SIS300|MD_SIS315}, + {"1024x600x8", {0x20,0x20}, 0x0000, 0x0000, 1024, 600, 8, 1, 128, 37, MD_SIS300 }, + {"1024x600x16", {0x21,0x21}, 0x0000, 0x0000, 1024, 600, 16, 1, 128, 37, MD_SIS300 }, + {"1024x600x24", {0x22,0x22}, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, MD_SIS300 }, +/*70*/ {"1024x600x32", {0x22,0x22}, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, MD_SIS300 }, + {"1024x768x8", {0x38,0x38}, 0x0105, 0x0105, 1024, 768, 8, 2, 128, 48, MD_SIS300|MD_SIS315}, + {"1024x768x16", {0x4a,0x4a}, 0x0117, 0x0117, 1024, 768, 16, 2, 128, 48, MD_SIS300|MD_SIS315}, + {"1024x768x24", {0x64,0x64}, 0x013c, 0x0118, 1024, 768, 32, 2, 128, 48, MD_SIS300|MD_SIS315}, + {"1024x768x32", {0x64,0x64}, 0x013c, 0x0118, 1024, 768, 32, 2, 128, 48, MD_SIS300|MD_SIS315}, + {"1152x768x8", {0x23,0x23}, 0x0000, 0x0000, 1152, 768, 8, 1, 144, 48, MD_SIS300 }, + {"1152x768x16", {0x24,0x24}, 0x0000, 0x0000, 1152, 768, 16, 1, 144, 48, MD_SIS300 }, + {"1152x768x24", {0x25,0x25}, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, MD_SIS300 }, + {"1152x768x32", {0x25,0x25}, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, MD_SIS300 }, + {"1152x864x8", {0x29,0x29}, 0x0000, 0x0000, 1152, 864, 8, 1, 144, 54, MD_SIS300|MD_SIS315}, +/*80*/ {"1152x864x16", {0x2a,0x2a}, 0x0000, 0x0000, 1152, 864, 16, 1, 144, 54, MD_SIS300|MD_SIS315}, + {"1152x864x24", {0x2b,0x2b}, 0x0000, 0x0000, 1152, 864, 32, 1, 144, 54, MD_SIS300|MD_SIS315}, + {"1152x864x32", {0x2b,0x2b}, 0x0000, 0x0000, 1152, 864, 32, 1, 144, 54, MD_SIS300|MD_SIS315}, + {"1280x720x8", {0x79,0x79}, 0x0000, 0x0000, 1280, 720, 8, 1, 160, 45, MD_SIS300|MD_SIS315}, + {"1280x720x16", {0x75,0x75}, 0x0000, 0x0000, 1280, 720, 16, 1, 160, 45, MD_SIS300|MD_SIS315}, + {"1280x720x24", {0x78,0x78}, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, MD_SIS300|MD_SIS315}, + {"1280x720x32", {0x78,0x78}, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, MD_SIS300|MD_SIS315}, + {"1280x768x8", {0x55,0x23}, 0x0000, 0x0000, 1280, 768, 8, 1, 160, 48, MD_SIS300|MD_SIS315}, + {"1280x768x16", {0x5a,0x24}, 0x0000, 0x0000, 1280, 768, 16, 1, 160, 48, MD_SIS300|MD_SIS315}, + {"1280x768x24", {0x5b,0x25}, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_SIS300|MD_SIS315}, +/*90*/ {"1280x768x32", {0x5b,0x25}, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_SIS300|MD_SIS315}, + {"1280x800x8", {0x14,0x14}, 0x0000, 0x0000, 1280, 800, 8, 1, 160, 50, MD_SIS315}, + {"1280x800x16", {0x15,0x15}, 0x0000, 0x0000, 1280, 800, 16, 1, 160, 50, MD_SIS315}, + {"1280x800x24", {0x16,0x16}, 0x0000, 0x0000, 1280, 800, 32, 1, 160, 50, MD_SIS315}, + {"1280x800x32", {0x16,0x16}, 0x0000, 0x0000, 1280, 800, 32, 1, 160, 50, MD_SIS315}, + {"1280x854x8", {0x14,0x14}, 0x0000, 0x0000, 1280, 854, 8, 1, 160, 53, MD_SIS315}, + {"1280x854x16", {0x15,0x15}, 0x0000, 0x0000, 1280, 854, 16, 1, 160, 53, MD_SIS315}, + {"1280x854x24", {0x16,0x16}, 0x0000, 0x0000, 1280, 854, 32, 1, 160, 53, MD_SIS315}, + {"1280x854x32", {0x16,0x16}, 0x0000, 0x0000, 1280, 854, 32, 1, 160, 53, MD_SIS315}, + {"1280x960x8", {0x7c,0x7c}, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60, MD_SIS300|MD_SIS315}, +/*100*/ {"1280x960x16", {0x7d,0x7d}, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60, MD_SIS300|MD_SIS315}, + {"1280x960x24", {0x7e,0x7e}, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_SIS300|MD_SIS315}, + {"1280x960x32", {0x7e,0x7e}, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_SIS300|MD_SIS315}, + {"1280x1024x8", {0x3a,0x3a}, 0x0107, 0x0107, 1280, 1024, 8, 2, 160, 64, MD_SIS300|MD_SIS315}, + {"1280x1024x16", {0x4d,0x4d}, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315}, + {"1280x1024x24", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315}, + {"1280x1024x32", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315}, + {"1360x768x8", {0x48,0x48}, 0x0000, 0x0000, 1360, 768, 8, 1, 170, 48, MD_SIS300|MD_SIS315}, + {"1360x768x16", {0x4b,0x4b}, 0x0000, 0x0000, 1360, 768, 16, 1, 170, 48, MD_SIS300|MD_SIS315}, + {"1360x768x24", {0x4e,0x4e}, 0x0000, 0x0000, 1360, 768, 32, 1, 170, 48, MD_SIS300|MD_SIS315}, +/*110*/ {"1360x768x32", {0x4e,0x4e}, 0x0000, 0x0000, 1360, 768, 32, 1, 170, 48, MD_SIS300|MD_SIS315}, + {"1360x1024x8", {0x67,0x67}, 0x0000, 0x0000, 1360, 1024, 8, 1, 170, 64, MD_SIS300 }, +#define DEFAULT_MODE_1360 112 + {"1360x1024x16", {0x6f,0x6f}, 0x0000, 0x0000, 1360, 1024, 16, 1, 170, 64, MD_SIS300 }, + {"1360x1024x24", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300 }, + {"1360x1024x32", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300 }, + {"1400x1050x8", {0x26,0x26}, 0x0000, 0x0000, 1400, 1050, 8, 1, 175, 65, MD_SIS315}, + {"1400x1050x16", {0x27,0x27}, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65, MD_SIS315}, + {"1400x1050x24", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_SIS315}, + {"1400x1050x32", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_SIS315}, + {"1600x1200x8", {0x3c,0x3c}, 0x0130, 0x011c, 1600, 1200, 8, 1, 200, 75, MD_SIS300|MD_SIS315}, +/*120*/ {"1600x1200x16", {0x3d,0x3d}, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315}, + {"1600x1200x24", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315}, + {"1600x1200x32", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315}, + {"1680x1050x8", {0x17,0x17}, 0x0000, 0x0000, 1680, 1050, 8, 1, 210, 65, MD_SIS315}, + {"1680x1050x16", {0x18,0x18}, 0x0000, 0x0000, 1680, 1050, 16, 1, 210, 65, MD_SIS315}, + {"1680x1050x24", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65, MD_SIS315}, + {"1680x1050x32", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65, MD_SIS315}, + {"1920x1080x8", {0x2c,0x2c}, 0x0000, 0x0000, 1920, 1080, 8, 1, 240, 67, MD_SIS315}, + {"1920x1080x16", {0x2d,0x2d}, 0x0000, 0x0000, 1920, 1080, 16, 1, 240, 67, MD_SIS315}, + {"1920x1080x24", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67, MD_SIS315}, +/*130*/ {"1920x1080x32", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67, MD_SIS315}, + {"1920x1440x8", {0x68,0x68}, 0x013f, 0x0000, 1920, 1440, 8, 1, 240, 75, MD_SIS300|MD_SIS315}, + {"1920x1440x16", {0x69,0x69}, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315}, + {"1920x1440x24", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315}, + {"1920x1440x32", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315}, + {"2048x1536x8", {0x6c,0x6c}, 0x0000, 0x0000, 2048, 1536, 8, 1, 256, 96, MD_SIS315}, + {"2048x1536x16", {0x6d,0x6d}, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96, MD_SIS315}, + {"2048x1536x24", {0x6e,0x6e}, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, MD_SIS315}, + {"2048x1536x32", {0x6e,0x6e}, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, MD_SIS315}, + {"\0", {0x00,0x00}, 0, 0, 0, 0, 0, 0, 0} +}; + +#define SIS_LCD_NUMBER 18 +static struct _sis_lcd_data { + u32 lcdtype; + u16 xres; + u16 yres; + u8 default_mode_idx; +} sis_lcd_data[] = { + { LCD_640x480, 640, 480, 23 }, + { LCD_800x600, 800, 600, 43 }, + { LCD_1024x600, 1024, 600, 67 }, + { LCD_1024x768, 1024, 768, 71 }, + { LCD_1152x768, 1152, 768, 75 }, + { LCD_1152x864, 1152, 864, 79 }, + { LCD_1280x720, 1280, 720, 83 }, + { LCD_1280x768, 1280, 768, 87 }, + { LCD_1280x800, 1280, 800, 91 }, + { LCD_1280x854, 1280, 854, 95 }, + { LCD_1280x960, 1280, 960, 99 }, + { LCD_1280x1024, 1280, 1024, 103 }, + { LCD_1400x1050, 1400, 1050, 115 }, + { LCD_1680x1050, 1680, 1050, 123 }, + { LCD_1600x1200, 1600, 1200, 119 }, + { LCD_320x240_2, 320, 240, 9 }, + { LCD_320x240_3, 320, 240, 9 }, + { LCD_320x240, 320, 240, 9 }, +}; + +/* CR36 evaluation */ +static unsigned short sis300paneltype[] = { + LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768, + LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, + LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN +}; + +static unsigned short sis310paneltype[] = { + LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, + LCD_1152x768, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, + LCD_320x240_2, LCD_320x240_3, LCD_UNKNOWN, LCD_UNKNOWN +}; + +static unsigned short sis661paneltype[] = { + LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, + LCD_1280x854, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, + LCD_1280x800, LCD_1680x1050, LCD_1280x720, LCD_UNKNOWN +}; + +#define FL_550_DSTN 0x01 +#define FL_550_FSTN 0x02 +#define FL_300 0x04 +#define FL_315 0x08 + +static struct _sis_crt2type { + char name[32]; + u32 type_no; + u32 tvplug_no; + u16 flags; +} sis_crt2type[] __initdata = { + {"NONE", 0, -1, FL_300|FL_315}, + {"LCD", CRT2_LCD, -1, FL_300|FL_315}, + {"TV", CRT2_TV, -1, FL_300|FL_315}, + {"VGA", CRT2_VGA, -1, FL_300|FL_315}, + {"SVIDEO", CRT2_TV, TV_SVIDEO, FL_300|FL_315}, + {"COMPOSITE", CRT2_TV, TV_AVIDEO, FL_300|FL_315}, + {"CVBS", CRT2_TV, TV_AVIDEO, FL_300|FL_315}, + {"SVIDEO+COMPOSITE", CRT2_TV, TV_AVIDEO|TV_SVIDEO, FL_300|FL_315}, + {"COMPOSITE+SVIDEO", CRT2_TV, TV_AVIDEO|TV_SVIDEO, FL_300|FL_315}, + {"SVIDEO+CVBS", CRT2_TV, TV_AVIDEO|TV_SVIDEO, FL_300|FL_315}, + {"CVBS+SVIDEO", CRT2_TV, TV_AVIDEO|TV_SVIDEO, FL_300|FL_315}, + {"SCART", CRT2_TV, TV_SCART, FL_300|FL_315}, + {"HIVISION", CRT2_TV, TV_HIVISION, FL_315}, + {"YPBPR480I", CRT2_TV, TV_YPBPR|TV_YPBPR525I, FL_315}, + {"YPBPR480P", CRT2_TV, TV_YPBPR|TV_YPBPR525P, FL_315}, + {"YPBPR720P", CRT2_TV, TV_YPBPR|TV_YPBPR750P, FL_315}, + {"YPBPR1080I", CRT2_TV, TV_YPBPR|TV_YPBPR1080I, FL_315}, + {"DSTN", CRT2_LCD, -1, FL_315|FL_550_DSTN}, + {"FSTN", CRT2_LCD, -1, FL_315|FL_550_FSTN}, + {"\0", -1, -1, 0} +}; + +/* TV standard */ +static struct _sis_tvtype { + char name[6]; + u32 type_no; +} sis_tvtype[] __initdata = { + {"PAL", TV_PAL}, + {"NTSC", TV_NTSC}, + {"PALM", TV_PAL|TV_PALM}, + {"PALN", TV_PAL|TV_PALN}, + {"NTSCJ", TV_NTSC|TV_NTSCJ}, + {"\0", -1} +}; + +static const struct _sis_vrate { + u16 idx; + u16 xres; + u16 yres; + u16 refresh; + bool SiS730valid32bpp; +} sisfb_vrate[] = { + {1, 320, 200, 70, true}, + {1, 320, 240, 60, true}, + {1, 400, 300, 60, true}, + {1, 512, 384, 60, true}, + {1, 640, 400, 72, true}, + {1, 640, 480, 60, true}, {2, 640, 480, 72, true}, {3, 640, 480, 75, true}, + {4, 640, 480, 85, true}, {5, 640, 480, 100, true}, {6, 640, 480, 120, true}, + {7, 640, 480, 160, true}, {8, 640, 480, 200, true}, + {1, 720, 480, 60, true}, + {1, 720, 576, 58, true}, + {1, 768, 576, 58, true}, + {1, 800, 480, 60, true}, {2, 800, 480, 75, true}, {3, 800, 480, 85, true}, + {1, 800, 600, 56, true}, {2, 800, 600, 60, true}, {3, 800, 600, 72, true}, + {4, 800, 600, 75, true}, {5, 800, 600, 85, true}, {6, 800, 600, 105, true}, + {7, 800, 600, 120, true}, {8, 800, 600, 160, true}, + {1, 848, 480, 39, true}, {2, 848, 480, 60, true}, + {1, 856, 480, 39, true}, {2, 856, 480, 60, true}, + {1, 960, 540, 60, true}, + {1, 960, 600, 60, true}, + {1, 1024, 576, 60, true}, {2, 1024, 576, 75, true}, {3, 1024, 576, 85, true}, + {1, 1024, 600, 60, true}, + {1, 1024, 768, 43, true}, {2, 1024, 768, 60, true}, {3, 1024, 768, 70, false}, + {4, 1024, 768, 75, false}, {5, 1024, 768, 85, true}, {6, 1024, 768, 100, true}, + {7, 1024, 768, 120, true}, + {1, 1152, 768, 60, true}, + {1, 1152, 864, 60, true}, {2, 1152, 864, 75, true}, {3, 1152, 864, 84, true}, + {1, 1280, 720, 60, true}, {2, 1280, 720, 75, true}, {3, 1280, 720, 85, true}, + {1, 1280, 768, 60, true}, + {1, 1280, 800, 60, true}, + {1, 1280, 854, 60, true}, + {1, 1280, 960, 60, true}, {2, 1280, 960, 85, true}, + {1, 1280, 1024, 43, true}, {2, 1280, 1024, 60, true}, {3, 1280, 1024, 75, true}, + {4, 1280, 1024, 85, true}, + {1, 1360, 768, 60, true}, + {1, 1360, 1024, 59, true}, + {1, 1400, 1050, 60, true}, {2, 1400, 1050, 75, true}, + {1, 1600, 1200, 60, true}, {2, 1600, 1200, 65, true}, {3, 1600, 1200, 70, true}, + {4, 1600, 1200, 75, true}, {5, 1600, 1200, 85, true}, {6, 1600, 1200, 100, true}, + {7, 1600, 1200, 120, true}, + {1, 1680, 1050, 60, true}, + {1, 1920, 1080, 30, true}, + {1, 1920, 1440, 60, true}, {2, 1920, 1440, 65, true}, {3, 1920, 1440, 70, true}, + {4, 1920, 1440, 75, true}, {5, 1920, 1440, 85, true}, {6, 1920, 1440, 100, true}, + {1, 2048, 1536, 60, true}, {2, 2048, 1536, 65, true}, {3, 2048, 1536, 70, true}, + {4, 2048, 1536, 75, true}, {5, 2048, 1536, 85, true}, + {0, 0, 0, 0, false} +}; + +static struct _sisfbddcsmodes { + u32 mask; + u16 h; + u16 v; + u32 d; +} sisfb_ddcsmodes[] = { + { 0x10000, 67, 75, 108000}, + { 0x08000, 48, 72, 50000}, + { 0x04000, 46, 75, 49500}, + { 0x01000, 35, 43, 44900}, + { 0x00800, 48, 60, 65000}, + { 0x00400, 56, 70, 75000}, + { 0x00200, 60, 75, 78800}, + { 0x00100, 80, 75, 135000}, + { 0x00020, 31, 60, 25200}, + { 0x00008, 38, 72, 31500}, + { 0x00004, 37, 75, 31500}, + { 0x00002, 35, 56, 36000}, + { 0x00001, 38, 60, 40000} +}; + +static struct _sisfbddcfmodes { + u16 x; + u16 y; + u16 v; + u16 h; + u32 d; +} sisfb_ddcfmodes[] = { + { 1280, 1024, 85, 92, 157500}, + { 1600, 1200, 60, 75, 162000}, + { 1600, 1200, 65, 82, 175500}, + { 1600, 1200, 70, 88, 189000}, + { 1600, 1200, 75, 94, 202500}, + { 1600, 1200, 85, 107,229500}, + { 1920, 1440, 60, 90, 234000}, + { 1920, 1440, 75, 113,297000} +}; + +#ifdef CONFIG_FB_SIS_300 +static struct _chswtable { + u16 subsysVendor; + u16 subsysCard; + char *vendorName; + char *cardName; +} mychswtable[] = { + { 0x1631, 0x1002, "Mitachi", "0x1002" }, + { 0x1071, 0x7521, "Mitac" , "7521P" }, + { 0, 0, "" , "" } +}; +#endif + +static struct _customttable { + u16 chipID; + char *biosversion; + char *biosdate; + u32 bioschksum; + u16 biosFootprintAddr[5]; + u8 biosFootprintData[5]; + u16 pcisubsysvendor; + u16 pcisubsyscard; + char *vendorName; + char *cardName; + u32 SpecialID; + char *optionName; +} mycustomttable[] = { + { SIS_630, "2.00.07", "09/27/2002-13:38:25", + 0x3240A8, + { 0x220, 0x227, 0x228, 0x229, 0x0ee }, + { 0x01, 0xe3, 0x9a, 0x6a, 0xef }, + 0x1039, 0x6300, + "Barco", "iQ R200L/300/400", CUT_BARCO1366, "BARCO_1366" + }, + { SIS_630, "2.00.07", "09/27/2002-13:38:25", + 0x323FBD, + { 0x220, 0x227, 0x228, 0x229, 0x0ee }, + { 0x00, 0x5a, 0x64, 0x41, 0xef }, + 0x1039, 0x6300, + "Barco", "iQ G200L/300/400/500", CUT_BARCO1024, "BARCO_1024" + }, + { SIS_650, "", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x0e11, 0x083c, + "Inventec (Compaq)", "3017cl/3045US", CUT_COMPAQ12802, "COMPAQ_1280" + }, + { SIS_650, "", "", + 0, + { 0x00c, 0, 0, 0, 0 }, + { 'e' , 0, 0, 0, 0 }, + 0x1558, 0x0287, + "Clevo", "L285/L287 (Version 1)", CUT_CLEVO1024, "CLEVO_L28X_1" + }, + { SIS_650, "", "", + 0, + { 0x00c, 0, 0, 0, 0 }, + { 'y' , 0, 0, 0, 0 }, + 0x1558, 0x0287, + "Clevo", "L285/L287 (Version 2)", CUT_CLEVO10242, "CLEVO_L28X_2" + }, + { SIS_650, "", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1558, 0x0400, /* possibly 401 and 402 as well; not panelsize specific (?) */ + "Clevo", "D400S/D410S/D400H/D410H", CUT_CLEVO1400, "CLEVO_D4X0" + }, + { SIS_650, "", "", + 0, /* Shift LCD in LCD-via-CRT1 mode */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1558, 0x2263, + "Clevo", "D22ES/D27ES", CUT_UNIWILL1024, "CLEVO_D2X0ES" + }, + { SIS_650, "", "", + 0, /* Shift LCD in LCD-via-CRT1 mode */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1734, 0x101f, + "Uniwill", "N243S9", CUT_UNIWILL1024, "UNIWILL_N243S9" + }, + { SIS_650, "", "", + 0, /* Shift LCD in LCD-via-CRT1 mode */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1584, 0x5103, + "Uniwill", "N35BS1", CUT_UNIWILL10242, "UNIWILL_N35BS1" + }, + { SIS_650, "1.09.2c", "", /* Other versions, too? */ + 0, /* Shift LCD in LCD-via-CRT1 mode */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1019, 0x0f05, + "ECS", "A928", CUT_UNIWILL1024, "ECS_A928" + }, + { SIS_740, "1.11.27a", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1043, 0x1612, + "Asus", "L3000D/L3500D", CUT_ASUSL3000D, "ASUS_L3X00" + }, + { SIS_650, "1.10.9k", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1025, 0x0028, + "Acer", "Aspire 1700", CUT_ACER1280, "ACER_ASPIRE1700" + }, + { SIS_650, "1.10.7w", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x14c0, 0x0012, + "Compal", "??? (V1)", CUT_COMPAL1400_1, "COMPAL_1400_1" + }, + { SIS_650, "1.10.7x", "", + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x14c0, 0x0012, + "Compal", "??? (V2)", CUT_COMPAL1400_2, "COMPAL_1400_2" + }, + { SIS_650, "1.10.8o", "", + 0, /* For EMI (unknown) */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1043, 0x1612, + "Asus", "A2H (V1)", CUT_ASUSA2H_1, "ASUS_A2H_1" + }, + { SIS_650, "1.10.8q", "", + 0, /* For EMI */ + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0x1043, 0x1612, + "Asus", "A2H (V2)", CUT_ASUSA2H_2, "ASUS_A2H_2" + }, + { 4321, "", "", /* never autodetected */ + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0, 0, + "Generic", "LVDS/Parallel 848x480", CUT_PANEL848, "PANEL848x480" + }, + { 4322, "", "", /* never autodetected */ + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0, 0, + "Generic", "LVDS/Parallel 856x480", CUT_PANEL856, "PANEL856x480" + }, + { 0, "", "", + 0, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + 0, 0, + "", "", CUT_NONE, "" + } +}; + +/* ---------------------- Prototypes ------------------------- */ + +/* Interface used by the world */ +#ifndef MODULE +static int sisfb_setup(char *options); +#endif + +/* Interface to the low level console driver */ +static int sisfb_init(void); + +/* fbdev routines */ +static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); + +static int sisfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); +static int sisfb_set_par(struct fb_info *info); +static int sisfb_blank(int blank, + struct fb_info *info); +extern void fbcon_sis_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +extern void fbcon_sis_copyarea(struct fb_info *info, + const struct fb_copyarea *area); +extern int fbcon_sis_sync(struct fb_info *info); + +/* Internal 2D accelerator functions */ +extern int sisfb_initaccel(struct sis_video_info *ivideo); +extern void sisfb_syncaccel(struct sis_video_info *ivideo); + +/* Internal general routines */ +static void sisfb_search_mode(char *name, bool quiet); +static int sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags); +static u8 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, + int index); +static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info); +static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info *info); +static void sisfb_pre_setmode(struct sis_video_info *ivideo); +static void sisfb_post_setmode(struct sis_video_info *ivideo); +static bool sisfb_CheckVBRetrace(struct sis_video_info *ivideo); +static bool sisfbcheckvretracecrt2(struct sis_video_info *ivideo); +static bool sisfbcheckvretracecrt1(struct sis_video_info *ivideo); +static bool sisfb_bridgeisslave(struct sis_video_info *ivideo); +static void sisfb_detect_VB_connect(struct sis_video_info *ivideo); +static void sisfb_get_VB_type(struct sis_video_info *ivideo); +static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val); +static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val); +#ifdef CONFIG_FB_SIS_300 +unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg); +void sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val); +unsigned int sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg); +#endif +#ifdef CONFIG_FB_SIS_315 +void sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val); +unsigned int sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg); +#endif + +/* SiS-specific exported functions */ +void sis_malloc(struct sis_memreq *req); +void sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req); +void sis_free(u32 base); +void sis_free_new(struct pci_dev *pdev, u32 base); + +/* Internal heap routines */ +static int sisfb_heap_init(struct sis_video_info *ivideo); +static struct SIS_OH * sisfb_poh_new_node(struct SIS_HEAP *memheap); +static struct SIS_OH * sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size); +static void sisfb_delete_node(struct SIS_OH *poh); +static void sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh); +static struct SIS_OH * sisfb_poh_free(struct SIS_HEAP *memheap, u32 base); +static void sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh); + +/* Routines from init.c/init301.c */ +extern unsigned short SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, bool FSTN, unsigned short CustomT, + int LCDwith, int LCDheight, unsigned int VBFlags2); +extern unsigned short SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, unsigned int VBFlags2); +extern unsigned short SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, unsigned int VBFlags2); +extern void SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); +extern bool SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +extern void SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable); +extern void SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable); + +extern bool SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr); + +extern bool sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, + int *htotal, int *vtotal, unsigned char rateindex); +extern int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, + unsigned char modeno, unsigned char rateindex); +extern int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, + unsigned char rateindex, struct fb_var_screeninfo *var); + +/* Chrontel TV, DDC and DPMS functions */ +extern unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg); +extern void SiS_SetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +extern unsigned short SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg); +extern void SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +extern void SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg, + unsigned char myor, unsigned char myand); +extern void SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime); +extern void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo); +extern unsigned short SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, + unsigned short adaptnum, unsigned short DDCdatatype, unsigned char *buffer, + unsigned int VBFlags2); +extern unsigned short SiS_ReadDDC1Bit(struct SiS_Private *SiS_Pr); +#ifdef CONFIG_FB_SIS_315 +extern void SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr); +extern void SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr); +#endif +extern void SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr); +extern void SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr); +#endif + + diff --git a/drivers/video/fbdev/sis/vgatypes.h b/drivers/video/fbdev/sis/vgatypes.h new file mode 100644 index 0000000..e3f9976 --- /dev/null +++ b/drivers/video/fbdev/sis/vgatypes.h @@ -0,0 +1,97 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * General type definitions for universal mode switching modules + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _VGATYPES_H_ +#define _VGATYPES_H_ + +#define SISIOMEMTYPE + +typedef unsigned long SISIOADDRESS; +#include <linux/types.h> /* Need __iomem */ +#undef SISIOMEMTYPE +#define SISIOMEMTYPE __iomem + +typedef enum _SIS_CHIP_TYPE { + SIS_VGALegacy = 0, + SIS_530, + SIS_OLD, + SIS_300, + SIS_630, + SIS_730, + SIS_540, + SIS_315H, /* SiS 310 */ + SIS_315, + SIS_315PRO, /* SiS 325 */ + SIS_550, + SIS_650, + SIS_740, + SIS_330, + SIS_661, + SIS_741, + SIS_670, + SIS_660 = 35, + SIS_760, + SIS_761, + SIS_762, + SIS_770, + SIS_340 = 55, + SIS_341, + SIS_342, + XGI_20 = 75, + XGI_21, + XGI_40, + MAX_SIS_CHIP +} SIS_CHIP_TYPE; + + +#endif + diff --git a/drivers/video/fbdev/sis/vstruct.h b/drivers/video/fbdev/sis/vstruct.h new file mode 100644 index 0000000..ea94d21 --- /dev/null +++ b/drivers/video/fbdev/sis/vstruct.h @@ -0,0 +1,551 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * General structure definitions for universal mode switching modules + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _VSTRUCT_H_ +#define _VSTRUCT_H_ + +struct SiS_PanelDelayTbl { + unsigned char timer[2]; +}; + +struct SiS_LCDData { + unsigned short RVBHCMAX; + unsigned short RVBHCFACT; + unsigned short VGAHT; + unsigned short VGAVT; + unsigned short LCDHT; + unsigned short LCDVT; +}; + +struct SiS_TVData { + unsigned short RVBHCMAX; + unsigned short RVBHCFACT; + unsigned short VGAHT; + unsigned short VGAVT; + unsigned short TVHDE; + unsigned short TVVDE; + unsigned short RVBHRS; + unsigned char FlickerMode; + unsigned short HALFRVBHRS; + unsigned short RVBHRS2; + unsigned char RY1COE; + unsigned char RY2COE; + unsigned char RY3COE; + unsigned char RY4COE; +}; + +struct SiS_LVDSData { + unsigned short VGAHT; + unsigned short VGAVT; + unsigned short LCDHT; + unsigned short LCDVT; +}; + +struct SiS_LVDSDes { + unsigned short LCDHDES; + unsigned short LCDVDES; +}; + +struct SiS_LVDSCRT1Data { + unsigned char CR[15]; +}; + +struct SiS_CHTVRegData { + unsigned char Reg[16]; +}; + +struct SiS_St { + unsigned char St_ModeID; + unsigned short St_ModeFlag; + unsigned char St_StTableIndex; + unsigned char St_CRT2CRTC; + unsigned char St_ResInfo; + unsigned char VB_StTVFlickerIndex; + unsigned char VB_StTVEdgeIndex; + unsigned char VB_StTVYFilterIndex; + unsigned char St_PDC; +}; + +struct SiS_VBMode { + unsigned char ModeID; + unsigned char VB_TVDelayIndex; + unsigned char VB_TVFlickerIndex; + unsigned char VB_TVPhaseIndex; + unsigned char VB_TVYFilterIndex; + unsigned char VB_LCDDelayIndex; + unsigned char _VB_LCDHIndex; + unsigned char _VB_LCDVIndex; +}; + +struct SiS_StandTable_S { + unsigned char CRT_COLS; + unsigned char ROWS; + unsigned char CHAR_HEIGHT; + unsigned short CRT_LEN; + unsigned char SR[4]; + unsigned char MISC; + unsigned char CRTC[0x19]; + unsigned char ATTR[0x14]; + unsigned char GRC[9]; +}; + +struct SiS_Ext { + unsigned char Ext_ModeID; + unsigned short Ext_ModeFlag; + unsigned short Ext_VESAID; + unsigned char Ext_RESINFO; + unsigned char VB_ExtTVFlickerIndex; + unsigned char VB_ExtTVEdgeIndex; + unsigned char VB_ExtTVYFilterIndex; + unsigned char VB_ExtTVYFilterIndexROM661; + unsigned char REFindex; + char ROMMODEIDX661; +}; + +struct SiS_Ext2 { + unsigned short Ext_InfoFlag; + unsigned char Ext_CRT1CRTC; + unsigned char Ext_CRTVCLK; + unsigned char Ext_CRT2CRTC; + unsigned char Ext_CRT2CRTC_NS; + unsigned char ModeID; + unsigned short XRes; + unsigned short YRes; + unsigned char Ext_PDC; + unsigned char Ext_FakeCRT2CRTC; + unsigned char Ext_FakeCRT2Clk; + unsigned char Ext_CRT1CRTC_NORM; + unsigned char Ext_CRTVCLK_NORM; + unsigned char Ext_CRT1CRTC_WIDE; + unsigned char Ext_CRTVCLK_WIDE; +}; + +struct SiS_Part2PortTbl { + unsigned char CR[12]; +}; + +struct SiS_CRT1Table { + unsigned char CR[17]; +}; + +struct SiS_MCLKData { + unsigned char SR28,SR29,SR2A; + unsigned short CLOCK; +}; + +struct SiS_VCLKData { + unsigned char SR2B,SR2C; + unsigned short CLOCK; +}; + +struct SiS_VBVCLKData { + unsigned char Part4_A,Part4_B; + unsigned short CLOCK; +}; + +struct SiS_StResInfo_S { + unsigned short HTotal; + unsigned short VTotal; +}; + +struct SiS_ModeResInfo_S { + unsigned short HTotal; + unsigned short VTotal; + unsigned char XChar; + unsigned char YChar; +}; + +/* Defines for SiS_CustomT */ +/* Never change these for sisfb compatibility */ +#define CUT_NONE 0 +#define CUT_FORCENONE 1 +#define CUT_BARCO1366 2 +#define CUT_BARCO1024 3 +#define CUT_COMPAQ1280 4 +#define CUT_COMPAQ12802 5 +#define CUT_PANEL848 6 +#define CUT_CLEVO1024 7 +#define CUT_CLEVO10242 8 +#define CUT_CLEVO1400 9 +#define CUT_CLEVO14002 10 +#define CUT_UNIWILL1024 11 +#define CUT_ASUSL3000D 12 +#define CUT_UNIWILL10242 13 +#define CUT_ACER1280 14 +#define CUT_COMPAL1400_1 15 +#define CUT_COMPAL1400_2 16 +#define CUT_ASUSA2H_1 17 +#define CUT_ASUSA2H_2 18 +#define CUT_UNKNOWNLCD 19 +#define CUT_AOP8060 20 +#define CUT_PANEL856 21 + +struct SiS_Private +{ + unsigned char ChipType; + unsigned char ChipRevision; + void *ivideo; + unsigned char *VirtualRomBase; + bool UseROM; + unsigned char SISIOMEMTYPE *VideoMemoryAddress; + unsigned int VideoMemorySize; + SISIOADDRESS IOAddress; + SISIOADDRESS IOAddress2; /* For dual chip XGI volari */ + + SISIOADDRESS RelIO; + SISIOADDRESS SiS_P3c4; + SISIOADDRESS SiS_P3d4; + SISIOADDRESS SiS_P3c0; + SISIOADDRESS SiS_P3ce; + SISIOADDRESS SiS_P3c2; + SISIOADDRESS SiS_P3ca; + SISIOADDRESS SiS_P3c6; + SISIOADDRESS SiS_P3c7; + SISIOADDRESS SiS_P3c8; + SISIOADDRESS SiS_P3c9; + SISIOADDRESS SiS_P3cb; + SISIOADDRESS SiS_P3cc; + SISIOADDRESS SiS_P3cd; + SISIOADDRESS SiS_P3da; + SISIOADDRESS SiS_Part1Port; + SISIOADDRESS SiS_Part2Port; + SISIOADDRESS SiS_Part3Port; + SISIOADDRESS SiS_Part4Port; + SISIOADDRESS SiS_Part5Port; + SISIOADDRESS SiS_VidCapt; + SISIOADDRESS SiS_VidPlay; + unsigned short SiS_IF_DEF_LVDS; + unsigned short SiS_IF_DEF_CH70xx; + unsigned short SiS_IF_DEF_CONEX; + unsigned short SiS_IF_DEF_TRUMPION; + unsigned short SiS_IF_DEF_DSTN; + unsigned short SiS_IF_DEF_FSTN; + unsigned short SiS_SysFlags; + unsigned char SiS_VGAINFO; + bool SiS_UseROM; + bool SiS_ROMNew; + bool SiS_XGIROM; + bool SiS_NeedRomModeData; + bool PanelSelfDetected; + bool DDCPortMixup; + int SiS_CHOverScan; + bool SiS_CHSOverScan; + bool SiS_ChSW; + bool SiS_UseLCDA; + int SiS_UseOEM; + unsigned int SiS_CustomT; + int SiS_UseWide, SiS_UseWideCRT2; + int SiS_TVBlue; + unsigned short SiS_Backup70xx; + bool HaveEMI; + bool HaveEMILCD; + bool OverruleEMI; + unsigned char EMI_30,EMI_31,EMI_32,EMI_33; + unsigned short SiS_EMIOffset; + unsigned short SiS_PWDOffset; + short PDC, PDCA; + unsigned char SiS_MyCR63; + unsigned short SiS_CRT1Mode; + unsigned short SiS_flag_clearbuffer; + int SiS_RAMType; + unsigned char SiS_ChannelAB; + unsigned char SiS_DataBusWidth; + unsigned short SiS_ModeType; + unsigned short SiS_VBInfo; + unsigned short SiS_TVMode; + unsigned short SiS_LCDResInfo; + unsigned short SiS_LCDTypeInfo; + unsigned short SiS_LCDInfo; + unsigned short SiS_LCDInfo661; + unsigned short SiS_VBType; + unsigned short SiS_VBExtInfo; + unsigned short SiS_YPbPr; + unsigned short SiS_SelectCRT2Rate; + unsigned short SiS_SetFlag; + unsigned short SiS_RVBHCFACT; + unsigned short SiS_RVBHCMAX; + unsigned short SiS_RVBHRS; + unsigned short SiS_RVBHRS2; + unsigned short SiS_VGAVT; + unsigned short SiS_VGAHT; + unsigned short SiS_VT; + unsigned short SiS_HT; + unsigned short SiS_VGAVDE; + unsigned short SiS_VGAHDE; + unsigned short SiS_VDE; + unsigned short SiS_HDE; + unsigned short SiS_NewFlickerMode; + unsigned short SiS_RY1COE; + unsigned short SiS_RY2COE; + unsigned short SiS_RY3COE; + unsigned short SiS_RY4COE; + unsigned short SiS_LCDHDES; + unsigned short SiS_LCDVDES; + SISIOADDRESS SiS_DDC_Port; + unsigned short SiS_DDC_Index; + unsigned short SiS_DDC_Data; + unsigned short SiS_DDC_NData; + unsigned short SiS_DDC_Clk; + unsigned short SiS_DDC_NClk; + unsigned short SiS_DDC_DeviceAddr; + unsigned short SiS_DDC_ReadAddr; + unsigned short SiS_DDC_SecAddr; + unsigned short SiS_ChrontelInit; + bool SiS_SensibleSR11; + unsigned short SiS661LCD2TableSize; + + unsigned short SiS_PanelMinLVDS; + unsigned short SiS_PanelMin301; + + const struct SiS_St *SiS_SModeIDTable; + const struct SiS_StandTable_S *SiS_StandTable; + const struct SiS_Ext *SiS_EModeIDTable; + const struct SiS_Ext2 *SiS_RefIndex; + const struct SiS_VBMode *SiS_VBModeIDTable; + const struct SiS_CRT1Table *SiS_CRT1Table; + const struct SiS_MCLKData *SiS_MCLKData_0; + const struct SiS_MCLKData *SiS_MCLKData_1; + struct SiS_VCLKData *SiS_VCLKData; + struct SiS_VBVCLKData *SiS_VBVCLKData; + const struct SiS_StResInfo_S *SiS_StResInfo; + const struct SiS_ModeResInfo_S *SiS_ModeResInfo; + + const unsigned char *pSiS_OutputSelect; + const unsigned char *pSiS_SoftSetting; + + const unsigned char *SiS_SR15; + + const struct SiS_PanelDelayTbl *SiS_PanelDelayTbl; + const struct SiS_PanelDelayTbl *SiS_PanelDelayTblLVDS; + + /* SiS bridge */ + + const struct SiS_LCDData *SiS_ExtLCD1024x768Data; + const struct SiS_LCDData *SiS_St2LCD1024x768Data; + const struct SiS_LCDData *SiS_LCD1280x720Data; + const struct SiS_LCDData *SiS_StLCD1280x768_2Data; + const struct SiS_LCDData *SiS_ExtLCD1280x768_2Data; + const struct SiS_LCDData *SiS_LCD1280x800Data; + const struct SiS_LCDData *SiS_LCD1280x800_2Data; + const struct SiS_LCDData *SiS_LCD1280x854Data; + const struct SiS_LCDData *SiS_LCD1280x960Data; + const struct SiS_LCDData *SiS_ExtLCD1280x1024Data; + const struct SiS_LCDData *SiS_St2LCD1280x1024Data; + const struct SiS_LCDData *SiS_StLCD1400x1050Data; + const struct SiS_LCDData *SiS_ExtLCD1400x1050Data; + const struct SiS_LCDData *SiS_StLCD1600x1200Data; + const struct SiS_LCDData *SiS_ExtLCD1600x1200Data; + const struct SiS_LCDData *SiS_LCD1680x1050Data; + const struct SiS_LCDData *SiS_NoScaleData; + const struct SiS_TVData *SiS_StPALData; + const struct SiS_TVData *SiS_ExtPALData; + const struct SiS_TVData *SiS_StNTSCData; + const struct SiS_TVData *SiS_ExtNTSCData; + const struct SiS_TVData *SiS_St1HiTVData; + const struct SiS_TVData *SiS_St2HiTVData; + const struct SiS_TVData *SiS_ExtHiTVData; + const struct SiS_TVData *SiS_St525iData; + const struct SiS_TVData *SiS_St525pData; + const struct SiS_TVData *SiS_St750pData; + const struct SiS_TVData *SiS_Ext525iData; + const struct SiS_TVData *SiS_Ext525pData; + const struct SiS_TVData *SiS_Ext750pData; + const unsigned char *SiS_NTSCTiming; + const unsigned char *SiS_PALTiming; + const unsigned char *SiS_HiTVExtTiming; + const unsigned char *SiS_HiTVSt1Timing; + const unsigned char *SiS_HiTVSt2Timing; + const unsigned char *SiS_HiTVGroup3Data; + const unsigned char *SiS_HiTVGroup3Simu; +#if 0 + const unsigned char *SiS_HiTVTextTiming; + const unsigned char *SiS_HiTVGroup3Text; +#endif + + const struct SiS_Part2PortTbl *SiS_CRT2Part2_1024x768_1; + const struct SiS_Part2PortTbl *SiS_CRT2Part2_1024x768_2; + const struct SiS_Part2PortTbl *SiS_CRT2Part2_1024x768_3; + + /* LVDS, Chrontel */ + + const struct SiS_LVDSData *SiS_LVDS320x240Data_1; + const struct SiS_LVDSData *SiS_LVDS320x240Data_2; + const struct SiS_LVDSData *SiS_LVDS640x480Data_1; + const struct SiS_LVDSData *SiS_LVDS800x600Data_1; + const struct SiS_LVDSData *SiS_LVDS1024x600Data_1; + const struct SiS_LVDSData *SiS_LVDS1024x768Data_1; + const struct SiS_LVDSData *SiS_LVDSBARCO1366Data_1; + const struct SiS_LVDSData *SiS_LVDSBARCO1366Data_2; + const struct SiS_LVDSData *SiS_LVDSBARCO1024Data_1; + const struct SiS_LVDSData *SiS_LVDS848x480Data_1; + const struct SiS_LVDSData *SiS_LVDS848x480Data_2; + const struct SiS_LVDSData *SiS_CHTVUNTSCData; + const struct SiS_LVDSData *SiS_CHTVONTSCData; + const struct SiS_LVDSData *SiS_CHTVUPALData; + const struct SiS_LVDSData *SiS_CHTVOPALData; + const struct SiS_LVDSData *SiS_CHTVUPALMData; + const struct SiS_LVDSData *SiS_CHTVOPALMData; + const struct SiS_LVDSData *SiS_CHTVUPALNData; + const struct SiS_LVDSData *SiS_CHTVOPALNData; + const struct SiS_LVDSData *SiS_CHTVSOPALData; + + const struct SiS_LVDSDes *SiS_PanelType04_1a; + const struct SiS_LVDSDes *SiS_PanelType04_2a; + const struct SiS_LVDSDes *SiS_PanelType04_1b; + const struct SiS_LVDSDes *SiS_PanelType04_2b; + + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_1; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_2; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_2_H; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_3; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_3_H; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1640x480_1; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1640x480_1_H; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1UNTSC; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1ONTSC; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1UPAL; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1OPAL; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1SOPAL; + + const struct SiS_CHTVRegData *SiS_CHTVReg_UNTSC; + const struct SiS_CHTVRegData *SiS_CHTVReg_ONTSC; + const struct SiS_CHTVRegData *SiS_CHTVReg_UPAL; + const struct SiS_CHTVRegData *SiS_CHTVReg_OPAL; + const struct SiS_CHTVRegData *SiS_CHTVReg_UPALM; + const struct SiS_CHTVRegData *SiS_CHTVReg_OPALM; + const struct SiS_CHTVRegData *SiS_CHTVReg_UPALN; + const struct SiS_CHTVRegData *SiS_CHTVReg_OPALN; + const struct SiS_CHTVRegData *SiS_CHTVReg_SOPAL; + + const unsigned char *SiS_CHTVVCLKUNTSC; + const unsigned char *SiS_CHTVVCLKONTSC; + const unsigned char *SiS_CHTVVCLKUPAL; + const unsigned char *SiS_CHTVVCLKOPAL; + const unsigned char *SiS_CHTVVCLKUPALM; + const unsigned char *SiS_CHTVVCLKOPALM; + const unsigned char *SiS_CHTVVCLKUPALN; + const unsigned char *SiS_CHTVVCLKOPALN; + const unsigned char *SiS_CHTVVCLKSOPAL; + + unsigned short PanelXRes, PanelHT; + unsigned short PanelYRes, PanelVT; + unsigned short PanelHRS, PanelHRE; + unsigned short PanelVRS, PanelVRE; + unsigned short PanelVCLKIdx300; + unsigned short PanelVCLKIdx315; + bool Alternate1600x1200; + + bool UseCustomMode; + bool CRT1UsesCustomMode; + unsigned short CHDisplay; + unsigned short CHSyncStart; + unsigned short CHSyncEnd; + unsigned short CHTotal; + unsigned short CHBlankStart; + unsigned short CHBlankEnd; + unsigned short CVDisplay; + unsigned short CVSyncStart; + unsigned short CVSyncEnd; + unsigned short CVTotal; + unsigned short CVBlankStart; + unsigned short CVBlankEnd; + unsigned int CDClock; + unsigned int CFlags; + unsigned char CCRT1CRTC[17]; + unsigned char CSR2B; + unsigned char CSR2C; + unsigned short CSRClock; + unsigned short CSRClock_CRT1; + unsigned short CModeFlag; + unsigned short CModeFlag_CRT1; + unsigned short CInfoFlag; + + int LVDSHL; + + bool Backup; + unsigned char Backup_Mode; + unsigned char Backup_14; + unsigned char Backup_15; + unsigned char Backup_16; + unsigned char Backup_17; + unsigned char Backup_18; + unsigned char Backup_19; + unsigned char Backup_1a; + unsigned char Backup_1b; + unsigned char Backup_1c; + unsigned char Backup_1d; + + unsigned char Init_P4_0E; + + int UsePanelScaler; + int CenterScreen; + + unsigned short CP_Vendor, CP_Product; + bool CP_HaveCustomData; + int CP_PreferredX, CP_PreferredY, CP_PreferredIndex; + int CP_MaxX, CP_MaxY, CP_MaxClock; + unsigned char CP_PrefSR2B, CP_PrefSR2C; + unsigned short CP_PrefClock; + bool CP_Supports64048075; + int CP_HDisplay[7], CP_VDisplay[7]; /* For Custom LCD panel dimensions */ + int CP_HTotal[7], CP_VTotal[7]; + int CP_HSyncStart[7], CP_VSyncStart[7]; + int CP_HSyncEnd[7], CP_VSyncEnd[7]; + int CP_HBlankStart[7], CP_VBlankStart[7]; + int CP_HBlankEnd[7], CP_VBlankEnd[7]; + int CP_Clock[7]; + bool CP_DataValid[7]; + bool CP_HSync_P[7], CP_VSync_P[7], CP_SyncValid[7]; +}; + +#endif + |