GNU Linux-libre 5.16.19-gnu
[releases.git] / drivers / usb / misc / sisusbvga / sisusb_init.c
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
54 static 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
71 static void
72 SiS_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
78 static void
79 SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
80                unsigned short data)
81 {
82         sisusb_setreg(SiS_Pr->sisusb, port, data);
83 }
84
85 static unsigned char
86 SiS_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
95 static unsigned char
96 SiS_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
105 static void
106 SiS_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
113 static void
114 SiS_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
120 static void
121 SiS_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
131 static 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
140 static 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
163 static 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
172 static 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
188 static 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
201 static 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
214 static 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
220 static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
221 {
222         SiS_SetSegmentReg(SiS_Pr, 0);
223 }
224
225 static void
226 SiS_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
236 static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
237 {
238         SiS_SetSegmentRegOver(SiS_Pr, 0);
239 }
240
241 static 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
251 static int
252 SiS_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
284 static 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
294 static unsigned short
295 SiS_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
318 static unsigned short
319 SiS_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
346 static void
347 SiS_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
367 static void
368 SiS_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
379 static void
380 SiS_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
397 static void
398 SiS_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
422 static void
423 SiS_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
443 static 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
458 static unsigned short
459 SiS_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
497 static 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
509 static void
510 SiS_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
557 static void
558 SiS_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
585 static void
586 SiS_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
604 static void
605 SiS_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
629 static void
630 SiS_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
659 static void
660 SiS_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
735 static void
736 SiS_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
763 static void
764 SiS_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
846 static void
847 SiS_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
889 int 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
926 int 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 }