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