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