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