via_fp.c revision 983b4bf2
1/* 2 * Copyright 2007-2015 The Openchrome Project 3 * [https://www.freedesktop.org/wiki/Openchrome] 4 * Copyright 1998-2007 VIA Technologies, Inc. All Rights Reserved. 5 * Copyright 2001-2007 S3 Graphics, Inc. All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sub license, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 * DEALINGS IN THE SOFTWARE. 25 */ 26 27/* 28 * Integrated LVDS power management functions. 29 */ 30 31#ifdef HAVE_CONFIG_H 32#include "config.h" 33#endif 34 35#include "via_driver.h" 36#include "via_mode.h" 37#include <unistd.h> 38 39/* 40 * Option handling. 41 */ 42enum ViaPanelOpts { 43 OPTION_CENTER 44}; 45 46static OptionInfoRec ViaPanelOptions[] = 47{ 48 {OPTION_CENTER, "Center", OPTV_BOOLEAN, {0}, FALSE}, 49 {-1, NULL, OPTV_NONE, {0}, FALSE} 50}; 51 52/* These table values were copied from lcd.c of VIA Frame 53 * Buffer device driver. */ 54/* {int Width, int Height, bool useDualEdge, bool useDithering}; */ 55static ViaPanelModeRec ViaPanelNativeModes[] = { 56 { 640, 480, FALSE, TRUE}, 57 { 800, 600, FALSE, TRUE}, 58 {1024, 768, FALSE, TRUE}, 59 {1280, 768, FALSE, TRUE}, 60 {1280, 1024, TRUE, TRUE}, 61 {1400, 1050, TRUE, TRUE}, 62 {1600, 1200, TRUE, TRUE}, 63 {1280, 800, FALSE, TRUE}, 64 { 800, 480, FALSE, TRUE}, 65 {1024, 768, TRUE, TRUE}, 66 {1024, 768, FALSE, FALSE}, 67 {1024, 768, TRUE, FALSE}, 68 {1280, 768, FALSE, FALSE}, 69 {1280, 1024, TRUE, FALSE}, 70 {1400, 1050, TRUE, FALSE}, 71 {1600, 1200, TRUE, FALSE}, 72 {1366, 768, FALSE, FALSE}, 73 {1024, 600, FALSE, TRUE}, 74 {1280, 768, TRUE, TRUE}, 75 {1280, 800, FALSE, TRUE}, 76 {1360, 768, FALSE, FALSE}, 77 {1280, 768, TRUE, FALSE}, 78 { 480, 640, FALSE, TRUE}, 79 {1200, 900, FALSE, FALSE}}; 80 81#define MODEPREFIX(name) NULL, NULL, name, 0, M_T_DRIVER | M_T_DEFAULT 82#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 83 84static DisplayModeRec OLPCMode = { 85 MODEPREFIX("1200x900"), 86 57275, 1200, 1208, 1216, 1240, 0, 87 900, 905, 908, 912, 0, 88 V_NHSYNC | V_NVSYNC, MODESUFFIX 89}; 90 91/* 92 1. Formula: 93 2^13 X 0.0698uSec [1/14.318MHz] = 8192 X 0.0698uSec =572.1uSec 94 Timer = Counter x 572 uSec 95 2. Note: 96 0.0698 uSec is too small to compute for hardware. So we multiply a 97 reference value(2^13) to make it big enough to compute for hardware. 98 3. Note: 99 The meaning of the TD0~TD3 are count of the clock. 100 TD(sec) = (sec)/(per clock) x (count of clocks) 101*/ 102 103#define TD0 200 104#define TD1 25 105#define TD2 0 106#define TD3 25 107 108/* 109 * Sets CX700 or later single chipset's LVDS1 I/O pad state. 110 */ 111void 112viaLVDS1SetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState) 113{ 114 vgaHWPtr hwp = VGAHWPTR(pScrn); 115 116 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 117 "Entered viaLVDS1SetIOPadSetting.\n")); 118 119 /* Set LVDS1 I/O pad state. */ 120 /* 3C5.2A[1:0] - LVDS1 I/O Pad Control */ 121 ViaSeqMask(hwp, 0x2A, ioPadState, 0x03); 122 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 123 "LVDS1 I/O Pad State: %d\n", 124 (ioPadState & 0x03)); 125 126 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 127 "Exiting viaLVDS1SetIOPadSetting.\n")); 128} 129 130/* 131 * Sets IGA1 or IGA2 as the display output source for VIA Technologies 132 * Chrome IGP LVDS1 integrated LVDS transmitter. 133 */ 134static void 135viaLVDS1SetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource) 136{ 137 vgaHWPtr hwp = VGAHWPTR(pScrn); 138 CARD8 temp = displaySource; 139 140 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 141 "Entered viaLVDS1SetDisplaySource.\n")); 142 143 /* Set LVDS1 integrated LVDS transmitter display output source. */ 144 /* 3X5.99[4] - LVDS Channel 1 Data Source Selection 145 * 0: Primary Display 146 * 1: Secondary Display */ 147 ViaCrtcMask(hwp, 0x99, temp << 4, 0x10); 148 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 149 "LVDS1 Integrated LVDS Transmitter Display Output " 150 "Source: IGA%d\n", 151 (temp & 0x01) + 1); 152 153 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 154 "Exiting viaLVDS1SetDisplaySource.\n")); 155} 156 157/* 158 * Sets LVDS1 (LVDS Channel 1) integrated LVDS transmitter format. 159 */ 160static void 161viaLVDS1SetFormat(ScrnInfoPtr pScrn, CARD8 format) 162{ 163 vgaHWPtr hwp = VGAHWPTR(pScrn); 164 165 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 166 "Entered viaLVDS1SetFormat.\n")); 167 168 /* Set LVDS1 format. */ 169 /* 3X5.D2[1] - LVDS Channel 1 Format Selection 170 * 0: SPWG Mode 171 * 1: OPENLDI Mode */ 172 ViaCrtcMask(hwp, 0xD2, format << 1, 0x02); 173 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 174 "LVDS1 Format: %s\n", 175 (format & 0x01) ? "OPENLDI" : "SPWG"); 176 177 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 178 "Exiting viaLVDS1SetFormat.\n")); 179} 180 181/* 182 * Sets CX700 or later single chipset's LVDS2 I/O pad state. 183 */ 184static void 185viaLVDS2SetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState) 186{ 187 vgaHWPtr hwp = VGAHWPTR(pScrn); 188 189 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 190 "Entered viaLVDS2SetIOPadSetting.\n")); 191 192 /* Set LVDS2 I/O pad state. */ 193 /* 3C5.2A[3:2] - LVDS2 I/O Pad Control */ 194 ViaSeqMask(hwp, 0x2A, ioPadState << 2, 0x0C); 195 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 196 "LVDS2 I/O Pad State: %d\n", 197 (ioPadState & 0x03)); 198 199 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 200 "Exiting viaLVDS2SetIOPadSetting.\n")); 201} 202 203/* 204 * Sets IGA1 or IGA2 as the display output source for VIA Technologies 205 * Chrome IGP LVDS2 integrated LVDS transmitter. 206 */ 207static void 208viaLVDS2SetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource) 209{ 210 vgaHWPtr hwp = VGAHWPTR(pScrn); 211 CARD8 temp = displaySource; 212 213 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 214 "Entered viaLVDS2SetDisplaySource.\n")); 215 216 /* Set LVDS2 integrated LVDS transmitter display output source. */ 217 /* 3X5.97[4] - LVDS Channel 2 Data Source Selection 218 * 0: Primary Display 219 * 1: Secondary Display */ 220 ViaCrtcMask(hwp, 0x97, temp << 4, 0x10); 221 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 222 "LVDS2 Integrated LVDS Transmitter Display Output " 223 "Source: IGA%d\n", 224 (temp & 0x01) + 1); 225 226 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 227 "Exiting viaLVDS2SetDisplaySource.\n")); 228} 229 230/* 231 * Sets LVDS2 (LVDS Channel 2) integrated LVDS transmitter delay tap. 232 */ 233static void 234viaLVDS2SetDelayTap(ScrnInfoPtr pScrn, CARD8 delayTap) 235{ 236 vgaHWPtr hwp = VGAHWPTR(pScrn); 237 238 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 239 "Entered viaLVDS2SetDelayTap.\n")); 240 241 /* Set LVDS2 delay tap. */ 242 /* 3X5.97[3:0] - LVDS2 Delay Tap */ 243 ViaCrtcMask(hwp, 0x97, delayTap, 0x0F); 244 245 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 246 "LVDS2 Delay Tap: %d\n", 247 (delayTap & 0x0F)); 248 249 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 250 "Exiting viaLVDS2SetDelayTap.\n")); 251} 252 253/* 254 * Sets LVDS2 (LVDS Channel 2) integrated LVDS transmitter format. 255 */ 256static void 257viaLVDS2SetFormat(ScrnInfoPtr pScrn, CARD8 format) 258{ 259 vgaHWPtr hwp = VGAHWPTR(pScrn); 260 261 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 262 "Entered viaLVDS2SetFormat.\n")); 263 264 /* Set LVDS2 format. */ 265 /* 3X5.D2[0] - LVDS Channel 2 Format Selection 266 * 0: SPWG Mode 267 * 1: OPENLDI Mode */ 268 ViaCrtcMask(hwp, 0xD2, format, 0x01); 269 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 270 "LVDS2 Format: %s\n", 271 (format & 0x01) ? "OPENLDI" : "SPWG"); 272 273 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 274 "Exiting viaLVDS2SetFormat.\n")); 275} 276 277/* 278 * Sets IGA1 or IGA2 as the display output source for VIA Technologies 279 * Chrome IGP DFP (Digital Flat Panel) High interface. 280 */ 281static void 282viaDFPHighSetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource) 283{ 284 vgaHWPtr hwp = VGAHWPTR(pScrn); 285 CARD8 temp = displaySource; 286 287 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 288 "Entered viaDFPHighSetDisplaySource.\n")); 289 290 /* Set DFP High display output source. */ 291 /* 3X5.97[4] - DFP High Data Source Selection 292 * 0: Primary Display 293 * 1: Secondary Display */ 294 ViaCrtcMask(hwp, 0x97, temp << 4, 0x10); 295 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 296 "DFP High Display Output Source: IGA%d\n", 297 (temp & 0x01) + 1); 298 299 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 300 "Exiting viaDFPHighSetDisplaySource.\n")); 301} 302 303/* 304 * Sets DFP (Digital Flat Panel) Low interface delay tap. 305 */ 306static void 307viaDFPLowSetDelayTap(ScrnInfoPtr pScrn, CARD8 delayTap) 308{ 309 vgaHWPtr hwp = VGAHWPTR(pScrn); 310 311 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 312 "Entered viaDFPLowSetDelayTap.\n")); 313 314 /* Set DFP Low interface delay tap. */ 315 /* 3X5.99[3:0] - DFP Low Delay Tap */ 316 ViaCrtcMask(hwp, 0x99, delayTap, 0x0F); 317 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 318 "DFP Low Delay Tap: %d\n", 319 (delayTap & 0x0F)); 320 321 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 322 "Exiting viaDFPLowSetDelayTap.\n")); 323} 324 325/* 326 * Sets DFP (Digital Flat Panel) High interface delay tap. 327 */ 328static void 329viaDFPHighSetDelayTap(ScrnInfoPtr pScrn, CARD8 delayTap) 330{ 331 vgaHWPtr hwp = VGAHWPTR(pScrn); 332 333 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 334 "Entered viaDFPHighSetDelayTap.\n")); 335 336 /* Set DFP High interface delay tap. */ 337 /* 3X5.97[3:0] - DFP High Delay Tap */ 338 ViaCrtcMask(hwp, 0x97, delayTap, 0x0F); 339 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 340 "DFP High Delay Tap: %d\n", 341 (delayTap & 0x0F)); 342 343 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 344 "Exiting viaDFPHighSetDelayTap.\n")); 345} 346 347/* 348 * Turns LVDS2 output color dithering on or off. (18-bit color display vs. 349 * 24-bit color display) 350 */ 351static void 352viaLVDS2SetDithering(ScrnInfoPtr pScrn, CARD8 ditheringStatus) 353{ 354 vgaHWPtr hwp = VGAHWPTR(pScrn); 355 356 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 357 "Entered viaLVDS2SetDithering.\n")); 358 359 /* Set LVDS2 output color dithering bit. */ 360 /* 3X5.D4[6] - LVDS Channel 2 Output Bits 361 * 0: 24 bits (dithering off) 362 * 1: 18 bits (dithering on) */ 363 ViaCrtcMask(hwp, 0xD4, ditheringStatus ? 0x40 : 0x00, 0x40); 364 365 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 366 "LVDS2 Output Color Dithering: %s\n", 367 ditheringStatus ? "On (18 bit)" : "Off (24 bit)"); 368 369 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 370 "Exiting viaLVDS2SetDithering.\n")); 371} 372 373/* 374 * Sets output format of LVDS2 to rotation or sequential mode. 375 */ 376static void 377viaLVDS2SetOutputFormat(ScrnInfoPtr pScrn, CARD8 outputFormat) 378{ 379 vgaHWPtr hwp = VGAHWPTR(pScrn); 380 381 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 382 "Entered viaLVDS2SetOutputFormat.\n")); 383 384 /* Set LVDS2 output format. */ 385 /* 3X5.D4[7] - LVDS Channel 2 Output Format 386 * 0: Rotation 387 * 1: Sequential */ 388 ViaCrtcMask(hwp, 0xD4, outputFormat ? 0x80 : 0x00, 0x80); 389 390 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 391 "LVDS2 Output Format: %s\n", 392 outputFormat ? "Sequential" : "Rotation"); 393 394 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 395 "Exiting viaLVDS2SetOutputFormat.\n")); 396} 397 398/* 399 * Sets PCIe based 2 chip chipset's pin multiplexed DVP0 I/O pad state. 400 */ 401static void 402viaDVP0PCIeSetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState) 403{ 404 vgaHWPtr hwp = VGAHWPTR(pScrn); 405 406 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 407 "Entered viaDVP0PCIeSetIOPadSetting.\n")); 408 409 /* Set pin multiplexed DVP1 I/O pad state. */ 410 /* 3C5.2A[3:2] - DVP0 I/O Pad Control */ 411 ViaSeqMask(hwp, 0x2A, ioPadState << 2, 0x0C); 412 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 413 "DVP0 I/O Pad State: %d\n", 414 (ioPadState & 0x03)); 415 416 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 417 "Exiting viaDVP0PCIeSetIOPadSetting.\n")); 418} 419 420/* 421 * Sets PCIe based 2 chip chipset's pin multiplexed DVP1 I/O pad state. 422 */ 423static void 424viaDVP1PCIeSetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState) 425{ 426 vgaHWPtr hwp = VGAHWPTR(pScrn); 427 428 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 429 "Entered viaDVP1PCIeSetIOPadSetting.\n")); 430 431 /* Set pin multiplexed DVP0 I/O pad state. */ 432 /* 3C5.2A[1:0] - DVP1 I/O Pad Control */ 433 ViaSeqMask(hwp, 0x2A, ioPadState, 0x03); 434 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 435 "DVP1 I/O Pad State: %d\n", 436 (ioPadState & 0x03)); 437 438 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 439 "Exiting viaDVP1PCIeSetIOPadSetting.\n")); 440} 441 442static void 443viaFPIOPadSetting(ScrnInfoPtr pScrn, Bool ioPadOn) 444{ 445 vgaHWPtr hwp = VGAHWPTR(pScrn); 446 VIAPtr pVia = VIAPTR(pScrn); 447 CARD8 sr12, sr13, sr5a; 448 449 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 450 "Entered viaFPIOPadSetting.\n")); 451 452 if ((pVia->Chipset == VIA_CX700) 453 || (pVia->Chipset == VIA_VX800) 454 || (pVia->Chipset == VIA_VX855) 455 || (pVia->Chipset == VIA_VX900)) { 456 457 sr5a = hwp->readSeq(hwp, 0x5A); 458 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 459 "SR5A: 0x%02X\n", sr5a)); 460 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 461 "Setting 3C5.5A[0] to 0.\n")); 462 ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01); 463 } 464 465 sr12 = hwp->readSeq(hwp, 0x12); 466 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 467 "SR12: 0x%02X\n", sr12)); 468 sr13 = hwp->readSeq(hwp, 0x13); 469 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 470 "SR13: 0x%02X\n", sr13)); 471 472 switch (pVia->Chipset) { 473 case VIA_CLE266: 474 break; 475 case VIA_KM400: 476 case VIA_K8M800: 477 case VIA_PM800: 478 case VIA_P4M800PRO: 479 break; 480 case VIA_P4M890: 481 case VIA_K8M890: 482 case VIA_P4M900: 483 /* The tricky thing about VIA Technologies PCI Express based 484 * north bridge / south bridge 2 chip chipset is that 485 * it pin multiplexes DVP0 / DVP1 with north bridge's PCI 486 * Express x16 link. In particular, HP 2133 Mini-Note's WLAN 487 * is connected to north bridge's PCI Express Lane 0, but the 488 * Lane 0 is also pin multiplexed with DVP0. What this means is 489 * turning on DVP0 without probing the relevant strapping pin 490 * to determine the connected panel interface type will lead to 491 * the PCIe based WLAN to getting disabled by OpenChrome DDX 492 * when X.Org Server starts. 493 * The current remedy for this will be to turn on DVP0 494 * only when an 18-bit / 24-bit interface flat panel is 495 * connected. */ 496 /* 3C5.12[4] - DVP0D4 pin strapping 497 * 0: Use DVP1 only for a flat panel. 498 * 1: Use DVP0 and DVP1 for a flat panel */ 499 if (sr12 & 0x10) { 500 /* Since an 18-bit / 24-bit flat panel is being used, actively 501 * control DVP0. */ 502 viaDVP0PCIeSetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); 503 } else { 504 /* Keep DVP0 powered down. Otherwise, it will interfere with 505 * PCIe Lane 0 through 7. */ 506 viaDVP0PCIeSetIOPadSetting(pScrn, 0x00); 507 } 508 509 /* Control DVP1 for a flat panel. */ 510 viaDVP1PCIeSetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); 511 break; 512 case VIA_CX700: 513 case VIA_VX800: 514 case VIA_VX855: 515 case VIA_VX900: 516 /* 3C5.13[7:6] - DVP1D15 and DVP1D14 pin strappings 517 * 00: LVDS1 + LVDS2 518 * 01: DVI + LVDS2 519 * 10: Dual LVDS (LVDS1 + LVDS2 used 520 * simultaneously) 521 * 11: DVI only */ 522 if ((((~(sr13 & 0x80)) && (~(sr13 & 0x40))) 523 || ((sr13 & 0x80) && (~(sr13 & 0x40)))) 524 && (!pVia->isVIANanoBook)) { 525 526 viaLVDS1SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); 527 } 528 529 if (((~(sr13 & 0x80)) || (~(sr13 & 0x40))) 530 || (pVia->isVIANanoBook)) { 531 532 viaLVDS2SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00); 533 } 534 break; 535 default: 536 break; 537 } 538 539 if ((pVia->Chipset == VIA_CX700) 540 || (pVia->Chipset == VIA_VX800) 541 || (pVia->Chipset == VIA_VX855) 542 || (pVia->Chipset == VIA_VX900)) { 543 544 hwp->writeSeq(hwp, 0x5A, sr5a); 545 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 546 "Restoring 3C5.5A[0].\n")); 547 } 548 549 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 550 "Exiting viaFPIOPadSetting.\n")); 551} 552 553static void 554ViaLVDSSoftwarePowerFirstSequence(ScrnInfoPtr pScrn, Bool on) 555{ 556 vgaHWPtr hwp = VGAHWPTR(pScrn); 557 558 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaLVDSSoftwarePowerFirstSequence: %d\n", on)); 559 if (on) { 560 561 /* Software control power sequence ON*/ 562 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0x7F); 563 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x01); 564 usleep(TD0); 565 566 /* VDD ON*/ 567 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x10); 568 usleep(TD1); 569 570 /* DATA ON */ 571 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x08); 572 usleep(TD2); 573 574 /* VEE ON (unused on vt3353)*/ 575 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x04); 576 usleep(TD3); 577 578 /* Back-Light ON */ 579 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x02); 580 } else { 581 /* Back-Light OFF */ 582 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xFD); 583 usleep(TD3); 584 585 /* VEE OFF (unused on vt3353)*/ 586 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xFB); 587 usleep(TD2); 588 589 /* DATA OFF */ 590 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xF7); 591 usleep(TD1); 592 593 /* VDD OFF */ 594 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xEF); 595 } 596} 597 598static void 599ViaLVDSSoftwarePowerSecondSequence(ScrnInfoPtr pScrn, Bool on) 600{ 601 vgaHWPtr hwp = VGAHWPTR(pScrn); 602 603 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaLVDSSoftwarePowerSecondSequence: %d\n", on)); 604 if (on) { 605 /* Secondary power hardware power sequence enable 0:off 1: on */ 606 hwp->writeCrtc(hwp, 0xD4, hwp->readCrtc(hwp, 0xD4) & 0xFD); 607 608 /* Software control power sequence ON */ 609 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x01); 610 usleep(TD0); 611 612 /* VDD ON*/ 613 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x10); 614 usleep(TD1); 615 616 /* DATA ON */ 617 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x08); 618 usleep(TD2); 619 620 /* VEE ON (unused on vt3353)*/ 621 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x04); 622 usleep(TD3); 623 624 /* Back-Light ON */ 625 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x02); 626 } else { 627 /* Back-Light OFF */ 628 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xFD); 629 usleep(TD3); 630 631 /* VEE OFF */ 632 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xFB); 633 /* Delay TD2 msec. */ 634 usleep(TD2); 635 636 /* DATA OFF */ 637 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xF7); 638 /* Delay TD1 msec. */ 639 usleep(TD1); 640 641 /* VDD OFF */ 642 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xEF); 643 } 644} 645 646 647static void 648ViaLVDSHardwarePowerFirstSequence(ScrnInfoPtr pScrn, Bool on) 649{ 650 vgaHWPtr hwp = VGAHWPTR(pScrn); 651 652 if (on) { 653 /* Use hardware control power sequence. */ 654 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xFE); 655 /* Turn on back light. */ 656 hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0x3F); 657 /* Turn on hardware power sequence. */ 658 hwp->writeCrtc(hwp, 0x6A, hwp->readCrtc(hwp, 0x6A) | 0x08); 659 } else { 660 /* Turn off power sequence. */ 661 hwp->writeCrtc(hwp, 0x6A, hwp->readCrtc(hwp, 0x6A) & 0xF7); 662 usleep(1); 663 /* Turn off back light. */ 664 hwp->writeCrtc(hwp, 0x91, 0xC0); 665 } 666} 667 668static void 669ViaLVDSHardwarePowerSecondSequence(ScrnInfoPtr pScrn, Bool on) 670{ 671 vgaHWPtr hwp = VGAHWPTR(pScrn); 672 673 if (on) { 674 /* Use hardware control power sequence. */ 675 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xFE); 676 /* Turn on back light. */ 677 hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0x3F); 678 /* Turn on hardware power sequence. */ 679 hwp->writeCrtc(hwp, 0xD4, hwp->readCrtc(hwp, 0xD4) | 0x02); 680 } else { 681 /* Turn off power sequence. */ 682 hwp->writeCrtc(hwp, 0xD4, hwp->readCrtc(hwp, 0xD4) & 0xFD); 683 usleep(1); 684 /* Turn off back light. */ 685 hwp->writeCrtc(hwp, 0xD3, 0xC0); 686 } 687} 688 689static void 690ViaLVDSPowerChannel(ScrnInfoPtr pScrn, Bool on) 691{ 692 vgaHWPtr hwp = VGAHWPTR(pScrn); 693 CARD8 lvdsMask; 694 695 if (on) { 696 /* LVDS0: 0x7F, LVDS1: 0xBF */ 697 lvdsMask = 0x7F & 0xBF; 698 hwp->writeCrtc(hwp, 0xD2, hwp->readCrtc(hwp, 0xD2) & lvdsMask); 699 } else { 700 /* LVDS0: 0x80, LVDS1: 0x40 */ 701 lvdsMask = 0x80 | 0x40; 702 hwp->writeCrtc(hwp, 0xD2, hwp->readCrtc(hwp, 0xD2) | lvdsMask); 703 } 704} 705 706static void 707ViaLVDSPower(ScrnInfoPtr pScrn, Bool Power_On) 708{ 709 vgaHWPtr hwp = VGAHWPTR(pScrn); 710 VIAPtr pVia = VIAPTR(pScrn); 711 CARD8 crd2; 712 713 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 714 "Entered ViaLVDSPower.\n")); 715 716 /* 717 * VX800, CX700 have HW issue, so we'd better use SW power sequence 718 * Fix Ticket #308 719 */ 720 switch (pVia->Chipset) { 721 case VIA_CX700: 722 case VIA_VX800: 723 724 /* Is the integrated TMDS transmitter (DVI) not in use? */ 725 crd2 = hwp->readCrtc(hwp, 0xD2); 726 if (((pVia->Chipset == VIA_CX700) 727 || (pVia->Chipset == VIA_VX800) 728 || (pVia->Chipset == VIA_VX855) 729 || (pVia->Chipset == VIA_VX900)) 730 && (!(crd2 & 0x10))) { 731 ViaLVDSSoftwarePowerFirstSequence(pScrn, Power_On); 732 } 733 734 ViaLVDSSoftwarePowerSecondSequence(pScrn, Power_On); 735 break; 736 737 case VIA_VX855: 738 case VIA_VX900: 739 /* Is the integrated TMDS transmitter (DVI) not in use? */ 740 crd2 = hwp->readCrtc(hwp, 0xD2); 741 if (((pVia->Chipset == VIA_CX700) 742 || (pVia->Chipset == VIA_VX800) 743 || (pVia->Chipset == VIA_VX855) 744 || (pVia->Chipset == VIA_VX900)) 745 && (!(crd2 & 0x10))) { 746 ViaLVDSHardwarePowerFirstSequence(pScrn, Power_On); 747 } 748 749 ViaLVDSHardwarePowerSecondSequence(pScrn, Power_On); 750 break; 751 default: 752 ViaLVDSHardwarePowerFirstSequence(pScrn, Power_On); 753 ViaLVDSHardwarePowerSecondSequence(pScrn, Power_On); 754 break; 755 } 756 757 ViaLVDSPowerChannel(pScrn, Power_On); 758 759 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 760 "Integrated LVDS Flat Panel Power: %s\n", 761 Power_On ? "On" : "Off"); 762 763 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 764 "Exiting ViaLVDSPower.\n")); 765} 766 767static void 768ViaLCDPowerSequence(vgaHWPtr hwp, VIALCDPowerSeqRec Sequence) 769{ 770 int i; 771 772 for (i = 0; i < Sequence.numEntry; i++) { 773 ViaVgahwMask(hwp, 0x300 + Sequence.port[i], Sequence.offset[i], 774 0x301 + Sequence.port[i], Sequence.data[i], 775 Sequence.mask[i]); 776 usleep(Sequence.delay[i]); 777 } 778} 779 780static void 781ViaLCDPower(xf86OutputPtr output, Bool Power_On) 782{ 783 ViaPanelInfoPtr Panel = output->driver_private; 784 ScrnInfoPtr pScrn = output->scrn; 785 vgaHWPtr hwp = VGAHWPTR(pScrn); 786 VIAPtr pVia = VIAPTR(pScrn); 787 VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; 788 int i; 789 790 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 791 "Entered ViaLCDPower.\n")); 792 793 /* Enable LCD */ 794 if (Power_On) 795 ViaCrtcMask(hwp, 0x6A, 0x08, 0x08); 796 else 797 ViaCrtcMask(hwp, 0x6A, 0x00, 0x08); 798 799 if (pBIOSInfo->LCDPower) 800 pBIOSInfo->LCDPower(pScrn, Power_On); 801 802 /* Find Panel Size Index for PowerSeq Table */ 803 if (pVia->Chipset == VIA_CLE266) { 804 if (Panel->NativeModeIndex != VIA_PANEL_INVALID) { 805 for (i = 0; i < NumPowerOn; i++) { 806 if (lcdTable[Panel->PanelIndex].powerSeq 807 == powerOn[i].powerSeq) 808 break; 809 } 810 } else 811 i = 0; 812 } else 813 /* KM and K8M use PowerSeq Table index 2. */ 814 i = 2; 815 816 usleep(1); 817 if (Power_On) 818 ViaLCDPowerSequence(hwp, powerOn[i]); 819 else 820 ViaLCDPowerSequence(hwp, powerOff[i]); 821 usleep(1); 822 823 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 824 "Integrated LVDS Flat Panel Power: %s\n", 825 Power_On ? "On" : "Off"); 826 827 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 828 "Exiting ViaLCDPower.\n")); 829} 830 831/* 832 * Try to interpret EDID ourselves. 833 */ 834static Bool 835ViaPanelGetSizeFromEDID(ScrnInfoPtr pScrn, xf86MonPtr pMon, 836 int *width, int *height) 837{ 838 int i, max_hsize = 0, vsize = 0; 839 840 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAGetPanelSizeFromEDID\n")); 841 842 /* !!! Why are we not checking VESA modes? */ 843 844 /* checking standard timings */ 845 for (i = 0; i < STD_TIMINGS; i++) 846 if ((pMon->timings2[i].hsize > 256) 847 && (pMon->timings2[i].hsize > max_hsize)) { 848 max_hsize = pMon->timings2[i].hsize; 849 vsize = pMon->timings2[i].vsize; 850 } 851 852 if (max_hsize != 0) { 853 *width = max_hsize; 854 *height = vsize; 855 return TRUE; 856 } 857 858 /* checking detailed monitor section */ 859 860 /* !!! skip Ranges and standard timings */ 861 862 /* check detailed timings */ 863 for (i = 0; i < DET_TIMINGS; i++) 864 if (pMon->det_mon[i].type == DT) { 865 struct detailed_timings timing = pMon->det_mon[i].section.d_timings; 866 867 /* ignore v_active for now */ 868 if ((timing.clock > 15000000) && (timing.h_active > max_hsize)) { 869 max_hsize = timing.h_active; 870 vsize = timing.v_active; 871 } 872 } 873 874 if (max_hsize != 0) { 875 *width = max_hsize; 876 *height = vsize; 877 return TRUE; 878 } 879 return FALSE; 880} 881 882static Bool 883ViaPanelGetSizeFromDDCv1(xf86OutputPtr output, int *width, int *height) 884{ 885 ScrnInfoPtr pScrn = output->scrn; 886 VIAPtr pVia = VIAPTR(pScrn); 887 xf86MonPtr pMon; 888 889 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 890 "Entered VIAGetPanelSizeFromDDCv1.\n")); 891 892 if (!pVia->pI2CBus2) { 893 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 894 "I2C Bus 2 does not exist.\n"); 895 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 896 "Exiting VIAGetPanelSizeFromDDCv1.\n")); 897 return FALSE; 898 } 899 900 if (!xf86I2CProbeAddress(pVia->pI2CBus2, 0xA0)) { 901 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 902 "I2C device on I2C Bus 2 does not support EDID.\n"); 903 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 904 "Exiting VIAGetPanelSizeFromDDCv1.\n")); 905 return FALSE; 906 } 907 908 /* Probe I2C Bus 2 to see if a flat panel is connected. */ 909 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 910 "Probing for a flat panel on I2C Bus 2.\n"); 911 pMon = xf86OutputGetEDID(output, pVia->pI2CBus2); 912 if (pMon && DIGITAL(pMon->features.input_type)) { 913 xf86OutputSetEDID(output, pMon); 914 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 915 "Detected a flat panel on I2C Bus 2.\n"); 916 } else { 917 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 918 "Did not detect a flat panel on I2C Bus 2.\n"); 919 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 920 "Exiting VIAGetPanelSizeFromDDCv1.\n")); 921 return FALSE; 922 923 } 924 925 if (!ViaPanelGetSizeFromEDID(pScrn, pMon, width, height)) { 926 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 927 "Unable to obtain panel size from EDID information.\n"); 928 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 929 "Exiting VIAGetPanelSizeFromDDCv1.\n")); 930 return FALSE; 931 } 932 933 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 934 "VIAGetPanelSizeFromDDCv1: (%d X %d)\n", 935 *width, *height)); 936 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 937 "Exiting VIAGetPanelSizeFromDDCv1.\n")); 938 return TRUE; 939} 940 941/* 942 * Gets the native panel resolution from scratch pad registers. 943 */ 944static void 945viaLVDSGetFPInfoFromScratchPad(xf86OutputPtr output) 946{ 947 ScrnInfoPtr pScrn = output->scrn; 948 vgaHWPtr hwp = VGAHWPTR(pScrn); 949 ViaPanelInfoPtr panel = output->driver_private; 950 CARD8 index; 951 952 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 953 "Entered viaLVDSGetFPInfoFromScratchPad.\n")); 954 955 index = hwp->readCrtc(hwp, 0x3F) & 0x0F; 956 957 panel->NativeModeIndex = index; 958 panel->NativeWidth = ViaPanelNativeModes[index].Width; 959 panel->NativeHeight = ViaPanelNativeModes[index].Height; 960 panel->useDualEdge = ViaPanelNativeModes[index].useDualEdge; 961 panel->useDithering = ViaPanelNativeModes[index].useDithering; 962 963 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 964 "VIA Technologies VGA BIOS Scratch Pad Register " 965 "Flat Panel Index: %d\n", 966 panel->NativeModeIndex); 967 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 968 "Flat Panel Native Resolution: %dx%d\n", 969 panel->NativeWidth, panel->NativeHeight); 970 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 971 "Flat Panel Dual Edge Transfer: %s\n", 972 panel->useDualEdge ? "On" : "Off"); 973 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 974 "Flat Panel Output Color Dithering: %s\n", 975 panel->useDithering ? "On (18 bit)" : "Off (24 bit)"); 976 977 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 978 "Exiting viaLVDSGetFPInfoFromScratchPad.\n")); 979} 980 981static void 982ViaPanelCenterMode(DisplayModePtr mode, DisplayModePtr adjusted_mode) 983{ 984 int panelHSyncTime = adjusted_mode->HSyncEnd - adjusted_mode->HSyncStart; 985 int panelVSyncTime = adjusted_mode->VSyncEnd - adjusted_mode->VSyncStart; 986 int panelHBlankStart = adjusted_mode->HDisplay; 987 int panelVBlankStart = adjusted_mode->VDisplay; 988 int hBorder = (adjusted_mode->HDisplay - mode->HDisplay)/2; 989 int vBorder = (adjusted_mode->VDisplay - mode->VDisplay)/2; 990 int newHBlankStart = hBorder + mode->HDisplay; 991 int newVBlankStart = vBorder + mode->VDisplay; 992 993 adjusted_mode->HDisplay = mode->HDisplay; 994 adjusted_mode->HSyncStart = (adjusted_mode->HSyncStart - panelHBlankStart) + newHBlankStart; 995 adjusted_mode->HSyncEnd = adjusted_mode->HSyncStart + panelHSyncTime; 996 adjusted_mode->VDisplay = mode->VDisplay; 997 adjusted_mode->VSyncStart = (adjusted_mode->VSyncStart - panelVBlankStart) + newVBlankStart; 998 adjusted_mode->VSyncEnd = adjusted_mode->VSyncStart + panelVSyncTime; 999 /* Adjust Crtc H and V */ 1000 adjusted_mode->CrtcHDisplay = adjusted_mode->HDisplay; 1001 adjusted_mode->CrtcHBlankStart = newHBlankStart; 1002 adjusted_mode->CrtcHBlankEnd = adjusted_mode->CrtcHTotal - hBorder; 1003 adjusted_mode->CrtcHSyncStart = adjusted_mode->HSyncStart; 1004 adjusted_mode->CrtcHSyncEnd = adjusted_mode->HSyncEnd; 1005 adjusted_mode->CrtcVDisplay = adjusted_mode->VDisplay; 1006 adjusted_mode->CrtcVBlankStart = newVBlankStart; 1007 adjusted_mode->CrtcVBlankEnd = adjusted_mode->CrtcVTotal - vBorder; 1008 adjusted_mode->CrtcVSyncStart = adjusted_mode->VSyncStart; 1009 adjusted_mode->CrtcVSyncEnd = adjusted_mode->VSyncEnd; 1010} 1011 1012static void 1013ViaPanelScale(ScrnInfoPtr pScrn, int resWidth, int resHeight, 1014 int panelWidth, int panelHeight) 1015{ 1016 VIAPtr pVia = VIAPTR(pScrn); 1017 vgaHWPtr hwp = VGAHWPTR(pScrn); 1018 int horScalingFactor = 0; 1019 int verScalingFactor = 0; 1020 CARD8 cra2 = 0; 1021 CARD8 cr77 = 0; 1022 CARD8 cr78 = 0; 1023 CARD8 cr79 = 0; 1024 CARD8 cr9f = 0; 1025 Bool scaling = FALSE; 1026 1027 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1028 "ViaPanelScale: %d,%d -> %d,%d\n", 1029 resWidth, resHeight, panelWidth, panelHeight)); 1030 1031 if (resWidth < panelWidth) { 1032 /* Load Horizontal Scaling Factor */ 1033 if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) { 1034 horScalingFactor = ((resWidth - 1) * 4096) / (panelWidth - 1); 1035 1036 /* Horizontal scaling enabled */ 1037 cra2 = 0xC0; 1038 cr9f = horScalingFactor & 0x0003; /* HSCaleFactor[1:0] at CR9F[1:0] */ 1039 } else { 1040 /* TODO: Need testing */ 1041 horScalingFactor = ((resWidth - 1) * 1024) / (panelWidth - 1); 1042 } 1043 1044 cr77 = (horScalingFactor & 0x03FC) >> 2; /* HSCaleFactor[9:2] at CR77[7:0] */ 1045 cr79 = (horScalingFactor & 0x0C00) >> 10; /* HSCaleFactor[11:10] at CR79[5:4] */ 1046 cr79 <<= 4; 1047 scaling = TRUE; 1048 } 1049 1050 if (resHeight < panelHeight) { 1051 /* Load Vertical Scaling Factor */ 1052 if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) { 1053 verScalingFactor = ((resHeight - 1) * 2048) / (panelHeight - 1); 1054 1055 /* Vertical scaling enabled */ 1056 cra2 |= 0x08; 1057 cr79 |= ((verScalingFactor & 0x0001) << 3); /* VSCaleFactor[0] at CR79[3] */ 1058 } else { 1059 /* TODO: Need testing */ 1060 verScalingFactor = ((resHeight - 1) * 1024) / (panelHeight - 1); 1061 } 1062 1063 cr78 |= (verScalingFactor & 0x01FE) >> 1; /* VSCaleFactor[8:1] at CR78[7:0] */ 1064 1065 cr79 |= ((verScalingFactor & 0x0600) >> 9) << 6; /* VSCaleFactor[10:9] at CR79[7:6] */ 1066 scaling = TRUE; 1067 } 1068 1069 if (scaling) { 1070 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1071 "Scaling factor: horizontal %d (0x%x), vertical %d (0x%x)\n", 1072 horScalingFactor, horScalingFactor, 1073 verScalingFactor, verScalingFactor)); 1074 1075 ViaCrtcMask(hwp, 0x77, cr77, 0xFF); 1076 ViaCrtcMask(hwp, 0x78, cr78, 0xFF); 1077 ViaCrtcMask(hwp, 0x79, cr79, 0xF8); 1078 1079 if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) { 1080 ViaCrtcMask(hwp, 0x9F, cr9f, 0x03); 1081 } 1082 ViaCrtcMask(hwp, 0x79, 0x03, 0x03); 1083 } else { 1084 /* Disable panel scale */ 1085 ViaCrtcMask(hwp, 0x79, 0x00, 0x01); 1086 } 1087 1088 if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) { 1089 ViaCrtcMask(hwp, 0xA2, cra2, 0xC8); 1090 } 1091 1092 /* Horizontal scaling selection: interpolation */ 1093 // ViaCrtcMask(hwp, 0x79, 0x02, 0x02); 1094 // else 1095 // ViaCrtcMask(hwp, 0x79, 0x00, 0x02); 1096 /* Horizontal scaling factor selection original / linear */ 1097 //ViaCrtcMask(hwp, 0xA2, 0x40, 0x40); 1098} 1099 1100static void 1101ViaPanelScaleDisable(ScrnInfoPtr pScrn) 1102{ 1103 VIAPtr pVia = VIAPTR(pScrn); 1104 vgaHWPtr hwp = VGAHWPTR(pScrn); 1105 1106 ViaCrtcMask(hwp, 0x79, 0x00, 0x01); 1107 /* Disable VX900 down scaling */ 1108 if (pVia->Chipset == VIA_VX900) 1109 ViaCrtcMask(hwp, 0x89, 0x00, 0x01); 1110 if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) 1111 ViaCrtcMask(hwp, 0xA2, 0x00, 0xC8); 1112} 1113 1114static void 1115via_lvds_create_resources(xf86OutputPtr output) 1116{ 1117} 1118 1119static void 1120via_lvds_dpms(xf86OutputPtr output, int mode) 1121{ 1122 ScrnInfoPtr pScrn = output->scrn; 1123 VIAPtr pVia = VIAPTR(pScrn); 1124 1125 switch (mode) { 1126 case DPMSModeOn: 1127 switch (pVia->Chipset) { 1128 case VIA_PM800: 1129 case VIA_P4M800PRO: 1130 case VIA_P4M890: 1131 case VIA_K8M890: 1132 case VIA_P4M900: 1133 case VIA_CX700: 1134 case VIA_VX800: 1135 case VIA_VX855: 1136 case VIA_VX900: 1137 ViaLVDSPower(pScrn, TRUE); 1138 break; 1139 default: 1140 ViaLCDPower(output, TRUE); 1141 break; 1142 } 1143 1144 viaFPIOPadSetting(pScrn, TRUE); 1145 break; 1146 1147 case DPMSModeStandby: 1148 case DPMSModeSuspend: 1149 case DPMSModeOff: 1150 switch (pVia->Chipset) { 1151 case VIA_PM800: 1152 case VIA_P4M800PRO: 1153 case VIA_P4M890: 1154 case VIA_K8M890: 1155 case VIA_P4M900: 1156 case VIA_CX700: 1157 case VIA_VX800: 1158 case VIA_VX855: 1159 case VIA_VX900: 1160 ViaLVDSPower(pScrn, FALSE); 1161 break; 1162 default: 1163 ViaLCDPower(output, FALSE); 1164 break; 1165 } 1166 1167 viaFPIOPadSetting(pScrn, FALSE); 1168 break; 1169 } 1170} 1171 1172static void 1173via_lvds_save(xf86OutputPtr output) 1174{ 1175} 1176 1177static void 1178via_lvds_restore(xf86OutputPtr output) 1179{ 1180 ViaLCDPower(output, TRUE); 1181} 1182 1183static int 1184via_lvds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) 1185{ 1186 ScrnInfoPtr pScrn = output->scrn; 1187 ViaPanelInfoPtr Panel = output->driver_private; 1188 1189 if (Panel->NativeWidth < pMode->HDisplay || 1190 Panel->NativeHeight < pMode->VDisplay) 1191 return MODE_PANEL; 1192 1193 if (!Panel->Scale && Panel->NativeHeight != pMode->VDisplay && 1194 Panel->NativeWidth != pMode->HDisplay) 1195 return MODE_PANEL; 1196 1197 if (!ViaModeDotClockTranslate(pScrn, pMode)) 1198 return MODE_NOCLOCK; 1199 1200 return MODE_OK; 1201} 1202 1203static Bool 1204via_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, 1205 DisplayModePtr adjusted_mode) 1206{ 1207 ViaPanelInfoPtr Panel = output->driver_private; 1208 1209 xf86SetModeCrtc(adjusted_mode, 0); 1210 if (!Panel->Center && (mode->HDisplay < Panel->NativeWidth || 1211 mode->VDisplay < Panel->NativeHeight)) { 1212 Panel->Scale = TRUE; 1213 } else { 1214 Panel->Scale = FALSE; 1215 ViaPanelCenterMode(mode, adjusted_mode); 1216 } 1217 return TRUE; 1218} 1219 1220static void 1221via_lvds_prepare(xf86OutputPtr output) 1222{ 1223 ScrnInfoPtr pScrn = output->scrn; 1224 1225 via_lvds_dpms(output, DPMSModeOff); 1226 viaFPIOPadSetting(pScrn, FALSE); 1227} 1228 1229static void 1230via_lvds_commit(xf86OutputPtr output) 1231{ 1232 ScrnInfoPtr pScrn = output->scrn; 1233 1234 via_lvds_dpms(output, DPMSModeOn); 1235 viaFPIOPadSetting(pScrn, TRUE); 1236} 1237 1238static void 1239via_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode, 1240 DisplayModePtr adjusted_mode) 1241{ 1242 ViaPanelInfoPtr Panel = output->driver_private; 1243 ScrnInfoPtr pScrn = output->scrn; 1244 drmmode_crtc_private_ptr iga = output->crtc->driver_private; 1245 VIAPtr pVia = VIAPTR(pScrn); 1246 1247 if (output->crtc) { 1248 if (Panel->Scale) { 1249 ViaPanelScale(pScrn, mode->HDisplay, mode->VDisplay, 1250 Panel->NativeWidth, 1251 Panel->NativeHeight); 1252 } else { 1253 ViaPanelScaleDisable(pScrn); 1254 } 1255 1256 switch (pVia->Chipset) { 1257 case VIA_P4M900: 1258 viaDFPLowSetDelayTap(pScrn, 0x08); 1259 break; 1260 case VIA_CX700: 1261 viaLVDS2SetDelayTap(pScrn, 0x01); 1262 break; 1263 default: 1264 break; 1265 } 1266 1267 1268 switch (pVia->Chipset) { 1269 case VIA_KM400: 1270 case VIA_K8M800: 1271 case VIA_PM800: 1272 case VIA_P4M800PRO: 1273 viaDFPLowSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); 1274 viaDFPHighSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); 1275 break; 1276 case VIA_P4M890: 1277 case VIA_K8M890: 1278 case VIA_P4M900: 1279 viaDFPLowSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); 1280 viaDVP1SetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); 1281 break; 1282 case VIA_CX700: 1283 case VIA_VX800: 1284 case VIA_VX855: 1285 case VIA_VX900: 1286 viaLVDS2SetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); 1287 1288 /* Set LVDS2 output color dithering. */ 1289 viaLVDS2SetDithering(pScrn, Panel->useDithering ? TRUE : FALSE); 1290 1291 /* Set LVDS2 output format to sequential mode. */ 1292 viaLVDS2SetOutputFormat(pScrn, 0x01); 1293 1294 /* Set LVDS2 output to OPENLDI mode. */ 1295 viaLVDS2SetFormat(pScrn, 0x01); 1296 break; 1297 default: 1298 break; 1299 } 1300 } 1301} 1302 1303static xf86OutputStatus 1304via_lvds_detect(xf86OutputPtr output) 1305{ 1306 xf86OutputStatus status = XF86OutputStatusDisconnected; 1307 ScrnInfoPtr pScrn = output->scrn; 1308 VIAPtr pVia = VIAPTR(pScrn); 1309 ViaPanelInfoPtr panel = output->driver_private; 1310 1311 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1312 "Entered via_lvds_detect.\n")); 1313 1314 /* Hardcode panel size for the OLPC XO-1.5. */ 1315 if (pVia->IsOLPCXO15) { 1316 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 1317 "Setting up OLPC XO-1.5 flat panel.\n"); 1318 panel->NativeWidth = 1200; 1319 panel->NativeHeight = 900; 1320 status = XF86OutputStatusConnected; 1321 goto exit; 1322 } 1323 1324 /* For now, FP detection code will not scan the I2C bus 1325 * in order to obtain EDID since it is often used by DVI 1326 * as well. Hence, reading off the CRTC scratch pad register 1327 * supplied by the VGA BIOS is the only method available 1328 * to figure out the FP native screen resolution. */ 1329 viaLVDSGetFPInfoFromScratchPad(output); 1330 status = XF86OutputStatusConnected; 1331 1332exit: 1333 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1334 "Exiting via_lvds_detect.\n")); 1335 return status; 1336} 1337 1338static DisplayModePtr 1339via_lvds_get_modes(xf86OutputPtr output) 1340{ 1341 ViaPanelInfoPtr pPanel = output->driver_private; 1342 ScrnInfoPtr pScrn = output->scrn; 1343 DisplayModePtr pDisplay_Mode = NULL; 1344 1345 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1346 "Entered via_lvds_get_modes.\n")); 1347 1348 if (output->status == XF86OutputStatusConnected) { 1349 if (!output->MonInfo) { 1350 /* 1351 * Generates a display mode for the native panel resolution, 1352 * using CVT. 1353 */ 1354 if (pPanel->NativeWidth && pPanel->NativeHeight) { 1355 VIAPtr pVia = VIAPTR(pScrn); 1356 1357 if (pVia->IsOLPCXO15) { 1358 pDisplay_Mode = xf86DuplicateMode(&OLPCMode); 1359 } else { 1360 pDisplay_Mode = xf86CVTMode(pPanel->NativeWidth, pPanel->NativeHeight, 1361 60.0f, FALSE, FALSE); 1362 } 1363 1364 if (pDisplay_Mode) { 1365 pDisplay_Mode->CrtcHDisplay = pDisplay_Mode->HDisplay; 1366 pDisplay_Mode->CrtcHSyncStart = pDisplay_Mode->HSyncStart; 1367 pDisplay_Mode->CrtcHSyncEnd = pDisplay_Mode->HSyncEnd; 1368 pDisplay_Mode->CrtcHTotal = pDisplay_Mode->HTotal; 1369 pDisplay_Mode->CrtcHSkew = pDisplay_Mode->HSkew; 1370 pDisplay_Mode->CrtcVDisplay = pDisplay_Mode->VDisplay; 1371 pDisplay_Mode->CrtcVSyncStart = pDisplay_Mode->VSyncStart; 1372 pDisplay_Mode->CrtcVSyncEnd = pDisplay_Mode->VSyncEnd; 1373 pDisplay_Mode->CrtcVTotal = pDisplay_Mode->VTotal; 1374 1375 pDisplay_Mode->CrtcVBlankStart = min(pDisplay_Mode->CrtcVSyncStart, pDisplay_Mode->CrtcVDisplay); 1376 pDisplay_Mode->CrtcVBlankEnd = max(pDisplay_Mode->CrtcVSyncEnd, pDisplay_Mode->CrtcVTotal); 1377 pDisplay_Mode->CrtcHBlankStart = min(pDisplay_Mode->CrtcHSyncStart, pDisplay_Mode->CrtcHDisplay); 1378 pDisplay_Mode->CrtcHBlankEnd = max(pDisplay_Mode->CrtcHSyncEnd, pDisplay_Mode->CrtcHTotal); 1379 pDisplay_Mode->type = M_T_DRIVER | M_T_PREFERRED; 1380 } else { 1381 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1382 "Out of memory. Size: %zu bytes\n", sizeof(DisplayModeRec)); 1383 } 1384 } else { 1385 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1386 "Invalid Flat Panel Screen Resolution: " 1387 "%dx%d\n", 1388 pPanel->NativeWidth, pPanel->NativeHeight); 1389 } 1390 } else { 1391 pDisplay_Mode = xf86OutputGetEDIDModes(output); 1392 } 1393 } 1394 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1395 "Exiting via_lvds_get_modes.\n")); 1396 return pDisplay_Mode; 1397} 1398 1399#ifdef RANDR_12_INTERFACE 1400static Bool 1401via_lvds_set_property(xf86OutputPtr output, Atom property, 1402 RRPropertyValuePtr value) 1403{ 1404 return FALSE; 1405} 1406 1407static Bool 1408via_lvds_get_property(xf86OutputPtr output, Atom property) 1409{ 1410 return FALSE; 1411} 1412#endif 1413 1414static void 1415via_lvds_destroy(xf86OutputPtr output) 1416{ 1417 if (output->driver_private) 1418 free(output->driver_private); 1419 output->driver_private = NULL; 1420} 1421 1422static const xf86OutputFuncsRec via_lvds_funcs = { 1423 .create_resources = via_lvds_create_resources, 1424 .dpms = via_lvds_dpms, 1425 .save = via_lvds_save, 1426 .restore = via_lvds_restore, 1427 .mode_valid = via_lvds_mode_valid, 1428 .mode_fixup = via_lvds_mode_fixup, 1429 .prepare = via_lvds_prepare, 1430 .commit = via_lvds_commit, 1431 .mode_set = via_lvds_mode_set, 1432 .detect = via_lvds_detect, 1433 .get_modes = via_lvds_get_modes, 1434#ifdef RANDR_12_INTERFACE 1435 .set_property = via_lvds_set_property, 1436#endif 1437#ifdef RANDR_13_INTERFACE 1438 .get_property = via_lvds_get_property, 1439#endif 1440 .destroy = via_lvds_destroy 1441}; 1442 1443 1444void 1445via_lvds_init(ScrnInfoPtr pScrn) 1446{ 1447 ViaPanelInfoPtr Panel = (ViaPanelInfoPtr) xnfcalloc(sizeof(ViaPanelInfoRec), 1); 1448 OptionInfoPtr Options = xnfalloc(sizeof(ViaPanelOptions)); 1449 MessageType from = X_DEFAULT; 1450 VIAPtr pVia = VIAPTR(pScrn); 1451 xf86OutputPtr output = NULL; 1452 vgaHWPtr hwp = VGAHWPTR(pScrn); 1453 CARD8 cr3b = 0x00; 1454 CARD8 cr3b_mask = 0x00; 1455 char outputNameBuffer[32]; 1456 1457 if (!Panel) 1458 return; 1459 1460 /* Apparently this is the way VIA Technologies passes */ 1461 /* the presence of a flat panel to the device driver */ 1462 /* via BIOS setup. */ 1463 if (pVia->Chipset == VIA_CLE266) { 1464 cr3b_mask = 0x08; 1465 } else { 1466 cr3b_mask = 0x02; 1467 } 1468 1469 cr3b = hwp->readCrtc(hwp, 0x3B) & cr3b_mask; 1470 1471 if (!cr3b) { 1472 return; 1473 } 1474 1475 memcpy(Options, ViaPanelOptions, sizeof(ViaPanelOptions)); 1476 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, Options); 1477 1478 Panel->NativeModeIndex = VIA_PANEL_INVALID; 1479 1480 /* LCD Center/Expend Option */ 1481 Panel->Center = FALSE; 1482 from = xf86GetOptValBool(Options, OPTION_CENTER, &Panel->Center) 1483 ? X_CONFIG : X_DEFAULT; 1484 xf86DrvMsg(pScrn->scrnIndex, from, "LVDS-0 : DVI Center is %s.\n", 1485 Panel->Center ? "enabled" : "disabled"); 1486 1487 /* The code to dynamically designate a particular FP (i.e., FP-1, 1488 * FP-2, etc.) for xrandr was borrowed from xf86-video-r128 DDX. */ 1489 sprintf(outputNameBuffer, "FP-%d", (pVia->numberFP + 1)); 1490 output = xf86OutputCreate(pScrn, &via_lvds_funcs, outputNameBuffer); 1491 1492 if (output) { 1493 output->driver_private = Panel; 1494 1495 /* While there are two (2) display controllers registered with the 1496 * X.Org Server, it is often desirable to fix FP (Flat Panel) to 1497 * IGA2 since only IGA2 contains panel resolution scaling 1498 * functionality. IGA1 does not have this. */ 1499 output->possible_crtcs = 1 << 1; 1500 1501 output->possible_clones = 0; 1502 output->interlaceAllowed = FALSE; 1503 output->doubleScanAllowed = FALSE; 1504 1505 /* Increment the number of FP connectors. */ 1506 pVia->numberFP++; 1507 1508 if (pVia->IsOLPCXO15) { 1509 output->mm_height = 152; 1510 output->mm_width = 114; 1511 } 1512 } else { 1513 free(Panel); 1514 } 1515} 1516