init.c revision dfe64dd3
1/*
2 * Mode initializing code (CRT1 section)
3 * (Universal module for Linux kernel framebuffer and XFree86 4.x)
4 *
5 * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
6 *
7 * If distributed as part of the Linux kernel, the following license terms
8 * apply:
9 *
10 * * This program is free software; you can redistribute it and/or modify
11 * * it under the terms of the GNU General Public License as published by
12 * * the Free Software Foundation; either version 2 of the named License,
13 * * or any later version.
14 * *
15 * * This program is distributed in the hope that it will be useful,
16 * * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * * GNU General Public License for more details.
19 * *
20 * * You should have received a copy of the GNU General Public License
21 * * along with this program; if not, write to the Free Software
22 * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
23 *
24 * Otherwise, the following license terms apply:
25 *
26 * * Redistribution and use in source and binary forms, with or without
27 * * modification, are permitted provided that the following conditions
28 * * are met:
29 * * 1) Redistributions of source code must retain the above copyright
30 * *    notice, this list of conditions and the following disclaimer.
31 * * 2) Redistributions in binary form must reproduce the above copyright
32 * *    notice, this list of conditions and the following disclaimer in the
33 * *    documentation and/or other materials provided with the distribution.
34 * * 3) The name of the author may not be used to endorse or promote products
35 * *    derived from this software without specific prior written permission.
36 * *
37 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
38 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
40 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
41 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
43 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
45 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
46 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 *
48 * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
49 *
50 * Formerly based on non-functional code-fragements for 300 series by XGI, Inc.
51 * Used by permission.
52 *
53 * TW says: This code looks awful, I know. But please don't do anything about
54 * this otherwise debugging will be hell.
55 * The code is extremely fragile as regards the different chipsets, different
56 * video bridges and combinations thereof. If anything is changed, extreme
57 * care has to be taken that that change doesn't break it for other chipsets,
58 * bridges or combinations thereof.
59 * All comments in this file are by me, regardless if they are marked TW or not.
60 *
61 */
62
63#ifdef HAVE_CONFIG_H
64#include "config.h"
65#endif
66
67#include "init.h"
68#include "vgatypes.h"
69#include "vb_def.h"
70#include "vb_setmode.h"
71
72/*********************************************/
73/*            HELPER: Get ModeID             */
74/*********************************************/
75/* Jong 09/18/2007; patch to GIT */
76/* VGAEngine is not used; FSTN is always FALSE */
77USHORT
78XGI_GetModeID(ULONG VBFlags, int HDisplay, int VDisplay,
79              int Depth, int LCDwidth, int LCDheight)
80{
81   USHORT 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	   {
90	     ModeIndex = ModeIndex_320x240[Depth];
91       }
92       break;
93     case 400:
94          if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
95          break;
96     case 512:
97          if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
98          break;
99     case 640:
100          if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
101	  else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
102          break;
103     case 720:
104          if(!(VBFlags & CRT1_LCDA)) {
105             if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
106             else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
107          }
108          break;
109     case 768:
110          if(!(VBFlags & CRT1_LCDA)) {
111             if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
112          }
113	  break;
114     case 800:
115	  if(VDisplay == 600)    ModeIndex = ModeIndex_800x600[Depth];
116	  else if(!(VBFlags & CRT1_LCDA)) {
117	     if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
118	  }
119          break;
120     case 848:
121          if(!(VBFlags & CRT1_LCDA)) {
122	     if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
123	  }
124	  break;
125     case 856:
126          if(!(VBFlags & CRT1_LCDA)) {
127	     if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
128	  }
129	  break;
130     case 1024:
131          if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
132	  else if(!(VBFlags & CRT1_LCDA)) {
133	     if(VDisplay == 576)    ModeIndex = ModeIndex_1024x576[Depth];
134	  }
135          break;
136     case 1152:
137          if(!(VBFlags & CRT1_LCDA)) {
138             if(VDisplay == 864)    ModeIndex = ModeIndex_1152x864[Depth];
139	  }
140	  break;
141     case 1280:
142          if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
143	  else if(VDisplay == 720) {
144	     if((VBFlags & CRT1_LCDA) && (LCDwidth == 1280) && (LCDheight == 720)) {
145	        ModeIndex = ModeIndex_1280x720[Depth];
146	     } else if(!(VBFlags & CRT1_LCDA)) {
147	        ModeIndex = ModeIndex_1280x720[Depth];
148	     }
149	  } else if(!(VBFlags & CRT1_LCDA)) {
150             if(VDisplay == 960)      ModeIndex = ModeIndex_1280x960[Depth];
151	     else if(VDisplay == 768) {
152	           ModeIndex = ModeIndex_310_1280x768[Depth];
153	     }
154	  }
155          break;
156     case 1360:
157          if(!(VBFlags & CRT1_LCDA)) {
158	     if(VDisplay == 768)     ModeIndex = ModeIndex_1360x768[Depth];
159	  }
160          break;
161     case 1400:
162          break;
163     case 1440:
164          /* if(VDisplay == 900) ModeIndex = ModeIndex_1440x900[Depth]; */
165          break;
166     case 1600:
167          if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
168          break;
169     case 1680:
170          break;
171     case 1920:
172          if(!(VBFlags & CRT1_LCDA)) {
173             if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth];
174	  }
175          break;
176     case 2048:
177          if(!(VBFlags & CRT1_LCDA)) {
178             if(VDisplay == 1536) {
179	            ModeIndex = ModeIndex_310_2048x1536[Depth];
180	     }
181	  }
182          break;
183   }
184
185   return(ModeIndex);
186}
187
188/*********************************************/
189/*          HELPER: SetReg, GetReg           */
190/*********************************************/
191
192void
193XGI_SetReg(XGIIOADDRESS port, USHORT index, USHORT data)
194{
195   outb(port,index);
196   outb(port + 1,data);
197}
198
199void
200XGI_SetRegByte(XGIIOADDRESS port, USHORT data)
201{
202   outb(port,data);
203}
204
205void
206XGI_SetRegShort(XGIIOADDRESS port, USHORT data)
207{
208   outw(port,data);
209}
210
211void
212XGI_SetRegLong(XGIIOADDRESS port, ULONG data)
213{
214    outl(port,data);
215}
216
217UCHAR
218XGI_GetReg(XGIIOADDRESS port, USHORT index)
219{
220   outb(port,index);
221   return inb(port + 1);
222}
223
224UCHAR
225XGI_GetRegByte(XGIIOADDRESS port)
226{
227   return inb(port);
228}
229
230USHORT
231XGI_GetRegShort(XGIIOADDRESS port)
232{
233   return inw(port);
234}
235
236ULONG
237XGI_GetRegLong(XGIIOADDRESS port)
238{
239   return inl(port);
240}
241
242void
243XGI_SetRegANDOR(XGIIOADDRESS Port,USHORT Index,USHORT DataAND,USHORT DataOR)
244{
245  USHORT temp;
246
247  temp = XGI_GetReg(Port,Index);
248  temp = (temp & (DataAND)) | DataOR;
249  XGI_SetReg(Port,Index,temp);
250}
251
252void
253XGI_SetRegAND(XGIIOADDRESS Port,USHORT Index,USHORT DataAND)
254{
255  USHORT temp;
256
257  temp = XGI_GetReg(Port,Index);
258  temp &= DataAND;
259  XGI_SetReg(Port,Index,temp);
260}
261
262void
263XGI_SetRegOR(XGIIOADDRESS Port,USHORT Index,USHORT DataOR)
264{
265  USHORT temp;
266
267  temp = XGI_GetReg(Port,Index);
268  temp |= DataOR;
269  XGI_SetReg(Port,Index,temp);
270}
271
272/*********************************************/
273/*      HELPER: DisplayOn, DisplayOff        */
274/*********************************************/
275
276void
277XGI_New_DisplayOn(VB_DEVICE_INFO *XGI_Pr)
278{
279   XGI_SetRegAND(XGI_Pr->P3c4,0x01,0xDF);
280}
281
282void
283XGI_New_DisplayOff(VB_DEVICE_INFO *XGI_Pr)
284{
285   XGI_SetRegOR(XGI_Pr->P3c4,0x01,0x20);
286}
287
288/*********************************************/
289/*         HELPER: Init PCI & Engines        */
290/*********************************************/
291
292static void
293XGIInitPCIetc(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwInfo)
294{
295   CARD8  bForce=0x00; /* Jong 01/07/2008; force to disable 2D */
296
297   switch(HwInfo->jChipType) {
298   case XG40:
299   case XG42:
300   case XG20:
301   case XG21:
302      XGI_SetReg(XGI_Pr->P3c4,0x20,0xa1);
303      /*  - Enable 2D (0x40)
304       *  - Enable 3D (0x02)
305       *  - Enable 3D vertex command fetch (0x10)
306       *  - Enable 3D command parser (0x08)
307       *  - Enable 3D G/L transformation engine (0x80)
308       */
309      XGI_SetRegOR(XGI_Pr->P3c4, 0x1E,
310		   SR1E_ENABLE_3D_TRANSFORM_ENGINE
311		   | SR1E_ENABLE_2D
312		   | SR1E_ENABLE_3D_AGP_VERTEX_FETCH
313		   | SR1E_ENABLE_3D_COMMAND_PARSER
314		   | SR1E_ENABLE_3D);
315
316	  /* Jong 01/07/2008; support forcing to disable 2D engine */
317	  if(HwInfo->jChipType == XG21)
318	  {
319  			inXGIIDXREG(XGI_Pr->P3c4, 0x3A, bForce) ;
320			bForce &= 0x40;
321
322			if(bForce != 0x00)
323			  XGI_SetRegAND(XGI_Pr->P3c4,0x1E,0xBF);
324	  }
325
326	  break;
327   }
328}
329
330/*********************************************/
331/*             HELPER: GetVBType             */
332/*********************************************/
333
334void
335XGI_New_GetVBType(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwInfo)
336{
337  USHORT flag=0, rev=0, nolcd=0;
338
339  XGI_Pr->VBType = 0;
340
341  flag = XGI_GetReg(XGI_Pr->Part4Port,0x00);
342PDEBUG(ErrorF("GetVBType: part4_0: %x \n",flag)); //yilin
343  if(flag > 3) return;
344
345  rev = XGI_GetReg(XGI_Pr->Part4Port,0x01);
346PDEBUG(ErrorF("GetVBType: part4_1: %x \n",rev)); //yilin
347
348  if(flag >= 2) {
349     XGI_Pr->VBType = VB_XGI302B;
350  } else if(flag == 1) {
351     if(rev >= 0xC0) {
352       	XGI_Pr->VBType = VB_XGI301C;
353     } else if(rev >= 0xB0) {
354       	XGI_Pr->VBType = VB_XGI301B;
355	/* Check if 30xB DH version (no LCD support, use Panel Link instead) */
356    	nolcd = XGI_GetReg(XGI_Pr->Part4Port,0x23);
357        if(!(nolcd & 0x02)) XGI_Pr->VBType |= VB_NoLCD;
358     } else {
359        XGI_Pr->VBType = VB_XGI301;
360     }
361  }
362  if(XGI_Pr->VBType & (VB_XGI301B | VB_XGI301C | VB_XGI302B)) {
363     if(rev >= 0xE0) {
364	flag = XGI_GetReg(XGI_Pr->Part4Port,0x39);
365	if(flag == 0xff) XGI_Pr->VBType = VB_XGI302LV;
366	else 	 	 XGI_Pr->VBType = VB_XGI302ELV;
367     } else if(rev >= 0xD0) {
368	XGI_Pr->VBType = VB_XGI301LV;
369     }
370  }
371PDEBUG(ErrorF("GetVBType: XGI_Pr->VBType=%x \n",XGI_Pr->VBType)); //yilin
372}
373
374/*********************************************/
375/*           HELPER: SearchModeID            */
376/*********************************************/
377
378BOOLEAN
379XGI_SearchModeID(const XGI_StStruct *SModeIDTable,
380		 const XGI_ExtStruct *EModeIDTable,
381		 unsigned char VGAINFO, USHORT *ModeNo, USHORT *ModeIdIndex)
382{
383    if (*ModeNo <= 0x13) {
384	if ((*ModeNo) <= 0x05)
385	    (*ModeNo) |= 0x01;
386
387	for (*ModeIdIndex = 0; /* emtpy */; (*ModeIdIndex)++) {
388	    if (SModeIDTable[*ModeIdIndex].St_ModeID == (*ModeNo))
389		break;
390
391	    if (SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF)
392		return FALSE;
393	}
394
395	if (*ModeNo == 0x07) {
396	    if (VGAINFO & 0x10)
397		(*ModeIdIndex)++;   /* 400 lines */
398	    /* else 350 lines */
399	}
400
401	if (*ModeNo <= 0x03) {
402	    if (!(VGAINFO & 0x80))
403		(*ModeIdIndex)++;
404
405	    if (VGAINFO & 0x10)
406		(*ModeIdIndex)++; /* 400 lines  */
407	    /* else 350 lines  */
408	}
409	/* else 200 lines  */
410    }
411    else {
412
413	for (*ModeIdIndex = 0; /* emtpy */; (*ModeIdIndex)++) {
414	    if (EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
415		break;
416
417	    if (EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
418		return FALSE;
419	}
420    }
421
422    return TRUE;
423}
424
425/*********************************************/
426/*            HELPER: GetModePtr             */
427/*********************************************/
428
429UCHAR
430XGI_GetModePtr(const XGI_StStruct *SModeIDTable, unsigned ModeType,
431	       USHORT ModeNo, USHORT ModeIdIndex)
432{
433    return (ModeNo <= 0x13)
434	? SModeIDTable[ModeIdIndex].St_StTableIndex
435	: ((ModeType <= 0x02) ? 0x1B /* 02 -> ModeEGA  */ : 0x0F);
436}
437
438
439/*********************************************/
440/*           HELPER: LowModeTests            */
441/*********************************************/
442
443static BOOLEAN
444XGI_DoLowModeTest(VB_DEVICE_INFO *XGI_Pr, USHORT ModeNo, PXGI_HW_DEVICE_INFO HwInfo)
445{
446    USHORT temp,temp1,temp2;
447
448    if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12))
449       return(1);
450    temp = XGI_GetReg(XGI_Pr->P3d4,0x11);
451    XGI_SetRegOR(XGI_Pr->P3d4,0x11,0x80);
452    temp1 = XGI_GetReg(XGI_Pr->P3d4,0x00);
453    XGI_SetReg(XGI_Pr->P3d4,0x00,0x55);
454    temp2 = XGI_GetReg(XGI_Pr->P3d4,0x00);
455    XGI_SetReg(XGI_Pr->P3d4,0x00,temp1);
456    XGI_SetReg(XGI_Pr->P3d4,0x11,temp);
457    if (temp2 == 0x55)
458	return(0);
459    else
460	return(1);
461}
462
463static void
464XGI_SetLowModeTest(VB_DEVICE_INFO *XGI_Pr, USHORT ModeNo, PXGI_HW_DEVICE_INFO HwInfo)
465{
466    if(XGI_DoLowModeTest(XGI_Pr, ModeNo, HwInfo)) {
467       XGI_Pr->SetFlag |= LowModeTests;
468    }
469}
470
471static void
472XGI_HandleCRT1(VB_DEVICE_INFO *XGI_Pr)
473{
474    XGI_SetRegAND(XGI_Pr->P3d4, 0x53, 0xbf);
475}
476
477/*********************************************/
478/*             HELPER: GetOffset             */
479/*********************************************/
480
481USHORT
482XGI_New_GetOffset(VB_DEVICE_INFO *XGI_Pr,USHORT ModeNo,USHORT ModeIdIndex,
483              USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwInfo)
484{
485  USHORT xres, temp, colordepth, infoflag;
486
487  infoflag = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
488  xres = XGI_Pr->RefIndex[RefreshRateTableIndex].XRes;
489
490  colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, XGI_Pr);
491
492  temp = xres / 16;
493  if(infoflag & InterlaceMode) temp <<= 1;
494  temp *= colordepth;
495  if(xres % 16) {
496     colordepth >>= 1;
497     temp += colordepth;
498  }
499
500  return(temp);
501}
502
503/*********************************************/
504/*                 RESET VCLK                */
505/*********************************************/
506
507static void
508XGI_ResetCRT1VCLK(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwInfo)
509{
510    XGI_SetRegANDOR(XGI_Pr->P3c4,0x31,0xCF,0x20);
511    XGI_SetReg(XGI_Pr->P3c4,0x2B,XGI_Pr->VCLKData[1].SR2B);
512    XGI_SetReg(XGI_Pr->P3c4,0x2C,XGI_Pr->VCLKData[1].SR2C);
513    XGI_SetReg(XGI_Pr->P3c4,0x2D,0x80);
514    XGI_SetRegANDOR(XGI_Pr->P3c4,0x31,0xcf,0x10);
515    XGI_SetReg(XGI_Pr->P3c4,0x2B,XGI_Pr->VCLKData[0].SR2B);
516    XGI_SetReg(XGI_Pr->P3c4,0x2C,XGI_Pr->VCLKData[0].SR2C);
517    XGI_SetReg(XGI_Pr->P3c4,0x2D,0x80);
518}
519
520/*********************************************/
521/*                  CRTC/2                   */
522/*********************************************/
523
524static void
525XGI_New_SetCRT1CRTC(VB_DEVICE_INFO *XGI_Pr, USHORT ModeNo, USHORT ModeIdIndex,
526                USHORT RefreshRateTableIndex,
527		PXGI_HW_DEVICE_INFO HwInfo)
528{
529  UCHAR  index;
530  USHORT temp,i,j,modeflag;
531
532  XGI_SetRegAND(XGI_Pr->P3d4,0x11,0x7f);		/* unlock cr0-7 */
533
534     if(ModeNo <= 0x13) {
535        modeflag = XGI_Pr->SModeIDTable[ModeIdIndex].St_ModeFlag;
536     } else {
537        modeflag = XGI_Pr->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
538     }
539
540     index = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
541
542     for(i=0,j=0;i<=7;i++,j++) {
543        XGI_SetReg(XGI_Pr->P3d4,j,XGI_Pr->XGINEWUB_CRT1Table[index].CR[i]);
544     }
545     for(j=0x10;i<=10;i++,j++) {
546        XGI_SetReg(XGI_Pr->P3d4,j,XGI_Pr->XGINEWUB_CRT1Table[index].CR[i]);
547     }
548     for(j=0x15;i<=12;i++,j++) {
549        XGI_SetReg(XGI_Pr->P3d4,j,XGI_Pr->XGINEWUB_CRT1Table[index].CR[i]);
550     }
551     for(j=0x0A;i<=15;i++,j++) {
552        XGI_SetReg(XGI_Pr->P3c4,j,XGI_Pr->XGINEWUB_CRT1Table[index].CR[i]);
553     }
554
555     temp = XGI_Pr->XGINEWUB_CRT1Table[index].CR[16] & 0xE0;
556     XGI_SetReg(XGI_Pr->P3c4,0x0E,temp);
557
558     temp = ((XGI_Pr->XGINEWUB_CRT1Table[index].CR[16]) & 0x01) << 5;
559     if(modeflag & DoubleScanMode)  temp |= 0x80;
560     XGI_SetRegANDOR(XGI_Pr->P3d4,0x09,0x5F,temp);
561
562  if(XGI_Pr->ModeType > ModeVGA) XGI_SetReg(XGI_Pr->P3d4,0x14,0x4F);
563}
564
565/*********************************************/
566/*               OFFSET & PITCH              */
567/*********************************************/
568/*  (partly overruled by SetPitch() in XF86) */
569/*********************************************/
570
571static void
572XGI_New_SetCRT1Offset(VB_DEVICE_INFO *XGI_Pr, USHORT ModeNo, USHORT ModeIdIndex,
573                  USHORT RefreshRateTableIndex,
574		  PXGI_HW_DEVICE_INFO HwInfo)
575{
576   USHORT temp, DisplayUnit, infoflag;
577
578   infoflag = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
579
580   DisplayUnit = XGI_New_GetOffset(XGI_Pr,ModeNo,ModeIdIndex,
581                     	       RefreshRateTableIndex,HwInfo);
582
583   temp = (DisplayUnit >> 8) & 0x0f;
584   XGI_SetRegANDOR(XGI_Pr->P3c4,0x0E,0xF0,temp);
585
586   temp = DisplayUnit & 0xFF;
587   XGI_SetReg(XGI_Pr->P3d4,0x13,temp);
588
589   if(infoflag & InterlaceMode) DisplayUnit >>= 1;
590
591   DisplayUnit <<= 5;
592   temp = (DisplayUnit & 0xff00) >> 8;
593   if(DisplayUnit & 0xff) temp++;
594   temp++;
595   XGI_SetReg(XGI_Pr->P3c4,0x10,temp);
596}
597
598/*********************************************/
599/*                  VCLK                     */
600/*********************************************/
601
602static void
603XGI_New_SetCRT1VCLK(VB_DEVICE_INFO *XGI_Pr, USHORT ModeNo, USHORT ModeIdIndex,
604                PXGI_HW_DEVICE_INFO HwInfo, USHORT RefreshRateTableIndex)
605{
606  USHORT  index=0, clka, clkb;
607
608     if((XGI_Pr->VBType & VB_XGI301BLV302BLV) && (XGI_Pr->VBInfo & SetCRT2ToLCDA)) {
609        clka = XGI_Pr->VBVCLKData[index].Part4_A;
610	clkb = XGI_Pr->VBVCLKData[index].Part4_B;
611     } else {
612        clka = XGI_Pr->VCLKData[index].SR2B;
613	clkb = XGI_Pr->VCLKData[index].SR2C;
614     }
615
616    XGI_SetRegAND(XGI_Pr->P3c4,0x31,0xCF);
617    XGI_SetReg(XGI_Pr->P3c4,0x2B,clka);
618    XGI_SetReg(XGI_Pr->P3c4,0x2C,clkb);
619    XGI_SetReg(XGI_Pr->P3c4,0x2D,0x01);
620}
621
622/*********************************************/
623/*              MODE REGISTERS               */
624/*********************************************/
625
626static void
627XGI_New_SetVCLKState(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwInfo,
628                 USHORT ModeNo, USHORT RefreshRateTableIndex,
629                 USHORT ModeIdIndex)
630{
631  USHORT data=0, VCLK=0, index=0;
632
633  if(ModeNo > 0x13) {
634        VCLK = XGI_Pr->VCLKData[index].CLOCK;
635  }
636
637    if(VCLK >= 166)
638	data |= 0x0c;
639
640    XGI_SetRegANDOR(XGI_Pr->P3c4,0x32,0xf3,data);
641
642    if(VCLK >= 166) {
643	XGI_SetRegAND(XGI_Pr->P3c4,0x1f,0xe7);
644    }
645
646    /* DAC speed */
647    XGI_SetRegANDOR(XGI_Pr->P3c4,0x07,0xE8,0x10);
648}
649
650static void
651XGI_New_SetCRT1ModeRegs(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwInfo,
652                    USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex)
653{
654  USHORT data,infoflag=0,modeflag;
655  USHORT resindex = 0,xres;
656
657     if(ModeNo > 0x13) {
658    	modeflag = XGI_Pr->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
659    	infoflag = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
660	xres = XGI_Pr->ModeResInfo[resindex].HTotal;
661     } else {
662    	modeflag = XGI_Pr->SModeIDTable[ModeIdIndex].St_ModeFlag;
663	xres = XGI_Pr->StResInfo[resindex].HTotal;
664     }
665
666  /* Disable DPMS */
667  XGI_SetRegAND(XGI_Pr->P3c4,0x1F,0x3F);
668
669  data = 0;
670  if(ModeNo > 0x13) {
671     if(XGI_Pr->ModeType > 0x02) {
672        data |= 0x02;
673        data |= ((XGI_Pr->ModeType - ModeVGA) << 2);
674     }
675     if(infoflag & InterlaceMode) data |= 0x20;
676  }
677  XGI_SetRegANDOR(XGI_Pr->P3c4,0x06,0xC0,data);
678
679    data = 0;
680    if(infoflag & InterlaceMode) {
681        if(xres <= 800)       data = 0x0020;
682        else if(xres <= 1024) data = 0x0035;
683        else                  data = 0x0048;
684    }
685    XGI_SetReg(XGI_Pr->P3d4,0x19,(data & 0xFF));
686    XGI_SetRegANDOR(XGI_Pr->P3d4,0x1a,0xFC,(data >> 8));
687
688  if(modeflag & HalfDCLK) {
689     XGI_SetRegOR(XGI_Pr->P3c4,0x01,0x08);
690  }
691
692  data = 0;
693  if(modeflag & LineCompareOff) data = 0x08;
694
695     XGI_SetRegANDOR(XGI_Pr->P3c4,0x0F,0xB7,data);
696     if(XGI_Pr->ModeType == ModeEGA) {
697        if(ModeNo > 0x13) {
698  	   XGI_SetRegOR(XGI_Pr->P3c4,0x0F,0x40);
699        }
700     }
701
702    XGI_SetRegAND(XGI_Pr->P3c4,0x31,0xfb);
703
704  data = 0x60;
705  if(XGI_Pr->ModeType != ModeText) {
706     data ^= 0x60;
707     if(XGI_Pr->ModeType != ModeEGA) {
708        data ^= 0xA0;
709     }
710  }
711  XGI_SetRegANDOR(XGI_Pr->P3c4,0x21,0x1F,data);
712
713  XGI_New_SetVCLKState(XGI_Pr, HwInfo, ModeNo, RefreshRateTableIndex, ModeIdIndex);
714}
715
716/*********************************************/
717/*                 LOAD DAC                  */
718/*********************************************/
719
720extern const uint8_t XGI_MDA_DAC[];
721extern const uint8_t XGI_CGA_DAC[];
722extern const uint8_t XGI_EGA_DAC[];
723extern const uint8_t XGI_VGA_DAC[];
724
725void
726XGI_New_LoadDAC(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwInfo,
727            USHORT ModeNo, USHORT ModeIdIndex)
728{
729   USHORT data,data2;
730   USHORT time,i,j,k,m,n,o;
731   USHORT si,di,bx,dl,al,ah,dh;
732   USHORT shiftflag;
733   XGIIOADDRESS DACAddr, DACData;
734   const uint8_t *table = NULL;
735
736   if(ModeNo <= 0x13) {
737      data = XGI_Pr->SModeIDTable[ModeIdIndex].St_ModeFlag;
738   } else {
739      data = XGI_Pr->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
740   }
741
742   data &= DACInfoFlag;
743   time = 64;
744   if(data == 0x00) table = XGI_MDA_DAC;
745   if(data == 0x08) table = XGI_CGA_DAC;
746   if(data == 0x10) table = XGI_EGA_DAC;
747   if(data == 0x18) {
748      time = 256;
749      table = XGI_VGA_DAC;
750   }
751   if(time == 256) j = 16;
752   else            j = time;
753
754   if( ( (XGI_Pr->VBInfo & SetCRT2ToLCD) &&        /* 301B-DH LCD */
755         (XGI_Pr->VBType & VB_NoLCD) )        ||
756       (XGI_Pr->VBInfo & SetCRT2ToLCDA)       ||   /* LCDA */
757       (!(XGI_Pr->SetFlag & ProgrammingCRT2)) ) {  /* Programming CRT1 */
758      DACAddr = XGI_Pr->P3c8;
759      DACData = XGI_Pr->P3c9;
760      shiftflag = 0;
761      XGI_SetRegByte(XGI_Pr->P3c6,0xFF);
762   } else {
763      shiftflag = 1;
764      DACAddr = XGI_Pr->Part5Port;
765      DACData = XGI_Pr->Part5Port + 1;
766   }
767
768   XGI_SetRegByte(DACAddr,0x00);
769
770   for(i=0; i<j; i++) {
771      data = table[i];
772      for(k=0; k<3; k++) {
773	data2 = 0;
774	if(data & 0x01) data2 = 0x2A;
775	if(data & 0x02) data2 += 0x15;
776	if(shiftflag) data2 <<= 2;
777	XGI_SetRegByte(DACData, data2);
778	data >>= 2;
779      }
780   }
781
782   if(time == 256) {
783      for(i = 16; i < 32; i++) {
784   	 data = table[i];
785	 if(shiftflag) data <<= 2;
786	 for(k = 0; k < 3; k++) XGI_SetRegByte(DACData, data);
787      }
788      si = 32;
789      for(m = 0; m < 9; m++) {
790         di = si;
791         bx = si + 4;
792         dl = 0;
793         for(n = 0; n < 3; n++) {
794  	    for(o = 0; o < 5; o++) {
795	       dh = table[si];
796	       ah = table[di];
797	       al = table[bx];
798	       si++;
799	       XGI_WriteDAC(DACData, shiftflag, dl, ah, al, dh);
800	    }
801	    si -= 2;
802	    for(o = 0; o < 3; o++) {
803	       dh = table[bx];
804	       ah = table[di];
805	       al = table[si];
806	       si--;
807	       XGI_WriteDAC(DACData, shiftflag, dl, ah, al, dh);
808	    }
809	    dl++;
810	 }            /* for n < 3 */
811	 si += 5;
812      }               /* for m < 9 */
813   }
814}
815
816/*********************************************/
817/*         SET CRT1 REGISTER GROUP           */
818/*********************************************/
819
820static void
821XGI_New_SetCRT1Group(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwInfo,
822                 USHORT ModeNo, USHORT ModeIdIndex)
823{
824    const USHORT StandTableIndex = XGI_GetModePtr(XGI_Pr->SModeIDTable,
825                                                  XGI_Pr->ModeType,
826                                                  ModeNo, ModeIdIndex);
827    USHORT RefreshRateTableIndex = 0;
828
829
830/*
831  if(XGI_Pr->SetFlag & LowModeTests) {
832     if(XGI_Pr->VBInfo & (SetSimuScanMode | SwitchToCRT2)) {
833        XGI_New_DisableBridge(XGI_Pr, HwInfo);
834     }
835  }
836*/
837  XGI_SetSeqRegs(StandTableIndex, XGI_Pr);
838  XGI_SetMiscRegs(StandTableIndex, XGI_Pr);
839  XGI_SetCRTCRegs(StandTableIndex, XGI_Pr);
840  XGI_SetATTRegs(ModeNo, StandTableIndex, ModeIdIndex, XGI_Pr);
841  XGI_SetGRCRegs(StandTableIndex, XGI_Pr);
842  XGI_ClearExt1Regs(ModeNo, XGI_Pr);
843  XGI_ResetCRT1VCLK(XGI_Pr, HwInfo);
844
845  XGI_Pr->SetFlag &= (~ProgrammingCRT2);
846
847#ifdef LINUX_XF86
848  xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n",
849                    XGI_Pr->VBType, XGI_Pr->VBInfo);
850#endif
851
852  if(XGI_Pr->VBInfo & SetSimuScanMode) {
853     if(XGI_Pr->VBInfo & SetInSlaveMode) {
854        XGI_Pr->SetFlag |= ProgrammingCRT2;
855     }
856  }
857
858  if(XGI_Pr->VBInfo & SetCRT2ToLCDA) {
859     XGI_Pr->SetFlag |= ProgrammingCRT2;
860  }
861
862  if(!(XGI_Pr->VBInfo & SetCRT2ToLCDA)) {
863     XGI_Pr->SetFlag &= ~ProgrammingCRT2;
864  }
865
866  if(RefreshRateTableIndex != 0xFFFF) {
867     XGI_SetSync(RefreshRateTableIndex, XGI_Pr);
868     XGI_New_SetCRT1CRTC(XGI_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
869     XGI_New_SetCRT1Offset(XGI_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
870     XGI_New_SetCRT1VCLK(XGI_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
871  }
872
873  XGI_New_SetCRT1ModeRegs(XGI_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex);
874
875  XGI_New_LoadDAC(XGI_Pr, HwInfo, ModeNo, ModeIdIndex);
876}
877
878
879/*********************************************/
880/*         XFree86: SET SCREEN PITCH         */
881/*********************************************/
882
883#ifdef LINUX_XF86
884static void
885XGI_SetPitchCRT1(VB_DEVICE_INFO *XGI_Pr, ScrnInfoPtr pScrn)
886{
887   XGIPtr pXGI = XGIPTR(pScrn);
888   UShort HDisplay = pXGI->scrnPitch >> 3;
889
890   XGI_SetReg(XGI_Pr->P3d4,0x13,(HDisplay & 0xFF));
891   XGI_SetRegANDOR(XGI_Pr->P3c4,0x0E,0xF0,(HDisplay>>8));
892}
893#endif
894
895/*********************************************/
896/*          XFree86: XGIBIOSSetMode()        */
897/*           for non-Dual-Head mode          */
898/*********************************************/
899
900#ifdef LINUX_XF86
901BOOLEAN
902XGIBIOSSetMode(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwInfo,
903	       ScrnInfoPtr pScrn, DisplayModePtr mode)
904{
905    XGIPtr  pXGI = XGIPTR(pScrn);
906    UShort  ModeNo=0;
907    BOOLEAN SetModeRet = FALSE ;
908    UShort  HDisplay = pXGI->scrnOffset >> 3 ;
909
910#if XGI_USING_BIOS_SETMODE
911    PDEBUG(ErrorF("XGI_USING_BIOS_SETMODE \n"));
912    if ((pXGI->pVbe != NULL) && (pXGI->pVbe->pInt10 != NULL)) {
913        xf86Int10InfoPtr pInt = pXGI->pVbe->pInt10;
914
915        if (xf86LoadSubModule(pScrn, "int10")) {
916            pInt->num = 0x10;
917            pInt->ax = 0x80 | ModeNo;
918
919            /* ah = 0, set mode */
920            xf86ExecX86int10(pInt);
921            SetModeRet = ((pInt->ax & 0x7f) == ModeNo);
922        }
923    }
924    else
925#endif
926    {
927        PDEBUG(ErrorF("XGI_USING_C_code_SETMODE \n"));
928		/* Jong 08/21/2007; support external modeline in X configuration file */
929		/* ------------------------------------------------------------------ */
930		HwInfo->BPP = pScrn->bitsPerPixel;
931		HwInfo->Frequency = mode->VRefresh;
932		HwInfo->Horizontal_ACTIVE = mode->HDisplay;
933		HwInfo->Vertical_ACTIVE = mode->VDisplay;
934		HwInfo->Interlace=FALSE;
935
936		if( (mode->type == M_T_USERDEF) || ((mode->type & M_T_CLOCK_CRTC_C) == M_T_CLOCK_CRTC_C) ) /* custom mode */
937		{
938			xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting a customer mode %dx%d\n", mode->HDisplay, mode->VDisplay);
939
940			HwInfo->SpecifyTiming = TRUE;
941			HwInfo->Horizontal_FP = mode->HSyncStart - mode->HDisplay; /* HSyncStart - HDisplay */
942			HwInfo->Horizontal_BP = mode->HTotal - mode->HSyncEnd; /* HTotal - HSyncEnd */
943			HwInfo->Horizontal_SYNC = mode->HSyncEnd - mode->HSyncStart; /* HSyncEnd - HSyncStart */
944			HwInfo->Vertical_FP =  mode->VSyncStart - mode->VDisplay;
945			HwInfo->Vertical_BP = mode->VTotal - mode->VSyncEnd;
946			HwInfo->Vertical_SYNC = mode->VSyncEnd - mode->VSyncStart;
947			HwInfo->DCLK = mode->Clock;
948		}
949		else
950		{
951			HwInfo->SpecifyTiming = FALSE;
952
953			ModeNo = XGI_CalcModeIndex(pScrn, mode, pXGI->VBFlags);
954			if(!ModeNo) return FALSE;
955
956			xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting a standard mode 0x%x\n", ModeNo);
957		}
958		/* ------------------------------------------------------------------ */
959
960        SetModeRet = XGISetModeNew(HwInfo, XGI_Pr, ModeNo);
961        PDEBUG(ErrorF("out_of_C_code_SETMODE \n"));
962    }
963
964
965    /* SetPitch: Adapt to virtual size & position */
966    if ((ModeNo > 0x13) || (mode->type == M_T_USERDEF) || ((mode->type & M_T_CLOCK_CRTC_C) == M_T_CLOCK_CRTC_C)) {
967        XGI_SetReg(XGI_Pr->Part1Port, 0x2f, 1);  //yilin for crt2pitch it shoude modify if not colone mode
968        XGI_SetReg(XGI_Pr->Part1Port, 0x07, (HDisplay & 0xFF));
969        XGI_SetRegANDOR(XGI_Pr->Part1Port, 0x09, 0xF0, (HDisplay>>8));
970
971		/* Jong10052009; Set pitch with HDisplay = pXGI->scrnOffset >> 3 */
972	    PDEBUG(ErrorF("scrnOffset is %d...\n", pXGI->scrnOffset));
973        XGI_SetReg(XGI_Pr->P3d4,0x13,(HDisplay & 0xFF));
974        XGI_SetRegANDOR(XGI_Pr->P3c4,0x0E,0xF0,(HDisplay>>8));
975		/*
976        XGI_SetReg(XGI_Pr->P3d4,0x13,(HDisplay & 0xFF));
977        XGI_SetRegANDOR(XGI_Pr->P3c4,0x0E,0xF0,(HDisplay>>8)); */
978    }
979
980    return SetModeRet;
981}
982
983/*********************************************/
984/*       XFree86: XGIBIOSSetModeCRT1()       */
985/*           for Dual-Head modes             */
986/*********************************************/
987
988BOOLEAN
989XGIBIOSSetModeCRT1(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwInfo,
990		   ScrnInfoPtr pScrn, DisplayModePtr mode)
991{
992    XGIPtr  pXGI = XGIPTR(pScrn);
993    USHORT  ModeIdIndex, ModeNo=0;
994    UCHAR backupreg=0;
995    unsigned vga_info;
996    XGIEntPtr pXGIEnt = ENTITY_PRIVATE(pXGI);
997    UCHAR backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0;
998
999
1000    ModeNo = XGI_CalcModeIndex(pScrn, mode, pXGI->VBFlags);
1001    if(!ModeNo) return FALSE;
1002
1003    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
1004                   "Setting standard mode 0x%x on CRT1\n", ModeNo);
1005
1006#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__))
1007    vga_info = XGI_GetSetBIOSScratch(pScrn, 0x489, 0xff);
1008#else
1009    vga_info = 0x11;
1010#endif
1011   XGIInitPCIetc(XGI_Pr, HwInfo);
1012
1013   XGI_SetReg(XGI_Pr->P3c4,0x05,0x86);
1014
1015   if (!XGI_SearchModeID(XGI_Pr->SModeIDTable, XGI_Pr->EModeIDTable,
1016                         vga_info, &ModeNo, &ModeIdIndex)) {
1017       return FALSE;
1018   }
1019
1020   /* Determine VBType */
1021   XGI_New_GetVBType(XGI_Pr, HwInfo);
1022
1023    if (XGI_Pr->VBType & VB_XGI301BLV302BLV) {
1024	backupreg = XGI_GetReg(XGI_Pr->P3d4,0x38);
1025    }
1026
1027   /* Get VB information (connectors, connected devices) */
1028   /* (We don't care if the current mode is a CRT2 mode) */
1029   XGI_SetLowModeTest(XGI_Pr, ModeNo, HwInfo);
1030
1031   /* Set mode on CRT1 */
1032   XGI_New_SetCRT1Group(XGI_Pr, HwInfo, ModeNo, ModeIdIndex);
1033   /* SetPitch: Adapt to virtual size & position */
1034   XGI_SetPitchCRT1(XGI_Pr, pScrn);
1035
1036
1037   /* Reset CRT2 if changing mode on CRT1 */
1038   if(IS_DUAL_HEAD(pXGI)) {
1039      if(pXGIEnt->CRT2ModeNo != -1) {
1040         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
1041				"(Re-)Setting mode for CRT2\n");
1042	 backupcr30 = XGI_GetReg(XGI_Pr->P3d4,0x30);
1043	 backupcr31 = XGI_GetReg(XGI_Pr->P3d4,0x31);
1044	 backupcr35 = XGI_GetReg(XGI_Pr->P3d4,0x35);
1045	 backupcr38 = XGI_GetReg(XGI_Pr->P3d4,0x38);
1046	 if(XGI_Pr->VBType & VB_XGIVB) {
1047	    /* Backup LUT-enable */
1048	    if(pXGIEnt->CRT2ModeSet) {
1049	       backupp40d = XGI_GetReg(XGI_Pr->Part4Port,0x0d) & 0x08;
1050	    }
1051	 }
1052	 if(XGI_Pr->VBInfo & SetCRT2ToLCDA) {
1053	    XGI_SetReg(XGI_Pr->P3d4,0x30,pXGIEnt->CRT2CR30);
1054	    XGI_SetReg(XGI_Pr->P3d4,0x31,pXGIEnt->CRT2CR31);
1055	    XGI_SetReg(XGI_Pr->P3d4,0x35,pXGIEnt->CRT2CR35);
1056	    XGI_SetReg(XGI_Pr->P3d4,0x38,pXGIEnt->CRT2CR38);
1057	 }
1058
1059         XGI_SetReg(XGI_Pr->P3d4,0x30,backupcr30);
1060	 XGI_SetReg(XGI_Pr->P3d4,0x31,backupcr31);
1061	 XGI_SetReg(XGI_Pr->P3d4,0x35,backupcr35);
1062	 XGI_SetReg(XGI_Pr->P3d4,0x38,backupcr38);
1063	 if(XGI_Pr->VBType & VB_XGIVB) {
1064	    XGI_SetRegANDOR(XGI_Pr->Part4Port,0x0d, ~0x08, backupp40d);
1065	 }
1066      }
1067   }
1068
1069   /* Warning: From here, the custom mode entries in XGI_Pr are
1070    * possibly overwritten
1071    */
1072
1073   XGI_HandleCRT1(XGI_Pr);
1074
1075   XGI_New_DisplayOn(XGI_Pr);
1076   XGI_SetRegByte(XGI_Pr->P3c6,0xFF);
1077
1078   /* Backup/Set ModeNo in BIOS scratch area */
1079   XGI_GetSetModeID(pScrn,ModeNo);
1080
1081   return TRUE;
1082}
1083#endif /* Linux_XF86 */
1084