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