cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sisusb_init.c (25370B)


      1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
      2/*
      3 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
      4 *
      5 * Display mode initializing code
      6 *
      7 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
      8 *
      9 * If distributed as part of the Linux kernel, this code is licensed under the
     10 * terms of the GPL v2.
     11 *
     12 * Otherwise, the following license terms apply:
     13 *
     14 * * Redistribution and use in source and binary forms, with or without
     15 * * modification, are permitted provided that the following conditions
     16 * * are met:
     17 * * 1) Redistributions of source code must retain the above copyright
     18 * *    notice, this list of conditions and the following disclaimer.
     19 * * 2) Redistributions in binary form must reproduce the above copyright
     20 * *    notice, this list of conditions and the following disclaimer in the
     21 * *    documentation and/or other materials provided with the distribution.
     22 * * 3) The name of the author may not be used to endorse or promote products
     23 * *    derived from this software without specific prior written permission.
     24 * *
     25 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     26 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     27 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     28 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     29 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     30 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     31 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     32 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     33 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     34 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     35 *
     36 * Author:	Thomas Winischhofer <thomas@winischhofer.net>
     37 *
     38 */
     39
     40#include <linux/module.h>
     41#include <linux/kernel.h>
     42#include <linux/errno.h>
     43#include <linux/poll.h>
     44#include <linux/spinlock.h>
     45
     46#include "sisusb.h"
     47#include "sisusb_init.h"
     48#include "sisusb_tables.h"
     49
     50/*********************************************/
     51/*         POINTER INITIALIZATION            */
     52/*********************************************/
     53
     54static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
     55{
     56	SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
     57	SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
     58
     59	SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
     60	SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
     61	SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
     62	SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
     63
     64	SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
     65}
     66
     67/*********************************************/
     68/*          HELPER: SetReg, GetReg           */
     69/*********************************************/
     70
     71static void
     72SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
     73	   unsigned short index, unsigned short data)
     74{
     75	sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
     76}
     77
     78static void
     79SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
     80	       unsigned short data)
     81{
     82	sisusb_setreg(SiS_Pr->sisusb, port, data);
     83}
     84
     85static unsigned char
     86SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
     87{
     88	u8 data;
     89
     90	sisusb_getidxreg(SiS_Pr->sisusb, port, index, &data);
     91
     92	return data;
     93}
     94
     95static unsigned char
     96SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
     97{
     98	u8 data;
     99
    100	sisusb_getreg(SiS_Pr->sisusb, port, &data);
    101
    102	return data;
    103}
    104
    105static void
    106SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
    107		unsigned short index, unsigned short DataAND,
    108		unsigned short DataOR)
    109{
    110	sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
    111}
    112
    113static void
    114SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
    115	      unsigned short index, unsigned short DataAND)
    116{
    117	sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
    118}
    119
    120static void
    121SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
    122	     unsigned short index, unsigned short DataOR)
    123{
    124	sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
    125}
    126
    127/*********************************************/
    128/*      HELPER: DisplayOn, DisplayOff        */
    129/*********************************************/
    130
    131static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
    132{
    133	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
    134}
    135
    136/*********************************************/
    137/*        HELPER: Init Port Addresses        */
    138/*********************************************/
    139
    140static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
    141{
    142	SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
    143	SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
    144	SiS_Pr->SiS_P3c0 = BaseAddr + 0x10;
    145	SiS_Pr->SiS_P3ce = BaseAddr + 0x1e;
    146	SiS_Pr->SiS_P3c2 = BaseAddr + 0x12;
    147	SiS_Pr->SiS_P3ca = BaseAddr + 0x1a;
    148	SiS_Pr->SiS_P3c6 = BaseAddr + 0x16;
    149	SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
    150	SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
    151	SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
    152	SiS_Pr->SiS_P3cb = BaseAddr + 0x1b;
    153	SiS_Pr->SiS_P3cc = BaseAddr + 0x1c;
    154	SiS_Pr->SiS_P3cd = BaseAddr + 0x1d;
    155	SiS_Pr->SiS_P3da = BaseAddr + 0x2a;
    156	SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04;
    157}
    158
    159/*********************************************/
    160/*             HELPER: GetSysFlags           */
    161/*********************************************/
    162
    163static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
    164{
    165	SiS_Pr->SiS_MyCR63 = 0x63;
    166}
    167
    168/*********************************************/
    169/*         HELPER: Init PCI & Engines        */
    170/*********************************************/
    171
    172static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
    173{
    174	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
    175	/*  - Enable 2D (0x40)
    176	 *  - Enable 3D (0x02)
    177	 *  - Enable 3D vertex command fetch (0x10)
    178	 *  - Enable 3D command parser (0x08)
    179	 *  - Enable 3D G/L transformation engine (0x80)
    180	 */
    181	SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1E, 0xDA);
    182}
    183
    184/*********************************************/
    185/*        HELPER: SET SEGMENT REGISTERS      */
    186/*********************************************/
    187
    188static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
    189{
    190	unsigned short temp;
    191
    192	value &= 0x00ff;
    193	temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0xf0;
    194	temp |= (value >> 4);
    195	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
    196	temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0xf0;
    197	temp |= (value & 0x0f);
    198	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
    199}
    200
    201static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
    202{
    203	unsigned short temp;
    204
    205	value &= 0x00ff;
    206	temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0x0f;
    207	temp |= (value & 0xf0);
    208	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
    209	temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0x0f;
    210	temp |= (value << 4);
    211	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
    212}
    213
    214static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
    215{
    216	SiS_SetSegRegLower(SiS_Pr, value);
    217	SiS_SetSegRegUpper(SiS_Pr, value);
    218}
    219
    220static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
    221{
    222	SiS_SetSegmentReg(SiS_Pr, 0);
    223}
    224
    225static void
    226SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
    227{
    228	unsigned short temp = value >> 8;
    229
    230	temp &= 0x07;
    231	temp |= (temp << 4);
    232	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1d, temp);
    233	SiS_SetSegmentReg(SiS_Pr, value);
    234}
    235
    236static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
    237{
    238	SiS_SetSegmentRegOver(SiS_Pr, 0);
    239}
    240
    241static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
    242{
    243	SiS_ResetSegmentReg(SiS_Pr);
    244	SiS_ResetSegmentRegOver(SiS_Pr);
    245}
    246
    247/*********************************************/
    248/*           HELPER: SearchModeID            */
    249/*********************************************/
    250
    251static int
    252SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
    253		 unsigned short *ModeIdIndex)
    254{
    255	if ((*ModeNo) <= 0x13) {
    256
    257		if ((*ModeNo) != 0x03)
    258			return 0;
    259
    260		(*ModeIdIndex) = 0;
    261
    262	} else {
    263
    264		for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
    265
    266			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
    267			    (*ModeNo))
    268				break;
    269
    270			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
    271			    0xFF)
    272				return 0;
    273		}
    274
    275	}
    276
    277	return 1;
    278}
    279
    280/*********************************************/
    281/*            HELPER: ENABLE CRT1            */
    282/*********************************************/
    283
    284static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
    285{
    286	/* Enable CRT1 gating */
    287	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
    288}
    289
    290/*********************************************/
    291/*           HELPER: GetColorDepth           */
    292/*********************************************/
    293
    294static unsigned short
    295SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    296		  unsigned short ModeIdIndex)
    297{
    298	static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
    299	unsigned short modeflag;
    300	short index;
    301
    302	if (ModeNo <= 0x13) {
    303		modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
    304	} else {
    305		modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
    306	}
    307
    308	index = (modeflag & ModeTypeMask) - ModeEGA;
    309	if (index < 0)
    310		index = 0;
    311	return ColorDepth[index];
    312}
    313
    314/*********************************************/
    315/*             HELPER: GetOffset             */
    316/*********************************************/
    317
    318static unsigned short
    319SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    320	      unsigned short ModeIdIndex, unsigned short rrti)
    321{
    322	unsigned short xres, temp, colordepth, infoflag;
    323
    324	infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
    325	xres = SiS_Pr->SiS_RefIndex[rrti].XRes;
    326
    327	colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex);
    328
    329	temp = xres / 16;
    330
    331	if (infoflag & InterlaceMode)
    332		temp <<= 1;
    333
    334	temp *= colordepth;
    335
    336	if (xres % 16)
    337		temp += (colordepth >> 1);
    338
    339	return temp;
    340}
    341
    342/*********************************************/
    343/*                   SEQ                     */
    344/*********************************************/
    345
    346static void
    347SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
    348{
    349	unsigned char SRdata;
    350	int i;
    351
    352	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x00, 0x03);
    353
    354	SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
    355	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
    356
    357	for (i = 2; i <= 4; i++) {
    358		SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
    359		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
    360	}
    361}
    362
    363/*********************************************/
    364/*                  MISC                     */
    365/*********************************************/
    366
    367static void
    368SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
    369{
    370	unsigned char Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
    371
    372	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, Miscdata);
    373}
    374
    375/*********************************************/
    376/*                  CRTC                     */
    377/*********************************************/
    378
    379static void
    380SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
    381{
    382	unsigned char CRTCdata;
    383	unsigned short i;
    384
    385	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
    386
    387	for (i = 0; i <= 0x18; i++) {
    388		CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
    389		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
    390	}
    391}
    392
    393/*********************************************/
    394/*                   ATT                     */
    395/*********************************************/
    396
    397static void
    398SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
    399{
    400	unsigned char ARdata;
    401	unsigned short i;
    402
    403	for (i = 0; i <= 0x13; i++) {
    404		ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
    405		SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
    406		SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
    407		SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, ARdata);
    408	}
    409	SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
    410	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x14);
    411	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x00);
    412
    413	SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
    414	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x20);
    415	SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
    416}
    417
    418/*********************************************/
    419/*                   GRC                     */
    420/*********************************************/
    421
    422static void
    423SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
    424{
    425	unsigned char GRdata;
    426	unsigned short i;
    427
    428	for (i = 0; i <= 0x08; i++) {
    429		GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
    430		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
    431	}
    432
    433	if (SiS_Pr->SiS_ModeType > ModeVGA) {
    434		/* 256 color disable */
    435		SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3ce, 0x05, 0xBF);
    436	}
    437}
    438
    439/*********************************************/
    440/*          CLEAR EXTENDED REGISTERS         */
    441/*********************************************/
    442
    443static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
    444{
    445	int i;
    446
    447	for (i = 0x0A; i <= 0x0E; i++) {
    448		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
    449	}
    450
    451	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x37, 0xFE);
    452}
    453
    454/*********************************************/
    455/*              Get rate index               */
    456/*********************************************/
    457
    458static unsigned short
    459SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    460	       unsigned short ModeIdIndex)
    461{
    462	unsigned short rrti, i, index, temp;
    463
    464	if (ModeNo <= 0x13)
    465		return 0xFFFF;
    466
    467	index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
    468	if (index > 0)
    469		index--;
    470
    471	rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
    472	ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
    473
    474	i = 0;
    475	do {
    476		if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
    477			break;
    478
    479		temp =
    480		    SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
    481		if (temp < SiS_Pr->SiS_ModeType)
    482			break;
    483
    484		i++;
    485		index--;
    486	} while (index != 0xFFFF);
    487
    488	i--;
    489
    490	return (rrti + i);
    491}
    492
    493/*********************************************/
    494/*                  SYNC                     */
    495/*********************************************/
    496
    497static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
    498{
    499	unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
    500	sync &= 0xC0;
    501	sync |= 0x2f;
    502	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, sync);
    503}
    504
    505/*********************************************/
    506/*                  CRTC/2                   */
    507/*********************************************/
    508
    509static void
    510SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    511		unsigned short ModeIdIndex, unsigned short rrti)
    512{
    513	unsigned char index;
    514	unsigned short temp, i, j, modeflag;
    515
    516	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
    517
    518	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
    519
    520	index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
    521
    522	for (i = 0, j = 0; i <= 7; i++, j++) {
    523		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
    524			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
    525	}
    526	for (j = 0x10; i <= 10; i++, j++) {
    527		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
    528			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
    529	}
    530	for (j = 0x15; i <= 12; i++, j++) {
    531		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
    532			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
    533	}
    534	for (j = 0x0A; i <= 15; i++, j++) {
    535		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
    536			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
    537	}
    538
    539	temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
    540	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
    541
    542	temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
    543	if (modeflag & DoubleScanMode)
    544		temp |= 0x80;
    545	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
    546
    547	if (SiS_Pr->SiS_ModeType > ModeVGA)
    548		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x14, 0x4F);
    549}
    550
    551/*********************************************/
    552/*               OFFSET & PITCH              */
    553/*********************************************/
    554/*  (partly overruled by SetPitch() in XF86) */
    555/*********************************************/
    556
    557static void
    558SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    559		  unsigned short ModeIdIndex, unsigned short rrti)
    560{
    561	unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
    562	unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
    563	unsigned short temp;
    564
    565	temp = (du >> 8) & 0x0f;
    566	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, 0xF0, temp);
    567
    568	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
    569
    570	if (infoflag & InterlaceMode)
    571		du >>= 1;
    572
    573	du <<= 5;
    574	temp = (du >> 8) & 0xff;
    575	if (du & 0xff)
    576		temp++;
    577	temp++;
    578	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
    579}
    580
    581/*********************************************/
    582/*                  VCLK                     */
    583/*********************************************/
    584
    585static void
    586SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    587		unsigned short rrti)
    588{
    589	unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
    590	unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
    591	unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
    592
    593	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
    594
    595	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
    596	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
    597	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
    598}
    599
    600/*********************************************/
    601/*                  FIFO                     */
    602/*********************************************/
    603
    604static void
    605SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    606		    unsigned short mi)
    607{
    608	unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
    609
    610	/* disable auto-threshold */
    611	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0xFE);
    612
    613	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0xAE);
    614	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x09, 0xF0);
    615
    616	if (ModeNo <= 0x13)
    617		return;
    618
    619	if ((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
    620		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0x34);
    621		SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0x01);
    622	}
    623}
    624
    625/*********************************************/
    626/*              MODE REGISTERS               */
    627/*********************************************/
    628
    629static void
    630SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    631		 unsigned short rrti)
    632{
    633	unsigned short data = 0, VCLK = 0, index = 0;
    634
    635	if (ModeNo > 0x13) {
    636		index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
    637		VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
    638	}
    639
    640	if (VCLK >= 166)
    641		data |= 0x0c;
    642	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
    643
    644	if (VCLK >= 166)
    645		SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1f, 0xe7);
    646
    647	/* DAC speed */
    648	data = 0x03;
    649	if (VCLK >= 260)
    650		data = 0x00;
    651	else if (VCLK >= 160)
    652		data = 0x01;
    653	else if (VCLK >= 135)
    654		data = 0x02;
    655
    656	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x07, 0xF8, data);
    657}
    658
    659static void
    660SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    661		    unsigned short ModeIdIndex, unsigned short rrti)
    662{
    663	unsigned short data, infoflag = 0, modeflag;
    664
    665	if (ModeNo <= 0x13)
    666		modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
    667	else {
    668		modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
    669		infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
    670	}
    671
    672	/* Disable DPMS */
    673	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1F, 0x3F);
    674
    675	data = 0;
    676	if (ModeNo > 0x13) {
    677		if (SiS_Pr->SiS_ModeType > ModeEGA) {
    678			data |= 0x02;
    679			data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
    680		}
    681		if (infoflag & InterlaceMode)
    682			data |= 0x20;
    683	}
    684	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
    685
    686	data = 0;
    687	if (infoflag & InterlaceMode) {
    688		/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
    689		unsigned short hrs =
    690		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
    691		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
    692		    - 3;
    693		unsigned short hto =
    694		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
    695		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
    696		    + 5;
    697		data = hrs - (hto >> 1) + 3;
    698	}
    699	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
    700	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x1a, 0xFC, (data >> 8));
    701
    702	if (modeflag & HalfDCLK)
    703		SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0x08);
    704
    705	data = 0;
    706	if (modeflag & LineCompareOff)
    707		data = 0x08;
    708	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0xB7, data);
    709
    710	if ((SiS_Pr->SiS_ModeType == ModeEGA) && (ModeNo > 0x13))
    711		SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0x40);
    712
    713	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xfb);
    714
    715	data = 0x60;
    716	if (SiS_Pr->SiS_ModeType != ModeText) {
    717		data ^= 0x60;
    718		if (SiS_Pr->SiS_ModeType != ModeEGA)
    719			data ^= 0xA0;
    720	}
    721	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x21, 0x1F, data);
    722
    723	SiS_SetVCLKState(SiS_Pr, ModeNo, rrti);
    724
    725	if (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x31) & 0x40)
    726		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x2c);
    727	else
    728		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x6c);
    729}
    730
    731/*********************************************/
    732/*                 LOAD DAC                  */
    733/*********************************************/
    734
    735static void
    736SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
    737	     unsigned short shiftflag, unsigned short dl, unsigned short ah,
    738	     unsigned short al, unsigned short dh)
    739{
    740	unsigned short d1, d2, d3;
    741
    742	switch (dl) {
    743	case 0:
    744		d1 = dh;
    745		d2 = ah;
    746		d3 = al;
    747		break;
    748	case 1:
    749		d1 = ah;
    750		d2 = al;
    751		d3 = dh;
    752		break;
    753	default:
    754		d1 = al;
    755		d2 = dh;
    756		d3 = ah;
    757	}
    758	SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
    759	SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
    760	SiS_SetRegByte(SiS_Pr, DACData, (d3 << shiftflag));
    761}
    762
    763static void
    764SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    765	    unsigned short mi)
    766{
    767	unsigned short data, data2, time, i, j, k, m, n, o;
    768	unsigned short si, di, bx, sf;
    769	unsigned long DACAddr, DACData;
    770	const unsigned char *table = NULL;
    771
    772	if (ModeNo < 0x13)
    773		data = SiS_Pr->SiS_SModeIDTable[mi].St_ModeFlag;
    774	else
    775		data = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
    776
    777	data &= DACInfoFlag;
    778
    779	j = time = 64;
    780	if (data == 0x00)
    781		table = SiS_MDA_DAC;
    782	else if (data == 0x08)
    783		table = SiS_CGA_DAC;
    784	else if (data == 0x10)
    785		table = SiS_EGA_DAC;
    786	else {
    787		j = 16;
    788		time = 256;
    789		table = SiS_VGA_DAC;
    790	}
    791
    792	DACAddr = SiS_Pr->SiS_P3c8;
    793	DACData = SiS_Pr->SiS_P3c9;
    794	sf = 0;
    795	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
    796
    797	SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
    798
    799	for (i = 0; i < j; i++) {
    800		data = table[i];
    801		for (k = 0; k < 3; k++) {
    802			data2 = 0;
    803			if (data & 0x01)
    804				data2 += 0x2A;
    805			if (data & 0x02)
    806				data2 += 0x15;
    807			SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
    808			data >>= 2;
    809		}
    810	}
    811
    812	if (time == 256) {
    813		for (i = 16; i < 32; i++) {
    814			data = table[i] << sf;
    815			for (k = 0; k < 3; k++)
    816				SiS_SetRegByte(SiS_Pr, DACData, data);
    817		}
    818		si = 32;
    819		for (m = 0; m < 9; m++) {
    820			di = si;
    821			bx = si + 4;
    822			for (n = 0; n < 3; n++) {
    823				for (o = 0; o < 5; o++) {
    824					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
    825						     table[di], table[bx],
    826						     table[si]);
    827					si++;
    828				}
    829				si -= 2;
    830				for (o = 0; o < 3; o++) {
    831					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
    832						     table[di], table[si],
    833						     table[bx]);
    834					si--;
    835				}
    836			}
    837			si += 5;
    838		}
    839	}
    840}
    841
    842/*********************************************/
    843/*         SET CRT1 REGISTER GROUP           */
    844/*********************************************/
    845
    846static void
    847SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
    848		 unsigned short ModeIdIndex)
    849{
    850	unsigned short StandTableIndex, rrti;
    851
    852	SiS_Pr->SiS_CRT1Mode = ModeNo;
    853
    854	if (ModeNo <= 0x13)
    855		StandTableIndex = 0;
    856	else
    857		StandTableIndex = 1;
    858
    859	SiS_ResetSegmentRegisters(SiS_Pr);
    860	SiS_SetSeqRegs(SiS_Pr, StandTableIndex);
    861	SiS_SetMiscRegs(SiS_Pr, StandTableIndex);
    862	SiS_SetCRTCRegs(SiS_Pr, StandTableIndex);
    863	SiS_SetATTRegs(SiS_Pr, StandTableIndex);
    864	SiS_SetGRCRegs(SiS_Pr, StandTableIndex);
    865	SiS_ClearExt1Regs(SiS_Pr, ModeNo);
    866
    867	rrti = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex);
    868
    869	if (rrti != 0xFFFF) {
    870		SiS_SetCRT1Sync(SiS_Pr, rrti);
    871		SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, rrti);
    872		SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
    873		SiS_SetCRT1VCLK(SiS_Pr, ModeNo, rrti);
    874	}
    875
    876	SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex);
    877
    878	SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, rrti);
    879
    880	SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex);
    881
    882	SiS_DisplayOn(SiS_Pr);
    883}
    884
    885/*********************************************/
    886/*                 SiSSetMode()              */
    887/*********************************************/
    888
    889int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
    890{
    891	unsigned short ModeIdIndex;
    892	unsigned long BaseAddr = SiS_Pr->IOAddress;
    893
    894	SiSUSB_InitPtr(SiS_Pr);
    895	SiSUSBRegInit(SiS_Pr, BaseAddr);
    896	SiS_GetSysFlags(SiS_Pr);
    897
    898	if (!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex)))
    899		return 0;
    900
    901	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x05, 0x86);
    902
    903	SiSInitPCIetc(SiS_Pr);
    904
    905	ModeNo &= 0x7f;
    906
    907	SiS_Pr->SiS_ModeType =
    908	    SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
    909
    910	SiS_Pr->SiS_SetFlag = LowModeTests;
    911
    912	/* Set mode on CRT1 */
    913	SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex);
    914
    915	SiS_HandleCRT1(SiS_Pr);
    916
    917	SiS_DisplayOn(SiS_Pr);
    918	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
    919
    920	/* Store mode number */
    921	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x34, ModeNo);
    922
    923	return 1;
    924}
    925
    926int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
    927{
    928	unsigned short ModeNo = 0;
    929	int i;
    930
    931	SiSUSB_InitPtr(SiS_Pr);
    932
    933	if (VModeNo == 0x03) {
    934
    935		ModeNo = 0x03;
    936
    937	} else {
    938
    939		i = 0;
    940		do {
    941
    942			if (SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID == VModeNo) {
    943				ModeNo = SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID;
    944				break;
    945			}
    946
    947		} while (SiS_Pr->SiS_EModeIDTable[i++].Ext_ModeID != 0xff);
    948
    949	}
    950
    951	if (!ModeNo)
    952		return 0;
    953
    954	return SiSUSBSetMode(SiS_Pr, ModeNo);
    955}