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 38static void 39SiS_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 80unsigned short 81SiS_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 */ 187DisplayModePtr 188SiSBuildBuiltInModeList(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(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(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(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 */ 546int 547SiSTranslateToVESA(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 */ 579int 580SiSTranslateToOldMode(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 598BOOLEAN 599SiS_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 661static BOOLEAN 662checkedid1(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 687static BOOLEAN 688checkedid2(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 704static int 705SiS_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 */ 738unsigned short 739SiS_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 1389unsigned short 1390SiS_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 1504static float 1505rcos(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 1521static int 1522roundandconv(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 1536void 1537SiS_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 1610void 1611SiS_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