1 /*
2  * X.org/XFree86 specific extensions to init.c/init301.c
3  *
4  * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1) Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2) Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3) The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
29  *
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include "initextx.h"
37 
38 static void
SiS_MakeClockRegs(ScrnInfoPtr pScrn,int clock,unsigned char * p2b,unsigned char * p2c)39 SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, unsigned char *p2b, unsigned char *p2c)
40 {
41    int          out_n, out_dn, out_div, out_sbit, out_scale;
42    unsigned int vclk[5];
43 
44 #define Midx         0
45 #define Nidx         1
46 #define VLDidx       2
47 #define Pidx         3
48 #define PSNidx       4
49 
50    if(SiS_compute_vclk(clock, &out_n, &out_dn, &out_div, &out_sbit, &out_scale)) {
51       (*p2b) = (out_div == 2) ? 0x80 : 0x00;
52       (*p2b) |= ((out_n - 1) & 0x7f);
53       (*p2c) = (out_dn - 1) & 0x1f;
54       (*p2c) |= (((out_scale - 1) & 3) << 5);
55       (*p2c) |= ((out_sbit & 0x01) << 7);
56 #ifdef TWDEBUG
57       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sb %d sc %d\n",
58         	 clock, out_n, out_dn, out_div, out_sbit, out_scale);
59 #endif
60    } else {
61       SiSCalcClock(pScrn, clock, 2, vclk);
62       (*p2b) = (vclk[VLDidx] == 2) ? 0x80 : 0x00;
63       (*p2b) |= (vclk[Midx] - 1) & 0x7f;
64       (*p2c) = (vclk[Nidx] - 1) & 0x1f;
65       if(vclk[Pidx] <= 4) {
66 	 /* postscale 1,2,3,4 */
67 	 (*p2c) |= ((vclk[Pidx] - 1) & 3) << 5;
68       } else {
69 	 /* postscale 6,8 */
70 	 (*p2c) |= (((vclk[Pidx] / 2) - 1) & 3) << 5;
71 	 (*p2c) |= 0x80;
72       }
73 #ifdef TWDEBUG
74       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sc %d\n",
75 		clock, vclk[Midx], vclk[Nidx], vclk[VLDidx], vclk[Pidx]);
76 #endif
77    }
78 }
79 
80 unsigned short
SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn,DisplayModePtr mode,unsigned int VBFlags)81 SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
82 {
83    SISPtr pSiS = SISPTR(pScrn);
84    int    depth = pSiS->CurrentLayout.bitsPerPixel;
85 
86    pSiS->SiS_Pr->CModeFlag = 0;
87 
88    pSiS->SiS_Pr->CDClock = mode->Clock;
89 
90    pSiS->SiS_Pr->CHDisplay = mode->HDisplay;
91    pSiS->SiS_Pr->CHSyncStart = mode->HSyncStart;
92    pSiS->SiS_Pr->CHSyncEnd = mode->HSyncEnd;
93    pSiS->SiS_Pr->CHTotal = mode->HTotal;
94 
95    pSiS->SiS_Pr->CVDisplay = mode->VDisplay;
96    pSiS->SiS_Pr->CVSyncStart = mode->VSyncStart;
97    pSiS->SiS_Pr->CVSyncEnd = mode->VSyncEnd;
98    pSiS->SiS_Pr->CVTotal = mode->VTotal;
99 
100    pSiS->SiS_Pr->CFlags = mode->Flags;
101 
102    if(pSiS->SiS_Pr->CFlags & V_INTERLACE) {
103       pSiS->SiS_Pr->CVDisplay >>= 1;
104       pSiS->SiS_Pr->CVSyncStart >>= 1;
105       pSiS->SiS_Pr->CVSyncEnd >>= 1;
106       pSiS->SiS_Pr->CVTotal >>= 1;
107    } else if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) {
108       pSiS->SiS_Pr->CVDisplay <<= 1;
109       pSiS->SiS_Pr->CVSyncStart <<= 1;
110       pSiS->SiS_Pr->CVSyncEnd <<= 1;
111       pSiS->SiS_Pr->CVTotal <<= 1;
112    }
113 
114    pSiS->SiS_Pr->CHBlankStart = pSiS->SiS_Pr->CHDisplay;
115    pSiS->SiS_Pr->CHBlankEnd = pSiS->SiS_Pr->CHTotal;
116    pSiS->SiS_Pr->CVBlankStart = pSiS->SiS_Pr->CVSyncStart - 1;
117    pSiS->SiS_Pr->CVBlankEnd = pSiS->SiS_Pr->CVTotal;
118 
119    if((!(mode->type & M_T_BUILTIN)) && (mode->HDisplay <= 512)) {
120       pSiS->SiS_Pr->CModeFlag |= HalfDCLK;
121       pSiS->SiS_Pr->CDClock <<= 1;
122    }
123 
124    /* Note: For CRT2, HDisplay, HSync* and HTotal must be shifted left
125     * in HalfDCLK mode.
126     */
127 
128    SiS_MakeClockRegs(pScrn, pSiS->SiS_Pr->CDClock, &pSiS->SiS_Pr->CSR2B, &pSiS->SiS_Pr->CSR2C);
129 
130    pSiS->SiS_Pr->CSRClock = (pSiS->SiS_Pr->CDClock / 1000) + 1;
131 
132    SiS_CalcCRRegisters(pSiS->SiS_Pr, depth);
133 
134    switch(depth) {
135    case  8: pSiS->SiS_Pr->CModeFlag |= 0x223b; break;
136    case 16: pSiS->SiS_Pr->CModeFlag |= 0x227d; break;
137    case 32: pSiS->SiS_Pr->CModeFlag |= 0x22ff; break;
138    default: return 0;
139    }
140 
141    if(pSiS->SiS_Pr->CFlags & V_DBLSCAN)
142       pSiS->SiS_Pr->CModeFlag |= DoubleScanMode;
143 
144    if((pSiS->SiS_Pr->CVDisplay >= 1024)	||
145       (pSiS->SiS_Pr->CVTotal >= 1024)   ||
146       (pSiS->SiS_Pr->CHDisplay >= 1024))
147       pSiS->SiS_Pr->CModeFlag |= LineCompareOff;
148 
149    pSiS->SiS_Pr->CInfoFlag = 0x0007;
150 
151    if(pSiS->SiS_Pr->CFlags & V_NHSYNC)
152       pSiS->SiS_Pr->CInfoFlag |= 0x4000;
153 
154    if(pSiS->SiS_Pr->CFlags & V_NVSYNC)
155       pSiS->SiS_Pr->CInfoFlag |= 0x8000;
156 
157    if(pSiS->SiS_Pr->CFlags & V_INTERLACE)
158       pSiS->SiS_Pr->CInfoFlag |= InterlaceMode;
159 
160    pSiS->SiS_Pr->UseCustomMode = TRUE;
161 #ifdef TWDEBUG
162    xf86DrvMsg(0, X_INFO, "Custom mode %dx%d:\n",
163 	pSiS->SiS_Pr->CHDisplay,pSiS->SiS_Pr->CVDisplay);
164    xf86DrvMsg(0, X_INFO, "Modeflag %04x, Infoflag %04x\n",
165 	pSiS->SiS_Pr->CModeFlag, pSiS->SiS_Pr->CInfoFlag);
166    xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
167 	pSiS->SiS_Pr->CCRT1CRTC[0], pSiS->SiS_Pr->CCRT1CRTC[1],
168 	pSiS->SiS_Pr->CCRT1CRTC[2], pSiS->SiS_Pr->CCRT1CRTC[3],
169 	pSiS->SiS_Pr->CCRT1CRTC[4], pSiS->SiS_Pr->CCRT1CRTC[5],
170 	pSiS->SiS_Pr->CCRT1CRTC[6], pSiS->SiS_Pr->CCRT1CRTC[7]);
171    xf86DrvMsg(0, X_INFO, "  0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
172 	pSiS->SiS_Pr->CCRT1CRTC[8], pSiS->SiS_Pr->CCRT1CRTC[9],
173 	pSiS->SiS_Pr->CCRT1CRTC[10], pSiS->SiS_Pr->CCRT1CRTC[11],
174 	pSiS->SiS_Pr->CCRT1CRTC[12], pSiS->SiS_Pr->CCRT1CRTC[13],
175 	pSiS->SiS_Pr->CCRT1CRTC[14], pSiS->SiS_Pr->CCRT1CRTC[15]);
176    xf86DrvMsg(0, X_INFO, "  0x%02x}},\n", pSiS->SiS_Pr->CCRT1CRTC[16]);
177    xf86DrvMsg(0, X_INFO, "Clock: 0x%02x, 0x%02x, %d\n",
178 	pSiS->SiS_Pr->CSR2B, pSiS->SiS_Pr->CSR2C, pSiS->SiS_Pr->CSRClock);
179 #endif
180    return 1;
181 }
182 
183 /* Build a list of supported modes:
184  * Built-in modes for which we have all data are M_T_DEFAULT,
185  * modes derived from DDC or database data are M_T_BUILTIN
186  */
187 DisplayModePtr
SiSBuildBuiltInModeList(ScrnInfoPtr pScrn,BOOLEAN includelcdmodes,BOOLEAN isfordvi,BOOLEAN fakecrt2modes,BOOLEAN IsForCRT2)188 SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi,
189 			BOOLEAN fakecrt2modes, BOOLEAN IsForCRT2)
190 {
191    SISPtr	  pSiS = SISPTR(pScrn);
192    unsigned char  sr2b, sr2c;
193    float	  num, denum, postscalar, divider;
194    int		  i, j, k, l, index, vclkindex, UseWide;
195    DisplayModePtr new = NULL, current = NULL, first = NULL;
196    BOOLEAN	  done = FALSE, IsHDCLK;
197 #if 0
198    DisplayModePtr backup = NULL;
199 #endif
200 
201    pSiS->backupmodelist = NULL;
202    pSiS->AddedPlasmaModes = FALSE;
203 
204    UseWide = pSiS->SiS_Pr->SiS_UseWide;
205    if(IsForCRT2) UseWide = pSiS->SiS_Pr->SiS_UseWideCRT2;
206 
207    if(!SiSInitPtr(pSiS->SiS_Pr)) return NULL;
208 
209    i = 0;
210    while(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag != 0xFFFF) {
211 
212       if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & HaveWideTiming) {
213 	 if(UseWide == 1) {
214 	    if((pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRT1CRTC_WIDE == 0xff) &&
215 	       (pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRTVCLK_WIDE == 0xff)) {
216 	       i++;
217 	       continue;
218 	    }
219 	 } else {
220 	    if((pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRT1CRTC_NORM == 0xff) &&
221 	       (pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRTVCLK_NORM == 0xff)) {
222 	       i++;
223 	       continue;
224 	    }
225 	 }
226       }
227 
228       index = SiS_GetRefCRT1CRTC(pSiS->SiS_Pr, i, UseWide);
229       if(fakecrt2modes) {
230 	 if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_FakeCRT2CRTC) {
231 	    index = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_FakeCRT2CRTC;
232 	 }
233       }
234 
235       /* 0x5a (320x240) for FTSN - skip, is bad for CRT1 */
236       if(pSiS->SiS_Pr->SiS_RefIndex[i].ModeID == 0x5a)  {
237 	 i++;
238 	 continue;
239       }
240 
241       if(!(new = malloc(sizeof(DisplayModeRec)))) return first;
242       memset(new, 0, sizeof(DisplayModeRec));
243       if(!(new->name = malloc(10))) {
244 	 free(new);
245 	 return first;
246       }
247       if(!first) first = new;
248       if(current) {
249 	 current->next = new;
250 	 new->prev = current;
251       }
252 
253       current = new;
254 
255       sprintf((char *)current->name, "%hu%hu", pSiS->SiS_Pr->SiS_RefIndex[i].XRes,
256 				      pSiS->SiS_Pr->SiS_RefIndex[i].YRes);
257 
258       current->status = MODE_OK;
259 
260       current->type = M_T_DEFAULT;
261 
262       vclkindex = SiS_GetRefCRTVCLK(pSiS->SiS_Pr, i, UseWide);
263       if(fakecrt2modes) {
264 	 if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_FakeCRT2Clk) {
265 	    vclkindex = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_FakeCRT2Clk;
266 	 }
267       }
268 
269       sr2b = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
270       sr2c = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
271 
272       divider = (sr2b & 0x80) ? 2.0 : 1.0;
273       postscalar = (sr2c & 0x80) ?
274               ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0) : (((sr2c >> 5) & 0x03) + 1.0);
275       num = (sr2b & 0x7f) + 1.0;
276       denum = (sr2c & 0x1f) + 1.0;
277 
278 #ifdef TWDEBUG
279       xf86DrvMsg(0, X_INFO, "------------\n");
280       xf86DrvMsg(0, X_INFO, "sr2b: %x sr2c %x div %f ps %f num %f denum %f\n",
281          sr2b, sr2c, divider, postscalar, num, denum);
282 #endif
283 
284       current->Clock = (int)(14318 * (divider / postscalar) * (num / denum));
285 
286       SiS_Generic_ConvertCRData(pSiS->SiS_Pr,
287 			(unsigned char *)&pSiS->SiS_Pr->SiS_CRT1Table[index].CR[0],
288 			pSiS->SiS_Pr->SiS_RefIndex[i].XRes,
289 			pSiS->SiS_Pr->SiS_RefIndex[i].YRes, current);
290 
291       if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x4000)
292 	  current->Flags |= V_NHSYNC;
293       else
294 	  current->Flags |= V_PHSYNC;
295 
296       if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x8000)
297 	  current->Flags |= V_NVSYNC;
298       else
299 	  current->Flags |= V_PVSYNC;
300 
301       if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x0080)
302           current->Flags |= V_INTERLACE;
303 
304       j = 0;
305       IsHDCLK = FALSE;
306       while(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) {
307 	  if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID ==
308 				pSiS->SiS_Pr->SiS_RefIndex[i].ModeID) {
309 	     if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) {
310 		  current->Flags |= V_DBLSCAN;
311 	      }
312 	      if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & HalfDCLK) {
313 		  IsHDCLK = TRUE;
314 	      }
315 	      break;
316 	  }
317 	  j++;
318       }
319 
320       if(current->Flags & V_INTERLACE) {
321 	 current->VDisplay <<= 1;
322 	 current->VSyncStart <<= 1;
323 	 current->VSyncEnd <<= 1;
324 	 current->VTotal <<= 1;
325 	 current->VTotal |= 1;
326       }
327 
328       if(IsHDCLK) {
329 	 current->Clock >>= 1;
330       }
331 
332       if(current->Flags & V_DBLSCAN) {
333 	 current->VDisplay >>= 1;
334 	 current->VSyncStart >>= 1;
335 	 current->VSyncEnd >>= 1;
336 	 current->VTotal >>= 1;
337       }
338 
339 #ifdef TWDEBUG
340       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
341 	"Built-in: %s %.2f %d %d %d %d %d %d %d %d\n",
342 	current->name, (float)current->Clock / 1000,
343 	current->HDisplay, current->HSyncStart, current->HSyncEnd, current->HTotal,
344 	current->VDisplay, current->VSyncStart, current->VSyncEnd, current->VTotal);
345 #endif
346 
347       i++;
348    }
349 
350    /* Add non-standard LCD modes for panel's detailed timings */
351 
352    if(!includelcdmodes) return first;
353 
354    if(pSiS->SiS_Pr->CP_Vendor) {
355       xf86DrvMsg(0, X_INFO, "Checking database for vendor %x, product %x\n",
356          pSiS->SiS_Pr->CP_Vendor, pSiS->SiS_Pr->CP_Product);
357    }
358 
359    i = 0;
360    while((!done) && (SiS_PlasmaTable[i].vendor) && (pSiS->SiS_Pr->CP_Vendor)) {
361 
362      if(SiS_PlasmaTable[i].vendor == pSiS->SiS_Pr->CP_Vendor) {
363 
364 	for(j=0; j<SiS_PlasmaTable[i].productnum; j++) {
365 
366 	    if(SiS_PlasmaTable[i].product[j] == pSiS->SiS_Pr->CP_Product) {
367 
368 	       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
369 		  "Identified %s panel, adding specific modes\n",
370 		  SiS_PlasmaTable[i].plasmaname);
371 
372 	       for(k=0; k<SiS_PlasmaTable[i].modenum; k++) {
373 
374 		  if(isfordvi) {
375 		     if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x80)) continue;
376 		  } else {
377 		     if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x40)) continue;
378 		  }
379 
380 		  l = SiS_PlasmaTable[i].plasmamodes[k] & 0x3f;
381 
382 		  if(!(pSiS->VBFlags2 & VB2_LCDOVER1280BRIDGE)) {
383 		     if(isfordvi) {
384 		        if(SiS_PlasmaMode[l].VDisplay > 1024) continue;
385 		     }
386 		  }
387 
388 		  if(!(new = malloc(sizeof(DisplayModeRec)))) return first;
389 
390 		  memset(new, 0, sizeof(DisplayModeRec));
391 		  if(!(new->name = malloc(12))) {
392 		     free(new);
393 		     return first;
394 		  }
395 		  if(!first) first = new;
396 		  if(current) {
397 		     current->next = new;
398 		     new->prev = current;
399 		  }
400 
401 		  current = new;
402 
403 		  pSiS->AddedPlasmaModes = TRUE;
404 
405 		  strcpy((char *)current->name, SiS_PlasmaMode[l].name);
406 
407 		  current->status = MODE_OK;
408 
409 		  current->type = M_T_BUILTIN;
410 
411 		  current->Clock = SiS_PlasmaMode[l].clock;
412 		  current->SynthClock = current->Clock;
413 
414 		  current->HDisplay   = SiS_PlasmaMode[l].HDisplay;
415 		  current->HSyncStart = current->HDisplay + SiS_PlasmaMode[l].HFrontPorch;
416 		  current->HSyncEnd   = current->HSyncStart + SiS_PlasmaMode[l].HSyncWidth;
417 		  current->HTotal     = SiS_PlasmaMode[l].HTotal;
418 
419 		  current->VDisplay   = SiS_PlasmaMode[l].VDisplay;
420 		  current->VSyncStart = current->VDisplay + SiS_PlasmaMode[l].VFrontPorch;
421 		  current->VSyncEnd   = current->VSyncStart + SiS_PlasmaMode[l].VSyncWidth;
422 		  current->VTotal     = SiS_PlasmaMode[l].VTotal;
423 
424 		  current->CrtcHDisplay = current->HDisplay;
425 		  current->CrtcHBlankStart = current->HSyncStart;
426 		  current->CrtcHSyncStart = current->HSyncStart;
427 		  current->CrtcHSyncEnd = current->HSyncEnd;
428 		  current->CrtcHBlankEnd = current->HSyncEnd;
429 		  current->CrtcHTotal = current->HTotal;
430 
431 		  current->CrtcVDisplay = current->VDisplay;
432 		  current->CrtcVBlankStart = current->VSyncStart;
433 		  current->CrtcVSyncStart = current->VSyncStart;
434 		  current->CrtcVSyncEnd = current->VSyncEnd;
435 		  current->CrtcVBlankEnd = current->VSyncEnd;
436 		  current->CrtcVTotal = current->VTotal;
437 
438 		  if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_HSYNCP)
439 		     current->Flags |= V_PHSYNC;
440 		  else
441 		     current->Flags |= V_NHSYNC;
442 
443 		  if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_VSYNCP)
444 		     current->Flags |= V_PVSYNC;
445 		  else
446 		     current->Flags |= V_NVSYNC;
447 
448 		  if(current->HDisplay > pSiS->LCDwidth)
449 		     pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX = current->HDisplay;
450 		  if(current->VDisplay > pSiS->LCDheight)
451 		     pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY = current->VDisplay;
452 
453 		  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
454 			"\tAdding \"%s\" to list of built-in modes\n", current->name);
455 
456 	       }
457 	       done = TRUE;
458 	       break;
459 	    }
460 	}
461      }
462 
463      i++;
464 
465    }
466 
467    if(pSiS->SiS_Pr->CP_HaveCustomData) {
468 
469       for(i=0; i<7; i++) {
470 
471 	 if(pSiS->SiS_Pr->CP_DataValid[i]) {
472 
473 	    if(!(new = malloc(sizeof(DisplayModeRec)))) return first;
474 
475 	    memset(new, 0, sizeof(DisplayModeRec));
476 	    if(!(new->name = malloc(10))) {
477 	       free(new);
478 	       return first;
479 	    }
480 	    if(!first) first = new;
481 	    if(current) {
482 	       current->next = new;
483 	       new->prev = current;
484 	    }
485 
486 	    current = new;
487 
488 	    sprintf((char *)current->name, "%dx%d", pSiS->SiS_Pr->CP_HDisplay[i],
489 						    pSiS->SiS_Pr->CP_VDisplay[i]);
490 
491 	    current->status = MODE_OK;
492 
493 	    current->type = M_T_BUILTIN;
494 
495 	    current->Clock = pSiS->SiS_Pr->CP_Clock[i];
496 	    current->SynthClock = current->Clock;
497 
498 	    current->HDisplay   = pSiS->SiS_Pr->CP_HDisplay[i];
499 	    current->HSyncStart = pSiS->SiS_Pr->CP_HSyncStart[i];
500 	    current->HSyncEnd   = pSiS->SiS_Pr->CP_HSyncEnd[i];
501 	    current->HTotal     = pSiS->SiS_Pr->CP_HTotal[i];
502 
503 	    current->VDisplay   = pSiS->SiS_Pr->CP_VDisplay[i];
504 	    current->VSyncStart = pSiS->SiS_Pr->CP_VSyncStart[i];
505 	    current->VSyncEnd   = pSiS->SiS_Pr->CP_VSyncEnd[i];
506 	    current->VTotal     = pSiS->SiS_Pr->CP_VTotal[i];
507 
508 	    current->CrtcHDisplay = current->HDisplay;
509 	    current->CrtcHBlankStart = pSiS->SiS_Pr->CP_HBlankStart[i];
510 	    current->CrtcHSyncStart = current->HSyncStart;
511 	    current->CrtcHSyncEnd = current->HSyncEnd;
512 	    current->CrtcHBlankEnd = pSiS->SiS_Pr->CP_HBlankEnd[i];
513 	    current->CrtcHTotal = current->HTotal;
514 
515 	    current->CrtcVDisplay = current->VDisplay;
516 	    current->CrtcVBlankStart = pSiS->SiS_Pr->CP_VBlankStart[i];
517 	    current->CrtcVSyncStart = current->VSyncStart;
518 	    current->CrtcVSyncEnd = current->VSyncEnd;
519 	    current->CrtcVBlankEnd = pSiS->SiS_Pr->CP_VBlankEnd[i];
520 	    current->CrtcVTotal = current->VTotal;
521 
522 	    if(pSiS->SiS_Pr->CP_SyncValid[i]) {
523 	       if(pSiS->SiS_Pr->CP_HSync_P[i])
524 		  current->Flags |= V_PHSYNC;
525 	       else
526 		  current->Flags |= V_NHSYNC;
527 
528 	       if(pSiS->SiS_Pr->CP_VSync_P[i])
529 		  current->Flags |= V_PVSYNC;
530 	       else
531 		  current->Flags |= V_NVSYNC;
532 	    } else {
533 	       /* No sync data? Use positive sync... */
534 	       current->Flags |= V_PHSYNC;
535 	       current->Flags |= V_PVSYNC;
536 	    }
537 	 }
538       }
539    }
540 
541    return first;
542 
543 }
544 
545 /* Translate a mode number into the VESA pendant */
546 int
SiSTranslateToVESA(ScrnInfoPtr pScrn,int modenumber)547 SiSTranslateToVESA(ScrnInfoPtr pScrn, int modenumber)
548 {
549    SISPtr pSiS = SISPTR(pScrn);
550    int    i = 0;
551 
552    if(!SiSInitPtr(pSiS->SiS_Pr)) return -1;
553 
554    if(modenumber <= 0x13) return modenumber;
555 
556 #ifdef SIS315H
557    if(pSiS->ROM661New) { /* Not XGI! */
558       while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) {
559 	 if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) {
560 	    return (int)SiS_EModeIDTable661[i].Ext_VESAID;
561 	 }
562 	 i++;
563       }
564    } else {
565 #endif
566       while(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID != 0xff) {
567 	 if(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID == modenumber) {
568 	    return (int)pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID;
569 	 }
570 	 i++;
571       }
572 #ifdef SIS315H
573    }
574 #endif
575    return -1;
576 }
577 
578 /* Translate a new (SiS or XGI) BIOS mode number into the driver's pendant */
579 int
SiSTranslateToOldMode(int modenumber)580 SiSTranslateToOldMode(int modenumber)
581 {
582 #ifdef SIS315H
583    int    i = 0;
584 
585    while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) {
586       if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) {
587 	 if(SiS_EModeIDTable661[i].Ext_MyModeID)
588 	    return (int)SiS_EModeIDTable661[i].Ext_MyModeID;
589 	 else
590 	    return modenumber;
591       }
592       i++;
593    }
594 #endif
595    return modenumber;
596 }
597 
598 BOOLEAN
SiS_GetPanelID(struct SiS_Private * SiS_Pr)599 SiS_GetPanelID(struct SiS_Private *SiS_Pr)
600 {
601   unsigned short tempax, tempbx, temp;
602   static const unsigned short PanelTypeTable300[16] = {
603       0xc101, 0xc117, 0x0121, 0xc135, 0xc142, 0xc152, 0xc162, 0xc072,
604       0xc181, 0xc192, 0xc1a1, 0xc1b6, 0xc1c2, 0xc0d2, 0xc1e2, 0xc1f2
605   };
606   static const unsigned short PanelTypeTable31030x[16] = {
607       0xc102, 0xc112, 0x0122, 0xc132, 0xc142, 0xc152, 0xc169, 0xc179,
608       0x0189, 0xc192, 0xc1a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
609   };
610   static const unsigned short PanelTypeTable310LVDS[16] = {
611       0xc111, 0xc122, 0xc133, 0xc144, 0xc155, 0xc166, 0xc177, 0xc188,
612       0xc199, 0xc0aa, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
613   };
614 
615   if(SiS_Pr->ChipType < SIS_315H) {
616 
617      tempbx = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18);
618      if(!(tempbx & 0x10)) {
619 	if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
620 	   tempbx = 0;
621 	   temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x38);
622 	   if(temp & 0x40) tempbx |= 0x08;
623 	   if(temp & 0x20) tempbx |= 0x02;
624 	   if(temp & 0x01) tempbx |= 0x01;
625 	   temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x39);
626 	   if(temp & 0x80) tempbx |= 0x04;
627 	} else {
628 	   return FALSE;
629 	}
630      }
631      tempbx = PanelTypeTable300[(tempbx & 0x0f)] | LCDSync;
632      SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,tempbx);
633      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),(tempbx >> 8));
634 
635   } else {
636 
637      if(SiS_Pr->ChipType >= SIS_661) return FALSE;
638 
639      tempax = (SiS_GetReg(SiS_Pr->SiS_P3c4,0x1a) & 0x1e) >> 1;
640      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
641 	if(tempax == 0) return FALSE;
642 	tempbx = PanelTypeTable310LVDS[tempax - 1];
643 	temp = tempax & 0xff;
644      } else {
645 	tempbx = PanelTypeTable31030x[tempax];
646 	temp = tempbx & 0xff;
647      }
648      SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp);
649      tempbx >>= 8;
650      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),(tempbx & 0xc1));
651      if(SiS_Pr->SiS_VBType & VB_SISVB) {
652 	SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x39,0xfb,(tempbx & 0x04));
653      }
654 
655   }
656   return TRUE;
657 }
658 
659 /* LCD and VGA2 detection */
660 
661 static BOOLEAN
checkedid1(unsigned char * buffer)662 checkedid1(unsigned char *buffer)
663 {
664    /* Check header */
665    if((buffer[0] != 0x00) ||
666       (buffer[1] != 0xff) ||
667       (buffer[2] != 0xff) ||
668       (buffer[3] != 0xff) ||
669       (buffer[4] != 0xff) ||
670       (buffer[5] != 0xff) ||
671       (buffer[6] != 0xff) ||
672       (buffer[7] != 0x00))
673       return FALSE;
674 
675    /* Check EDID version and revision */
676    if((buffer[0x12] != 1) || (buffer[0x13] > 4)) return FALSE;
677 
678    /* Check week of manufacture for sanity */
679    if(buffer[0x10] > 54) return FALSE;
680 
681    /* Check year of manufacture for sanity */
682    if(buffer[0x11] > 40) return FALSE;
683 
684    return TRUE;
685 }
686 
687 static BOOLEAN
checkedid2(unsigned char * buffer)688 checkedid2(unsigned char *buffer)
689 {
690    unsigned short year = buffer[6] | (buffer[7] << 8);
691 
692    /* Check EDID version */
693    if((buffer[0] & 0xf0) != 0x20) return FALSE;
694 
695    /* Check week of manufacture for sanity */
696    if(buffer[5] > 54) return FALSE;
697 
698    /* Check year of manufacture for sanity */
699    if((year != 0) && ((year < 1990) || (year > 2030))) return FALSE;
700 
701    return TRUE;
702 }
703 
704 static int
SiS_FindPanelFromDB(SISPtr pSiS,unsigned short panelvendor,unsigned short panelproduct,int * maxx,int * maxy,int * prefx,int * prefy)705 SiS_FindPanelFromDB(SISPtr pSiS, unsigned short panelvendor, unsigned short panelproduct,
706 			int *maxx, int *maxy, int *prefx, int *prefy)
707 {
708    int i, j;
709    BOOLEAN done = FALSE;
710 
711    i = 0;
712    while((!done) && (SiS_PlasmaTable[i].vendor) && panelvendor) {
713       if(SiS_PlasmaTable[i].vendor == panelvendor) {
714 	 for(j=0; j<SiS_PlasmaTable[i].productnum; j++) {
715 	    if(SiS_PlasmaTable[i].product[j] == panelproduct) {
716 	       if(SiS_PlasmaTable[i].maxx && SiS_PlasmaTable[i].maxy) {
717 		  (*maxx) = (int)SiS_PlasmaTable[i].maxx;
718 		  (*maxy) = (int)SiS_PlasmaTable[i].maxy;
719 		  (*prefx) = (int)SiS_PlasmaTable[i].prefx;
720 		  (*prefy) = (int)SiS_PlasmaTable[i].prefy;
721 		  done = TRUE;
722 		  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
723 			"Identified %s, correcting max X res %d, max Y res %d\n",
724 			 SiS_PlasmaTable[i].plasmaname,
725 			 SiS_PlasmaTable[i].maxx, SiS_PlasmaTable[i].maxy);
726 		  break;
727 	       }
728 	    }
729 	 }
730       }
731       i++;
732    }
733    return (done) ? 1 : 0;
734 }
735 
736 /* Sense the LCD parameters (CR36, CR37) via DDC */
737 /* SiS TMDS bridges only */
738 unsigned short
SiS_SenseLCDDDC(struct SiS_Private * SiS_Pr,SISPtr pSiS)739 SiS_SenseLCDDDC(struct SiS_Private *SiS_Pr, SISPtr pSiS)
740 {
741    unsigned short DDCdatatype, paneltype, adapternum, flag, xres=0, yres=0;
742    unsigned short index, myindex, lumsize, numcodes, panelvendor, panelproduct;
743    int maxx=0, maxy=0, prefx=0, prefy=0;
744    unsigned char cr37=0, seekcode;
745    BOOLEAN checkexpand = FALSE;
746    BOOLEAN havesync = FALSE;
747    BOOLEAN indb = FALSE;
748    int retry, i;
749    int panel1280x960 = (pSiS->VGAEngine == SIS_315_VGA) ? Panel310_1280x960 : Panel300_1280x960;
750    unsigned char buffer[256];
751 
752    for(i=0; i<7; i++) SiS_Pr->CP_DataValid[i] = FALSE;
753    SiS_Pr->CP_HaveCustomData = FALSE;
754    SiS_Pr->CP_MaxX = SiS_Pr->CP_MaxY = SiS_Pr->CP_MaxClock = 0;
755    SiS_Pr->CP_PreferredX = SiS_Pr->CP_PreferredY = 0;
756    SiS_Pr->CP_PreferredIndex = -1;
757    SiS_Pr->CP_PrefClock = 0;
758    SiS_Pr->PanelSelfDetected = FALSE;
759 
760    if(!(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE)) return 0;
761    if(pSiS->VBFlags2 & VB2_30xBDH) return 0;
762 
763    /* Specific for XGI_40/Rev 2/A01 (XGI V3XT A01): This card has CRT1's
764     * and CRT2's DDC ports physically connected to each other. There
765     * is no connection to the video bridge's DDC port, both DDC
766     * channels are routed to the GPU. Smart. If both CRT1 (CRT) and
767     * CRT2 (VGA or LCD) are connected, DDC will fail. Hence, no
768     * reliable panel detection here...
769     */
770    adapternum = 1;
771    if(SiS_Pr->DDCPortMixup) adapternum = 0;
772 
773    if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, adapternum, 0, FALSE, pSiS->VBFlags2) == 0xFFFF)
774       return 0;
775 
776    SiS_Pr->SiS_DDC_SecAddr = 0x00;
777 
778    /* Probe supported DA's */
779    flag = SiS_ProbeDDC(SiS_Pr);
780 #ifdef TWDEBUG
781    xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
782 	"CRT2 DDC capabilities 0x%x\n", flag);
783 #endif
784    if(flag & 0x10) {
785       SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;	/* EDID V2 (FP) */
786       DDCdatatype = 4;
787    } else if(flag & 0x08) {
788       SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;	/* EDID V2 (P&D-D Monitor) */
789       DDCdatatype = 3;
790    } else if(flag & 0x02) {
791       SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;	/* EDID V1 */
792       DDCdatatype = 1;
793    } else return 0;				/* no DDC support (or no device attached) */
794 
795    /* Read the entire EDID */
796    retry = 2;
797    do {
798       if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) {
799 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
800 		"CRT2: DDC read failed (attempt %d), %s\n",
801 		(3-retry), (retry == 1) ? "giving up" : "retrying");
802 	 retry--;
803 	 if(retry == 0) return 0xFFFF;
804       } else break;
805    } while(1);
806 
807 #ifdef TWDEBUG
808    for(i=0; i<256; i+=16) {
809       xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
810 	"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
811 	buffer[i],    buffer[i+1], buffer[i+2], buffer[i+3],
812 	buffer[i+4],  buffer[i+5], buffer[i+6], buffer[i+7],
813 	buffer[i+8],  buffer[i+9], buffer[i+10], buffer[i+11],
814 	buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]);
815    }
816 #endif
817 
818    /* Analyze EDID and retrieve LCD panel information */
819    paneltype = 0;
820    switch(DDCdatatype) {
821    case 1:							/* Analyze EDID V1 */
822       /* Catch a few clear cases: */
823       if(!(checkedid1(buffer))) {
824 	xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
825 	 	"LCD sense: EDID corrupt\n");
826 	 return 0;
827       }
828 
829       if(!(buffer[0x14] & 0x80)) {
830 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
831 		"LCD sense: Attached display expects analog input (0x%02x)\n",
832 		buffer[0x14]);
833 	 return 0;
834       }
835 
836       /* Save given gamma */
837       pSiS->CRT2LCDMonitorGamma = (buffer[0x17] + 100) * 10;
838 
839       /* Now analyze the first Detailed Timing Block and see
840        * if the preferred timing mode is stored there. If so,
841        * check if this is a standard panel for which we already
842        * know the timing.
843        */
844 
845       paneltype = Panel_Custom;
846       checkexpand = FALSE;
847 
848       panelvendor = buffer[9] | (buffer[8] << 8);
849       panelproduct = buffer[10] | (buffer[11] << 8);
850 
851       /* Overrule bogus preferred modes from database */
852       if((indb = SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) {
853 	 if(prefx) SiS_Pr->CP_PreferredX = xres = prefx;
854 	 if(prefy) SiS_Pr->CP_PreferredY = yres = prefy;
855       }
856 
857       if(buffer[0x18] & 0x02) {
858 
859 	 unsigned short pclk = (buffer[0x36] | (buffer[0x37] << 8));
860 	 unsigned short phb  = (buffer[0x39] | ((buffer[0x3a] & 0x0f) << 8));
861 	 unsigned short pvb  = (buffer[0x3c] | ((buffer[0x3d] & 0x0f) << 8));
862 
863 	 if(!xres) SiS_Pr->CP_PreferredX = xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
864 	 if(!yres) SiS_Pr->CP_PreferredY = yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
865 
866 	 switch(xres) {
867 	    case 1024:
868 	        if(yres == 768) {
869 		   paneltype = Panel_1024x768;
870 		   checkexpand = TRUE;
871 	        }
872 	        break;
873 	    case 1280:
874 		if(yres == 1024) {
875 		   paneltype = Panel_1280x1024;
876 		   checkexpand = TRUE;
877 		} else if(yres == 960) {
878 		   paneltype = panel1280x960;
879 		} else if(yres == 768) {
880 		   if( (pclk == 8100) &&
881 		       (phb == (1688 - 1280)) &&
882 		       (pvb == (802 - 768)) ) {
883 		      paneltype = Panel_1280x768;
884 		      checkexpand = FALSE;
885 		      cr37 |= 0x10;
886 		   }
887 		} else if(yres == 800) {
888 		   if( (pclk == 6900) &&
889 		       (phb == (1408 - 1280)) &&
890 		       (pvb == (816 - 800)) ) {
891 		      paneltype = Panel_1280x800;
892 		   }
893 		}
894 		break;
895 	    case 1400:
896 		if(pSiS->VGAEngine == SIS_315_VGA) {
897 		   if(yres == 1050) {
898 		      paneltype = Panel310_1400x1050;
899 		      checkexpand = TRUE;
900 		   }
901 		}
902 		break;
903 	    case 1600:
904 		if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_30xC)) {
905 		   if(yres == 1200) {
906 		      if( (pclk == 16200) &&
907 			  (phb == (2160 - 1600)) &&
908 			  (pvb == (1250 - 1200)) ) {
909 			 paneltype = Panel310_1600x1200;
910 			 checkexpand = TRUE;
911 		      }
912 		   }
913 		}
914 		break;
915 	 }
916 
917 	 /* Save sync: This is used if "Pass 1:1" is off; in this case
918 	  * we always use the panel's native mode = this "preferred mode"
919 	  * we just have been analysing. Hence, we also need its sync.
920 	  */
921 	 if((buffer[0x47] & 0x18) == 0x18) {
922 	    cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
923 	    havesync = TRUE;
924 	 } else {
925 	    /* What now? There is no digital separate output timing... */
926 	    xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
927 		   "LCD sense: Unable to retrieve Sync polarity information\n");
928 	    cr37 |= 0xc0;  /* Default */
929 	 }
930 
931       }
932 
933       /* Check against our database; eg. Sanyo Z2 projector reports
934        * 1024x768 as preferred mode, although it supports 1280x720
935        * natively in non-HDCP mode. Treat such wrongly reporting
936        * panels as custom and fixup actual maximum resolutions.
937        */
938       if(paneltype != Panel_Custom) {
939 	 if(indb) {
940 	    paneltype = Panel_Custom;
941 	    SiS_Pr->CP_MaxX = maxx;
942 	    SiS_Pr->CP_MaxY = maxy;
943 	    /* Leave preferred unchanged (MUST contain a valid mode!) */
944 	 }
945       }
946 
947       /* If we still don't know what panel this is, we take it
948        * as a custom panel and derive the timing data from the
949        * detailed timing blocks
950        */
951       if(paneltype == Panel_Custom) {
952 
953 	 int i, temp, base = 0x36;
954 	 unsigned long estpack;
955 	 static const unsigned short estx[] = {
956 		720, 720, 640, 640, 640, 640, 800, 800,
957 		800, 800, 832,1024,1024,1024,1024,1280,
958 		1152
959 	 };
960 	 static const unsigned short esty[] = {
961 		400, 400, 480, 480, 480, 480, 600, 600,
962 		600, 600, 624, 768, 768, 768, 768,1024,
963 		870
964 	 };
965 	 static const int estclk[] = {
966 		    0,     0, 25100,   0, 31500, 31500, 36100, 40000,
967 		50100, 49500,     0,   0, 65100, 75200, 78700,135200,
968 		0
969 	 };
970 
971 	 paneltype = 0;
972 	 SiS_Pr->CP_Supports64048075 = TRUE;
973 
974 	 /* Find the maximum resolution */
975 
976 	 /* 1. From Established timings */
977 	 estpack = (buffer[0x23] << 9) | (buffer[0x24] << 1) | ((buffer[0x25] >> 7) & 0x01);
978 	 for(i=16; i>=0; i--) {
979 	     if(estpack & (1 << i)) {
980 		if(estx[16 - i] > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = estx[16 - i];
981 		if(esty[16 - i] > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = esty[16 - i];
982 		if(estclk[16 - i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = estclk[16 - i];
983 	     }
984 	 }
985 
986 	 /* By default we drive the LCD at 75Hz in 640x480 mode; if
987 	  * the panel does not provide this mode, use 60hz
988 	  */
989 	 if(!(buffer[0x23] & 0x04)) SiS_Pr->CP_Supports64048075 = FALSE;
990 
991 	 /* 2. From Standard Timings */
992 	 for(i=0x26; i < 0x36; i+=2) {
993 	    if((buffer[i] != 0x01) && (buffer[i+1] != 0x01)) {
994 	       temp = (buffer[i] + 31) * 8;
995 	       if(temp > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = temp;
996 	       switch((buffer[i+1] & 0xc0) >> 6) {
997 	       case 0x03: temp = temp * 9 / 16; break;
998 	       case 0x02: temp = temp * 4 / 5;  break;
999 	       case 0x01: temp = temp * 3 / 4;  break;
1000 	       }
1001 	       if(temp > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = temp;
1002 	    }
1003 	 }
1004 
1005 	 /* Now extract the Detailed Timings and convert them into modes */
1006 
1007 	for(i = 0; i < 4; i++, base += 18) {
1008 
1009 	    /* Is this a detailed timing block or a monitor descriptor? */
1010 	    if(buffer[base] || buffer[base+1] || buffer[base+2]) {
1011 
1012 	       xres = buffer[base+2] | ((buffer[base+4] & 0xf0) << 4);
1013 	       yres = buffer[base+5] | ((buffer[base+7] & 0xf0) << 4);
1014 
1015 	       SiS_Pr->CP_HDisplay[i] = xres;
1016 	       SiS_Pr->CP_HSyncStart[i] = xres + (buffer[base+8] | ((buffer[base+11] & 0xc0) << 2));
1017 	       SiS_Pr->CP_HSyncEnd[i]   = SiS_Pr->CP_HSyncStart[i] + (buffer[base+9] | ((buffer[base+11] & 0x30) << 4));
1018 	       SiS_Pr->CP_HTotal[i] = xres + (buffer[base+3] | ((buffer[base+4] & 0x0f) << 8));
1019 	       SiS_Pr->CP_HBlankStart[i] = xres + 1;
1020 	       SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i];
1021 
1022 	       SiS_Pr->CP_VDisplay[i] = yres;
1023 	       SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[base+10] & 0xf0) >> 4) | ((buffer[base+11] & 0x0c) << 2));
1024 	       SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[base+10] & 0x0f) | ((buffer[base+11] & 0x03) << 4));
1025 	       SiS_Pr->CP_VTotal[i] = yres + (buffer[base+6] | ((buffer[base+7] & 0x0f) << 8));
1026 	       SiS_Pr->CP_VBlankStart[i] = yres + 1;
1027 	       SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i];
1028 
1029 	       SiS_Pr->CP_Clock[i] = (buffer[base] | (buffer[base+1] << 8)) * 10;
1030 
1031 	       SiS_Pr->CP_DataValid[i] = TRUE;
1032 
1033 	       /* Sort out invalid timings, interlace and too high clocks */
1034 	       if((SiS_Pr->CP_HDisplay[i] & 7)						  ||
1035 		  (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i])			  ||
1036 		  (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i])			  ||
1037 		  (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i])			  ||
1038 		  (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i])			  ||
1039 		  (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i])			  ||
1040 		  (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i])			  ||
1041 		  (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i])			  ||
1042 		  (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i])			  ||
1043 		  (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i])			  ||
1044 		  (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i])			  ||
1045 		  (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i])			  ||
1046 		  (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i])			  ||
1047 		  (((pSiS->VBFlags2 & VB2_30xC) && (SiS_Pr->CP_Clock[i] > 162500)) ||
1048 		   ((!(pSiS->VBFlags2 & VB2_30xC))        &&
1049 		    ( (SiS_Pr->CP_Clock[i] > 110500)  ||		/* TODO for 307 */
1050 		      (SiS_Pr->CP_VDisplay[i] > 1024) ||
1051 		      (SiS_Pr->CP_HDisplay[i] > 1600) )))				  ||
1052 		  (buffer[base+17] & 0x80)) {
1053 
1054 		  SiS_Pr->CP_DataValid[i] = FALSE;
1055 
1056 	       } else {
1057 
1058 		  SiS_Pr->CP_HaveCustomData = TRUE;
1059 
1060 		  if(xres > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = xres;
1061 		  if(yres > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = yres;
1062 		  if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
1063 
1064 		  if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) {
1065 		     SiS_Pr->CP_PreferredIndex = i;
1066 		     SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C);
1067 		     SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1;
1068 		  }
1069 
1070 		  /* Extract the sync polarisation information. This only works
1071 		   * if the Flags indicate a digital separate output.
1072 		   */
1073 		  if((buffer[base+17] & 0x18) == 0x18) {
1074 		     SiS_Pr->CP_HSync_P[i] = (buffer[base+17] & 0x02) ? TRUE : FALSE;
1075 		     SiS_Pr->CP_VSync_P[i] = (buffer[base+17] & 0x04) ? TRUE : FALSE;
1076 		     SiS_Pr->CP_SyncValid[i] = TRUE;
1077 		     if((i == SiS_Pr->CP_PreferredIndex) && (!havesync)) {
1078 			cr37 |= ((((buffer[base+17] & 0x06) ^ 0x06) << 5) | 0x20);
1079 			havesync = TRUE;
1080 		     }
1081 		  } else {
1082 		     SiS_Pr->CP_SyncValid[i] = FALSE;
1083 		  }
1084 
1085 	       }
1086 
1087 	    } else if((!buffer[base]) && (!buffer[base+1]) && (!buffer[base+2]) && (!buffer[base+4])) {
1088 
1089 	       /* Maximum pixclock from Monitor Range Limits */
1090 	       if((buffer[base+3] == 0xfd) && (buffer[base+9] != 0xff)) {
1091 		  int maxclk = buffer[base+9] * 10;
1092 		  /* More than 170 is not supported anyway */
1093 		  if(maxclk <= 170) SiS_Pr->CP_MaxClock = maxclk * 1000;
1094 	       }
1095 
1096 	    }
1097 
1098 	 }
1099 
1100 	 if(SiS_Pr->CP_MaxX && SiS_Pr->CP_MaxY) {
1101 	    paneltype = Panel_Custom;
1102 	    checkexpand = FALSE;
1103 	    cr37 |= 0x10;
1104 	    SiS_Pr->CP_Vendor = panelvendor;
1105 	    SiS_Pr->CP_Product = panelproduct;
1106 	 }
1107 
1108       }
1109 
1110       if(paneltype && checkexpand) {
1111 	 /* If any of the Established low-res modes is supported, the
1112 	  * panel can scale automatically. For 800x600 panels, we only
1113 	  * check the even lower ones.
1114 	  */
1115 	 if(paneltype == Panel_800x600) {
1116 	    if(buffer[0x23] & 0xfc) cr37 |= 0x10;
1117 	 } else {
1118 	    if(buffer[0x23])	    cr37 |= 0x10;
1119 	 }
1120       }
1121 
1122       break;
1123 
1124    case 3:							/* Analyze EDID V2 */
1125    case 4:
1126       index = 0;
1127 
1128       if(!(checkedid2(buffer))) {
1129 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1130 	 	"LCD sense: EDID corrupt\n");
1131 	 return 0;
1132       }
1133 
1134       if((buffer[0x41] & 0x0f) == 0x03) {
1135 	 index = 0x42 + 3;
1136 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1137 	 	"LCD sense: Display supports TMDS input on primary interface\n");
1138       } else if((buffer[0x41] & 0xf0) == 0x30) {
1139 	 index = 0x46 + 3;
1140 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1141 	 	"LCD sense: Display supports TMDS input on secondary interface\n");
1142       } else {
1143 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1144 		"LCD sense: Display does not support TMDS video interface (0x%02x)\n",
1145 		buffer[0x41]);
1146 	 return 0;
1147       }
1148 
1149       /* Save given gamma */
1150       pSiS->CRT2LCDMonitorGamma = (buffer[0x56] + 100) * 10;
1151 
1152       SiS_Pr->CP_Vendor = panelvendor = buffer[2] | (buffer[1] << 8);
1153       SiS_Pr->CP_Product = panelproduct = buffer[3] | (buffer[4] << 8);
1154 
1155       paneltype = Panel_Custom;
1156       SiS_Pr->CP_MaxX = SiS_Pr->CP_PreferredX = xres = buffer[0x76] | (buffer[0x77] << 8);
1157       SiS_Pr->CP_MaxY = SiS_Pr->CP_PreferredY = yres = buffer[0x78] | (buffer[0x79] << 8);
1158 
1159       switch(xres) {
1160          case 1024:
1161 	     if(yres == 768) {
1162 		paneltype = Panel_1024x768;
1163 		checkexpand = TRUE;
1164 	     }
1165 	     break;
1166 	 case 1280:
1167 	     if(yres == 960) {
1168 		paneltype = panel1280x960;
1169 	     } else if(yres == 1024) {
1170 		paneltype = Panel_1280x1024;
1171 		checkexpand = TRUE;
1172 	     }
1173 	     /* 1280x768, 1280x800 treated as custom here */
1174 	     break;
1175 	 case 1400:
1176 	     if(pSiS->VGAEngine == SIS_315_VGA) {
1177 		if(yres == 1050) {
1178 		   paneltype = Panel310_1400x1050;
1179 		   checkexpand = TRUE;
1180 		}
1181 	     }
1182 	     break;
1183 	 /* 1600x1200 treated as custom */
1184       }
1185 
1186       /* Determine if RGB18 or RGB24 */
1187       if(index) {
1188 	 if((buffer[index] == 0x20) || (buffer[index] == 0x34)) {
1189 	    cr37 |= 0x01;
1190 	 }
1191       }
1192 
1193       if(checkexpand) {
1194 	 /* TODO - for now, we let the panel scale */
1195 	 cr37 |= 0x10;
1196       }
1197 
1198       /* Now seek 4-Byte Timing codes and extract sync pol info */
1199       index = 0x80;
1200       if(buffer[0x7e] & 0x20) {			    /* skip Luminance Table (if provided) */
1201 	 lumsize = buffer[0x80] & 0x1f;
1202 	 if(buffer[0x80] & 0x80) lumsize *= 3;
1203 	 lumsize++;  /* luminance header byte */
1204 	 index += lumsize;
1205       }
1206 #if 0 /* "pixel rate" = pixel clock? */
1207       if(buffer[0x7e] & 0x1c) {
1208 	 for(i=0; i<((buffer[0x7e] & 0x1c) >> 2); i++) {
1209 	    if(buffer[index + (i*8) + 6] && (buffer[index + (i*8) + 7] & 0x0f)) {
1210 	       int clk = (buffer[index + (i*8) + 6] | ((buffer[index + (i*8) + 7] & 0x0f) << 4)) * 1000;
1211 	       if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk;
1212 	    }
1213 	 }
1214       }
1215 #endif
1216       index += (((buffer[0x7e] & 0x1c) >> 2) * 8);   /* skip Frequency Ranges */
1217       if(buffer[0x7e] & 0x03) {
1218 	 for(i=0; i<(buffer[0x7e] & 0x03); i++) {
1219 	    if((buffer[index + (i*27) + 9]) || (buffer[index + (i*27) + 10])) {
1220 	       int clk = ((buffer[index + (i*27) + 9]) | ((buffer[index + (i*27) + 9]) << 8)) * 10;
1221 	       if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk;
1222 	    }
1223 	 }
1224       }
1225       index += ((buffer[0x7e] & 0x03) * 27);         /* skip Detailed Range Limits */
1226       numcodes = (buffer[0x7f] & 0xf8) >> 3;
1227       if(numcodes) {
1228 	 myindex = index;
1229 	 seekcode = (xres - 256) / 16;
1230 	 for(i=0; i<numcodes; i++) {
1231 	    if(buffer[myindex] == seekcode) break;
1232 	    myindex += 4;
1233 	 }
1234 	 if(buffer[myindex] == seekcode) {
1235 	    cr37 |= ((((buffer[myindex + 1] & 0x0c) ^ 0x0c) << 4) | 0x20);
1236 	    havesync = TRUE;
1237 	 } else {
1238 	    xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
1239 		"LCD sense: Unable to retrieve Sync polarity information\n");
1240 	 }
1241       } else {
1242          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
1243 	     "LCD sense: Unable to retrieve Sync polarity information\n");
1244       }
1245 
1246       /* Check against our database; Eg. Sanyo projector reports
1247        * 1024x768 in non-HDPC mode, although it supports 1280x720.
1248        * Treat such wrongly reporting panels as custom.
1249        */
1250       if(paneltype != Panel_Custom) {
1251 	 int maxx, maxy, prefx, prefy;
1252 	 if((SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) {
1253 	    paneltype = Panel_Custom;
1254 	    SiS_Pr->CP_MaxX = maxx;
1255 	    SiS_Pr->CP_MaxY = maxy;
1256 	    cr37 |= 0x10;
1257 	    /* Leave preferred unchanged (MUST be a valid mode!) */
1258 	 }
1259       }
1260 
1261       /* Now seek the detailed timing descriptions for custom panels */
1262       if(paneltype == Panel_Custom) {
1263 
1264          SiS_Pr->CP_Supports64048075 = TRUE;
1265 
1266          index += (numcodes * 4);
1267 	 numcodes = buffer[0x7f] & 0x07;
1268 	 for(i=0; i<numcodes; i++, index += 18) {
1269 	    xres = buffer[index+2] | ((buffer[index+4] & 0xf0) << 4);
1270             yres = buffer[index+5] | ((buffer[index+7] & 0xf0) << 4);
1271 
1272 	    SiS_Pr->CP_HDisplay[i] = xres;
1273 	    SiS_Pr->CP_HSyncStart[i] = xres + (buffer[index+8] | ((buffer[index+11] & 0xc0) << 2));
1274             SiS_Pr->CP_HSyncEnd[i] = SiS_Pr->CP_HSyncStart[i] + (buffer[index+9] | ((buffer[index+11] & 0x30) << 4));
1275 	    SiS_Pr->CP_HTotal[i] = xres + (buffer[index+3] | ((buffer[index+4] & 0x0f) << 8));
1276 	    SiS_Pr->CP_HBlankStart[i] = xres + 1;
1277 	    SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i];
1278 
1279 	    SiS_Pr->CP_VDisplay[i] = yres;
1280             SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[index+10] & 0xf0) >> 4) | ((buffer[index+11] & 0x0c) << 2));
1281             SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[index+10] & 0x0f) | ((buffer[index+11] & 0x03) << 4));
1282 	    SiS_Pr->CP_VTotal[i] = yres + (buffer[index+6] | ((buffer[index+7] & 0x0f) << 8));
1283 	    SiS_Pr->CP_VBlankStart[i] = yres + 1;
1284 	    SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i];
1285 
1286 	    SiS_Pr->CP_Clock[i] = (buffer[index] | (buffer[index+1] << 8)) * 10;
1287 
1288 	    SiS_Pr->CP_DataValid[i] = TRUE;
1289 
1290 	    if((SiS_Pr->CP_HDisplay[i] & 7)						||
1291 	       (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i])  			||
1292 	       (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i])   			||
1293 	       (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i])     			||
1294 	       (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) 			||
1295 	       (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i])    			||
1296 	       (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i])      			||
1297 	       (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i])  			||
1298 	       (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i])   			||
1299 	       (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i])     			||
1300 	       (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i])  			||
1301 	       (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i])    			||
1302 	       (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i])      			||
1303 	       (((pSiS->VBFlags2 & VB2_30xC) && (SiS_Pr->CP_Clock[i] > 162500)) ||
1304 	        ((!(pSiS->VBFlags2 & VB2_30xC))        &&
1305 		 ( (SiS_Pr->CP_Clock[i] > 110500)  ||
1306 		   (SiS_Pr->CP_VDisplay[i] > 1024) ||
1307 		   (SiS_Pr->CP_HDisplay[i] > 1600) )))					||
1308 	       (buffer[index + 17] & 0x80)) {
1309 
1310 	       SiS_Pr->CP_DataValid[i] = FALSE;
1311 
1312 	    } else {
1313 
1314 	       SiS_Pr->CP_HaveCustomData = TRUE;
1315 
1316 	       if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
1317 
1318 	       if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) {
1319 		  SiS_Pr->CP_PreferredIndex = i;
1320 		  SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C);
1321 		  SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1;
1322 		  if(!havesync) {
1323 		     cr37 |= ((((buffer[index + 17] & 0x06) ^ 0x06) << 5) | 0x20);
1324 		     havesync = TRUE;
1325 		  }
1326 	       }
1327 
1328 	       SiS_Pr->CP_HSync_P[i] = (buffer[index + 17] & 0x02) ? TRUE : FALSE;
1329 	       SiS_Pr->CP_VSync_P[i] = (buffer[index + 17] & 0x04) ? TRUE : FALSE;
1330 	       SiS_Pr->CP_SyncValid[i] = TRUE;
1331 
1332 	    }
1333 	 }
1334 
1335 	 cr37 |= 0x10;
1336 
1337       }
1338 
1339       break;
1340 
1341    }
1342 
1343    /* 1280x960 panels are always RGB24, unable to scale and use
1344     * high active sync polarity. (Check is save, other panel types
1345     * for other chipset series not being set up)
1346     */
1347    if(paneltype == panel1280x960) cr37 &= 0x0e;
1348 
1349    for(i = 0; i < 7; i++) {
1350       if(SiS_Pr->CP_DataValid[i]) {
1351 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1352 	    "Non-standard LCD/DVI-D timing data no. %d:\n", i);
1353 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1354 	    "   HDisplay %d HSync %d HSyncEnd %d HTotal %d\n",
1355 	    SiS_Pr->CP_HDisplay[i], SiS_Pr->CP_HSyncStart[i],
1356 	    SiS_Pr->CP_HSyncEnd[i], SiS_Pr->CP_HTotal[i]);
1357 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1358 	    "   VDisplay %d VSync %d VSyncEnd %d VTotal %d\n",
1359 	    SiS_Pr->CP_VDisplay[i], SiS_Pr->CP_VSyncStart[i],
1360 	    SiS_Pr->CP_VSyncEnd[i], SiS_Pr->CP_VTotal[i]);
1361 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1362 	    "   Pixel clock: %3.3fMhz\n", (float)SiS_Pr->CP_Clock[i] / 1000);
1363 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
1364 	    "   To use this, add \"%dx%d\" to the Modes list in the Screen section\n",
1365 	    SiS_Pr->CP_HDisplay[i],
1366 	    SiS_Pr->CP_VDisplay[i]);
1367       }
1368    }
1369 
1370    if(paneltype) {
1371        if(!SiS_Pr->CP_PreferredX) SiS_Pr->CP_PreferredX = SiS_Pr->CP_MaxX;
1372        if(!SiS_Pr->CP_PreferredY) SiS_Pr->CP_PreferredY = SiS_Pr->CP_MaxY;
1373        SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x08);
1374        SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,paneltype);
1375        cr37 &= 0xf1;
1376        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0x0c,cr37);
1377        SiS_Pr->PanelSelfDetected = TRUE;
1378 #ifdef TWDEBUG
1379        xf86DrvMsgVerb(pSiS->pScrn->scrnIndex, X_PROBED, 3,
1380 	   "LCD sense: [DDC LCD results: 0x%02x, 0x%02x]\n", paneltype, cr37);
1381 #endif
1382    } else {
1383        SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x32,~0x08);
1384        SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,0x00);
1385    }
1386    return 0;
1387 }
1388 
1389 unsigned short
SiS_SenseVGA2DDC(struct SiS_Private * SiS_Pr,SISPtr pSiS)1390 SiS_SenseVGA2DDC(struct SiS_Private *SiS_Pr, SISPtr pSiS)
1391 {
1392    unsigned short DDCdatatype, flag;
1393    BOOLEAN foundcrt = FALSE;
1394    int retry;
1395    unsigned char buffer[256];
1396 
1397    if(!(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) return 0;
1398 
1399    /* Specific for XGI_40/Rev 2/A01 (XGI V3XT A01): This card has CRT1's
1400     * and CRT2's DDC ports physically connected to each other. There
1401     * is no connection to the video bridge's DDC port, both DDC
1402     * channels are routed to the GPU. Smart. If both CRT1 (CRT) and
1403     * CRT2 (VGA or LCD) are connected, DDC will fail. If a CRT is
1404     * connected to the DVI-I port, it will report "analog" as well,
1405     * so we never know if the monitor is connected to CRT1 or CRT2.
1406     * Hence, no reliable CRT detection here... we need to fall back to
1407     * the sensing stuff in sis_vb.c.
1408     */
1409    if(SiS_Pr->DDCPortMixup) return 0;
1410 
1411    if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 2, 0, FALSE, pSiS->VBFlags2) == 0xFFFF)
1412       return 0;
1413 
1414    SiS_Pr->SiS_DDC_SecAddr = 0x00;
1415 
1416    /* Probe supported DA's */
1417    flag = SiS_ProbeDDC(SiS_Pr);
1418    if(flag & 0x10) {
1419       SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;	/* EDID V2 (FP) */
1420       DDCdatatype = 4;
1421    } else if(flag & 0x08) {
1422       SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;	/* EDID V2 (P&D-D Monitor) */
1423       DDCdatatype = 3;
1424    } else if(flag & 0x02) {
1425       SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;	/* EDID V1 */
1426       DDCdatatype = 1;
1427    } else {
1428 	xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1429 		"VGA2 sense: Do DDC answer\n");
1430 	return 0;				/* no DDC support (or no device attached) */
1431    }
1432 
1433    /* Read the entire EDID */
1434    retry = 2;
1435    do {
1436       if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) {
1437 	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1438 		"VGA2 sense: DDC read failed (attempt %d), %s\n",
1439 		(3-retry), (retry == 1) ? "giving up" : "retrying");
1440 	 retry--;
1441 	 if(retry == 0) return 0xFFFF;
1442       } else break;
1443    } while(1);
1444 
1445    /* Analyze EDID. We don't have many chances to
1446     * distinguish a flat panel from a CRT...
1447     */
1448    switch(DDCdatatype) {
1449 
1450    case 1:
1451       if(!(checkedid1(buffer))) {
1452 	  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
1453 		"VGA2 sense: EDID corrupt\n");
1454 	  return 0;
1455       }
1456       if(buffer[0x14] & 0x80) {		/* Display uses digital input */
1457 	  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
1458 		"VGA2 sense: Attached display expects digital input\n");
1459 	  return 0;
1460       }
1461       SiS_Pr->CP_Vendor = buffer[9] | (buffer[8] << 8);
1462       SiS_Pr->CP_Product = buffer[10] | (buffer[11] << 8);
1463       foundcrt = TRUE;
1464 
1465       /* Save given gamma */
1466       pSiS->CRT2VGAMonitorGamma = (buffer[0x17] + 100) * 10;
1467 
1468       break;
1469 
1470    case 3:
1471    case 4:
1472       if(!(checkedid2(buffer))) {
1473 	  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
1474 		"VGA2 sense: EDID corrupt\n");
1475 	  return 0;
1476       }
1477       if( ((buffer[0x41] & 0x0f) != 0x01) &&  	/* Display does not support analog input */
1478 	  ((buffer[0x41] & 0x0f) != 0x02) &&
1479 	  ((buffer[0x41] & 0xf0) != 0x10) &&
1480 	  ((buffer[0x41] & 0xf0) != 0x20) ) {
1481 	  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
1482 		"VGA2 sense: Attached display does not support analog input (0x%02x)\n",
1483 		buffer[0x41]);
1484 	  return 0;
1485       }
1486       SiS_Pr->CP_Vendor = buffer[2] | (buffer[1] << 8);
1487       SiS_Pr->CP_Product = buffer[3] | (buffer[4] << 8);
1488       foundcrt = TRUE;
1489 
1490       /* Save given gamma */
1491       pSiS->CRT2VGAMonitorGamma = (buffer[0x56] + 100) * 10;
1492 
1493       break;
1494    }
1495 
1496    if(foundcrt) {
1497       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x10);
1498    }
1499    return(0);
1500 }
1501 
1502 /* 4-tap scaler for 301C and later */
1503 
1504 static float
rcos(float x)1505 rcos(float x)
1506 {
1507    double pi = 3.14159265358979;
1508    float  r = 0.5, y;
1509 
1510     if(x == 0.0) {
1511        y = 1.0;
1512     } else if(x == -1.0 || x == 1.0) {
1513        y = 0.0;
1514     } else {
1515        y = sin(pi * x) / (pi * x) * cos(r * pi * x) / (1 - x * x);
1516     }
1517 
1518     return y;
1519 }
1520 
1521 static int
roundandconv(float in)1522 roundandconv(float in)
1523 {
1524     int a = ((int)(in)) * 10;
1525     int b = (int)(in * 10.0);
1526 
1527     if (in >= 0) {
1528       if((b - a) < 5)  return (a / 10);
1529       else             return (a / 10) + 1;
1530     } else {
1531       if((b - a) > -5) return (a / 10);
1532       else             return (a / 10) -1;
1533     }
1534 }
1535 
1536 void
SiS_CalcXTapScaler(struct SiS_Private * SiS_Pr,int srcsize,int destsize,int taps,Bool ishoriz)1537 SiS_CalcXTapScaler(struct SiS_Private *SiS_Pr, int srcsize, int destsize, int taps, Bool ishoriz)
1538 {
1539    float scale = (float)srcsize / (float)destsize;
1540    int   coe_bit_number = 6;
1541    float fixnumber = (float)(1 << (coe_bit_number - 1));
1542    float ops, WW, W[8];
1543    int   WeightMat[16][8];
1544    int   i, j, index;
1545 
1546    /* For now: */
1547    if(taps != 4) taps = 4;
1548 
1549    if(scale < 1.0)      scale = 1.0;
1550    else if(scale > 1.0) scale *= 1.1;
1551 
1552    for(i = 0; i < 16; i++) {
1553 
1554       ops = (float)i / (16.0 * scale);
1555 
1556       switch(taps) {
1557       case 4:
1558 	 W[0] = rcos( 1.0 / scale + ops);
1559 	 W[1] = rcos( 0.0 / scale + ops);
1560 	 W[2] = rcos(-1.0 / scale + ops);
1561 	 W[3] = rcos(-2.0 / scale + ops);
1562 
1563 	 WW = W[0] + W[1] + W[2] + W[3];
1564 
1565 	 WeightMat[i][0] = roundandconv(W[0] / WW * fixnumber);
1566 	 WeightMat[i][1] = roundandconv(W[1] / WW * fixnumber);
1567 	 WeightMat[i][2] = roundandconv(W[2] / WW * fixnumber);
1568 	 WeightMat[i][3] = (int)fixnumber - WeightMat[i][0] - WeightMat[i][1] - WeightMat[i][2];
1569 	 break;
1570 #if 0 /* For future use */
1571      case 8:
1572 	 W[0] = rcos( 3.0/scale + ops);
1573 	 W[1] = rcos( 2.0/scale + ops);
1574 	 W[2] = rcos( 1.0/scale + ops);
1575 	 W[3] = rcos( 0.0/scale + ops);
1576 	 W[4] = rcos(-1.0/scale + ops);
1577 	 W[5] = rcos(-2.0/scale + ops);
1578 	 W[6] = rcos(-3.0/scale + ops);
1579 	 W[7] = rcos(-4.0/scale + ops);
1580 
1581 	 WW = W[0] + W[1] + W[2] + W[3] + W[4] + W[5] + W[6] + W[7];
1582 
1583 	 WeightMat[i][0] = roundandconv(W[0]/WW * fixnumber);
1584 	 WeightMat[i][1] = roundandconv(W[1]/WW * fixnumber);
1585 	 WeightMat[i][2] = roundandconv(W[2]/WW * fixnumber);
1586 	 WeightMat[i][3] = roundandconv(W[3]/WW * fixnumber);
1587 	 WeightMat[i][4] = roundandconv(W[4]/WW * fixnumber);
1588 	 WeightMat[i][5] = roundandconv(W[5]/WW * fixnumber);
1589 	 WeightMat[i][6] = roundandconv(W[6]/WW * fixnumber);
1590 	 WeightMat[i][7] = (int)fixnumber - WeightMat[i][0] - WeightMat[i][1] -
1591 					    WeightMat[i][2] - WeightMat[i][3] -
1592 					    WeightMat[i][4] - WeightMat[i][5] - WeightMat[i][6];
1593 	 break;
1594 #endif
1595       }
1596    }
1597 
1598    index = ishoriz ? 0x80 : 0xc0;
1599    for(i = 0; i < 16; i++) {
1600       for(j = 0; j < 4 /* taps! */; j++) {
1601          if(WeightMat[i][j] < 0) {
1602 	    WeightMat[i][j] = ((~(-WeightMat[i][j])) + 1) & 0x7f;
1603          }
1604          SiS_SetReg(SiS_Pr->SiS_Part2Port, index++, WeightMat[i][j]);
1605       }
1606    }
1607 
1608 }
1609 
1610 void
SiS_SetGroup2_C_ELV(struct SiS_Private * SiS_Pr,unsigned short ModeNo,unsigned short ModeIdIndex,unsigned short RefreshRateTableIndex)1611 SiS_SetGroup2_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex,
1612 	      	    unsigned short RefreshRateTableIndex)
1613 {
1614    unsigned char temp;
1615 
1616    if(!(SiS_Pr->SiS_VBType & VB_SISTAP4SCALER)) return;
1617 
1618    SiS_CalcXTapScaler(SiS_Pr, SiS_Pr->SiS_VGAHDE, SiS_Pr->SiS_HDE, 4, TRUE);
1619    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
1620       SiS_CalcXTapScaler(SiS_Pr, SiS_Pr->SiS_VGAVDE, SiS_Pr->SiS_VDE, 4, FALSE);
1621    }
1622 
1623    temp = 0x10;
1624    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp |= 0x04;
1625    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xeb,temp);
1626 }
1627 
1628 
1629