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