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