1/* 2 * Copyright 2005-2016 The OpenChrome Project 3 * [https://www.freedesktop.org/wiki/Openchrome] 4 * Copyright 2004-2005 The Unichrome Project [unichrome.sf.net] 5 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. 6 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sub license, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 * DEALINGS IN THE SOFTWARE. 26 */ 27 28/* 29 * via_analog.c 30 * 31 * Handles the initialization and management of analog VGA related 32 * resources. 33 * 34 */ 35 36#ifdef HAVE_CONFIG_H 37#include "config.h" 38#endif 39 40#include "via_driver.h" 41#include <unistd.h> 42 43 44/* 45 * Enables or disables analog VGA output by controlling DAC 46 * (Digital to Analog Converter) output state. 47 */ 48static void 49viaAnalogOutput(ScrnInfoPtr pScrn, Bool outputState) 50{ 51 vgaHWPtr hwp = VGAHWPTR(pScrn); 52 53 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 54 "Entered viaAnalogOutput.\n")); 55 56 /* This register controls analog VGA DAC output state. */ 57 /* 3X5.47[2] - DACOFF Backdoor Register 58 * 0: DAC on 59 * 1: DAC off */ 60 ViaCrtcMask(hwp, 0x47, outputState ? 0x00 : 0x04, 0x04); 61 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 62 "Analog VGA Output: %s\n", 63 outputState ? "On" : "Off"); 64 65 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 66 "Exiting viaAnalogOutput.\n")); 67} 68 69/* 70 * Specifies IGA1 or IGA2 for analog VGA DAC source. 71 */ 72static void 73viaAnalogSetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource) 74{ 75 vgaHWPtr hwp = VGAHWPTR(pScrn); 76 CARD8 value = displaySource; 77 78 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 79 "Entered viaAnalogSetDisplaySource.\n")); 80 81 ViaSeqMask(hwp, 0x16, value << 6, 0x40); 82 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 83 "Analog VGA Display Output Source: IGA%d\n", 84 (value & 0x01) + 1); 85 86 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 87 "Exiting viaAnalogSetDisplaySource.\n")); 88} 89 90/* 91 * Intializes analog VGA related registers. 92 */ 93static void 94viaAnalogInit(ScrnInfoPtr pScrn) 95{ 96 vgaHWPtr hwp = VGAHWPTR(pScrn); 97 VIAPtr pVia = VIAPTR(pScrn); 98 99 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 100 "Entered viaAnalogInit.\n")); 101 102 /* 3X5.37[7] - DAC Power Save Control 1 103 * 0: Depend on Rx3X5.37[5:4] setting 104 * 1: DAC always goes into power save mode 105 * 3X5.37[6] - DAC Power Down Control 106 * 0: Depend on Rx3X5.47[2] setting 107 * 1: DAC never goes to power down mode 108 * 3X5.37[5:4] - DAC Power Save Control 2 109 * 00: DAC never goes to power save mode 110 * 01: DAC goes to power save mode by line 111 * 10: DAC goes to power save mode by frame 112 * 11: DAC goes to power save mode by line and frame 113 * 3X5.37[3] - DAC PEDESTAL Control 114 * 3X5.37[2:0] - DAC Factor 115 * (Default: 100) */ 116 ViaCrtcMask(hwp, 0x37, 0x04, 0xFF); 117 118 switch (pVia->Chipset) { 119 case VIA_CX700: 120 case VIA_VX800: 121 case VIA_VX855: 122 case VIA_VX900: 123 /* 3C5.5E[0] - CRT DACOFF Setting 124 * 1: CRT DACOFF controlled by 3C5.01[5] */ 125 ViaSeqMask(hwp, 0x5E, 0x01, 0x01); 126 break; 127 default: 128 break; 129 } 130 131 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 132 "Exiting viaAnalogInit.\n")); 133} 134 135/* 136 * Sets the polarity of horizontal synchronization and vertical 137 * synchronization. 138 */ 139static void 140viaAnalogSetSyncPolarity(ScrnInfoPtr pScrn, DisplayModePtr mode) 141{ 142 vgaHWPtr hwp = VGAHWPTR(pScrn); 143 CARD8 miscRegister; 144 145 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 146 "Entered viaAnalogSetSyncPolarity.\n")); 147 148/* Set certain bits of miscellaneous output register 149 * meant for IGA1. */ 150 miscRegister = hwp->readMiscOut(hwp); 151 if (mode->Flags & V_NHSYNC) { 152 miscRegister |= 0x40; 153 } else { 154 miscRegister &= (~0x40); 155 } 156 157 if (mode->Flags & V_NVSYNC) { 158 miscRegister |= 0x80; 159 } else { 160 miscRegister &= (~0x80); 161 } 162 163 hwp->writeMiscOut(hwp, miscRegister); 164 165 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 166 "Exiting viaAnalogSetSyncPolarity.\n")); 167} 168 169 170static void 171via_analog_create_resources(xf86OutputPtr output) 172{ 173} 174 175static void 176via_analog_dpms(xf86OutputPtr output, int mode) 177{ 178 ScrnInfoPtr pScrn = output->scrn; 179 180 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 181 "Entered via_analog_dpms.\n")); 182 183 switch (mode) { 184 case DPMSModeOn: 185 viaAnalogOutput(pScrn, TRUE); 186 break; 187 case DPMSModeStandby: 188 case DPMSModeSuspend: 189 case DPMSModeOff: 190 viaAnalogOutput(pScrn, FALSE); 191 break; 192 default: 193 break; 194 } 195 196 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 197 "Exiting via_analog_dpms.\n")); 198} 199 200static void 201via_analog_save(xf86OutputPtr output) 202{ 203} 204 205static void 206via_analog_restore(xf86OutputPtr output) 207{ 208} 209 210static int 211via_analog_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) 212{ 213 ScrnInfoPtr pScrn = output->scrn; 214 215 if (!ViaModeDotClockTranslate(pScrn, pMode)) 216 return MODE_NOCLOCK; 217 return MODE_OK; 218} 219 220static Bool 221via_analog_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, 222 DisplayModePtr adjusted_mode) 223{ 224 return TRUE; 225} 226 227static void 228via_analog_prepare(xf86OutputPtr output) 229{ 230 via_analog_dpms(output, DPMSModeOff); 231} 232 233static void 234via_analog_commit(xf86OutputPtr output) 235{ 236 via_analog_dpms(output, DPMSModeOn); 237} 238 239static void 240via_analog_mode_set(xf86OutputPtr output, DisplayModePtr mode, 241 DisplayModePtr adjusted_mode) 242{ 243 ScrnInfoPtr pScrn = output->scrn; 244 drmmode_crtc_private_ptr iga = output->crtc->driver_private; 245 246 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 247 "Entered via_analog_mode_set.\n")); 248 249 if (output->crtc) { 250 viaAnalogInit(pScrn); 251 viaAnalogSetSyncPolarity(pScrn, adjusted_mode); 252 viaAnalogSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00); 253 } 254 255 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 256 "Exiting via_analog_mode_set.\n")); 257} 258 259static xf86OutputStatus 260via_analog_detect(xf86OutputPtr output) 261{ 262 xf86OutputStatus status = XF86OutputStatusDisconnected; 263 ScrnInfoPtr pScrn = output->scrn; 264 VIAPtr pVia = VIAPTR(pScrn); 265 xf86MonPtr mon; 266 267 /* Probe I2C Bus 1 to see if a VGA monitor is connected. */ 268 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 269 "Probing for a VGA monitor on I2C Bus 1.\n"); 270 mon = xf86OutputGetEDID(output, pVia->pI2CBus1); 271 if (mon && (!mon->features.input_type)) { 272 xf86OutputSetEDID(output, mon); 273 status = XF86OutputStatusConnected; 274 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 275 "Detected a VGA monitor on I2C Bus 1.\n"); 276 } else { 277 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 278 "Did not detect a VGA monitor on I2C Bus 1.\n"); 279 280 /* Probe I2C Bus 2 to see if a VGA monitor is connected. */ 281 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 282 "Probing for a VGA monitor on I2C Bus 2.\n"); 283 mon = xf86OutputGetEDID(output, pVia->pI2CBus2); 284 if (mon && (!mon->features.input_type)) { 285 xf86OutputSetEDID(output, mon); 286 status = XF86OutputStatusConnected; 287 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 288 "Detected a VGA monitor on I2C Bus 2.\n"); 289 } else { 290 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 291 "Did not detect a VGA monitor on I2C Bus 2.\n"); 292 293 /* Perform manual detection of a VGA monitor since */ 294 /* it was not detected via I2C buses. */ 295 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 296 "Now perform manual detection of a VGA " 297 "monitor.\n"); 298 vgaHWPtr hwp = VGAHWPTR(pScrn); 299 CARD8 SR01 = hwp->readSeq(hwp, 0x01); 300 CARD8 SR40 = hwp->readSeq(hwp, 0x40); 301 CARD8 CR36 = hwp->readCrtc(hwp, 0x36); 302 303 /* We have to power on the display to detect it */ 304 ViaSeqMask(hwp, 0x01, 0x00, 0x20); 305 ViaCrtcMask(hwp, 0x36, 0x00, 0xF0); 306 307 /* Wait for vblank */ 308 usleep(16); 309 310 /* Detect the load on pins */ 311 ViaSeqMask(hwp, 0x40, 0x80, 0x80); 312 313 if ((VIA_CX700 == pVia->Chipset) || 314 (VIA_VX800 == pVia->Chipset) || 315 (VIA_VX855 == pVia->Chipset) || 316 (VIA_VX900 == pVia->Chipset)) 317 ViaSeqMask(hwp, 0x40, 0x00, 0x80); 318 319 if (ViaVgahwIn(hwp, 0x3C2) & 0x20) { 320 status = XF86OutputStatusConnected; 321 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 322 "Detected a VGA monitor using manual " 323 "detection method.\n"); 324 } 325 326 if ((VIA_CX700 == pVia->Chipset) || 327 (VIA_VX800 == pVia->Chipset) || 328 (VIA_VX855 == pVia->Chipset) || 329 (VIA_VX900 == pVia->Chipset)) 330 ViaSeqMask(hwp, 0x40, 0x00, 0x80); 331 332 /* Restore previous state */ 333 hwp->writeSeq(hwp, 0x40, SR40); 334 hwp->writeSeq(hwp, 0x01, SR01); 335 hwp->writeCrtc(hwp, 0x36, CR36); 336 } 337 } 338 339 return status; 340} 341 342#ifdef RANDR_12_INTERFACE 343static Bool 344via_analog_set_property(xf86OutputPtr output, Atom property, 345 RRPropertyValuePtr value) 346{ 347 return TRUE; 348} 349#endif 350 351#ifdef RANDR_13_INTERFACE 352static Bool 353via_analog_get_property(xf86OutputPtr output, Atom property) 354{ 355 return FALSE; 356} 357#endif 358 359static void 360via_analog_destroy(xf86OutputPtr output) 361{ 362} 363 364static const xf86OutputFuncsRec via_analog_funcs = { 365 .create_resources = via_analog_create_resources, 366 .dpms = via_analog_dpms, 367 .save = via_analog_save, 368 .restore = via_analog_restore, 369 .mode_valid = via_analog_mode_valid, 370 .mode_fixup = via_analog_mode_fixup, 371 .prepare = via_analog_prepare, 372 .commit = via_analog_commit, 373 .mode_set = via_analog_mode_set, 374 .detect = via_analog_detect, 375 .get_modes = xf86OutputGetEDIDModes, 376#ifdef RANDR_12_INTERFACE 377 .set_property = via_analog_set_property, 378#endif 379#ifdef RANDR_13_INTERFACE 380 .get_property = via_analog_get_property, 381#endif 382 .destroy = via_analog_destroy, 383}; 384 385void 386via_analog_init(ScrnInfoPtr pScrn) 387{ 388 VIAPtr pVia = VIAPTR(pScrn); 389 VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; 390 xf86OutputPtr output = NULL; 391 char outputNameBuffer[32]; 392 393 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 394 "Entered via_analog_init.\n")); 395 396 if (!pVia->pI2CBus1 || !pVia->pI2CBus2) { 397 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 398 "I2C Bus 1 or I2C Bus 2 does not exist.\n"); 399 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 400 "Exiting via_analog_init.\n")); 401 return; 402 } 403 404 /* The code to dynamically designate the output name for 405 * xrandr was borrowed from xf86-video-r128 DDX. */ 406 sprintf(outputNameBuffer, "VGA-%d", (pVia->numberVGA + 1)); 407 output = xf86OutputCreate(pScrn, &via_analog_funcs, outputNameBuffer); 408 409 /* While there are two (2) display controllers registered with the 410 * X.Org Server, it is often desirable to fix the analog VGA output 411 * to IGA1 since LVDS FP (Flat Panel) typically prefers IGA2. (While 412 * it is not used at this point, only IGA2 contains panel resolution 413 * scaling functionality. IGA1 does not have this.) 414 * With this arrangement, DVI should end up getting assigned to IGA2 415 * since DVI can go to either display controller without limitations. 416 * This should be the case for TV as well. */ 417 output->possible_crtcs = (1 << 0); 418 419 output->possible_clones = 0; 420 output->interlaceAllowed = TRUE; 421 output->doubleScanAllowed = FALSE; 422 pBIOSInfo->analog = output; 423 424 /* Increment the number of analog VGA connectors. */ 425 pVia->numberVGA++; 426 427 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 428 "Exiting via_analog_init.\n")); 429} 430