1 /*
2  * Copyright 2016 Kevin Brace
3  * Copyright 2015-2016 The OpenChrome Project
4  *                     [https://www.freedesktop.org/wiki/Openchrome]
5  * Copyright 2014 SHS SERVICES GmbH
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  * via_tmds.c
29  *
30  * Handles initialization of TMDS (DVI) related resources and
31  * controls the integrated TMDS transmitter found in CX700 and
32  * later VIA Technologies chipsets.
33  *
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #include <unistd.h>
41 #include "via_driver.h"
42 #include "via_vt1632.h"
43 #include "via_sii164.h"
44 
45 
46 /*
47 	1. Formula:
48 		2^13 X 0.0698uSec [1/14.318MHz] = 8192 X 0.0698uSec =572.1uSec
49 		Timer = Counter x 572 uSec
50 	2. Note:
51 		0.0698 uSec is too small to compute for hardware. So we multiply a
52 		reference value(2^13) to make it big enough to compute for hardware.
53 	3. Note:
54 		The meaning of the TD0~TD3 are count of the clock.
55 		TD(sec) = (sec)/(per clock) x (count of clocks)
56 */
57 #define TD0 200
58 #define TD1 25
59 #define TD2 0
60 #define TD3 25
61 
62 
63 /*
64  * Initializes most registers related to VIA Technologies IGP
65  * integrated TMDS transmitter. Synchronization polarity and
66  * display output source need to be set separately. */
67 static void
viaTMDSInitRegisters(ScrnInfoPtr pScrn)68 viaTMDSInitRegisters(ScrnInfoPtr pScrn)
69 {
70     vgaHWPtr hwp = VGAHWPTR(pScrn);
71 
72     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
73                         "Entered viaTMDSInitRegisters.\n"));
74 
75     /* Activate DVI + LVDS2 mode. */
76     /* 3X5.D2[5:4] - Display Channel Select
77      *               00: LVDS1 + LVDS2
78      *               01: DVI + LVDS2
79      *               10: One Dual LVDS Channel (High Resolution Pannel)
80      *               11: Single Channel DVI */
81     ViaCrtcMask(hwp, 0xD2, 0x10, 0x30);
82 
83     /* Various DVI PLL settings should be set to default settings. */
84     /* 3X5.D1[7]   - PLL2 Reference Clock Edge Select Bit
85      *               0: PLLCK lock to rising edge of reference clock
86      *               1: PLLCK lock to falling edge of reference clock
87      * 3X5.D1[6:5] - PLL2 Charge Pump Current Set Bits
88      *               00: ICH = 12.5 uA
89      *               01: ICH = 25.0 uA
90      *               10: ICH = 37.5 uA
91      *               11: ICH = 50.0 uA
92      * 3X5.D1[4:1] - Reserved
93      * 3X5.D1[0]   - PLL2 Control Voltage Measurement Enable Bit */
94     ViaCrtcMask(hwp, 0xD1, 0x00, 0xE1);
95 
96     /* Disable DVI test mode. */
97     /* 3X5.D5[7] - PD1 Enable Selection
98      *             1: Select by power flag
99      *             0: By register
100      * 3X5.D5[5] - DVI Testing Mode Enable
101      * 3X5.D5[4] - DVI Testing Format Selection
102      *             0: Half cycle
103      *             1: LFSR mode */
104     ViaCrtcMask(hwp, 0xD5, 0x00, 0xB0);
105 
106     /* Disable DVI sense interrupt. */
107     /* 3C5.2B[7] - DVI Sense Interrupt Enable
108      *             0: Disable
109      *             1: Enable */
110     ViaSeqMask(hwp, 0x2B, 0x00, 0x80);
111 
112     /* Clear DVI sense interrupt status. */
113     /* 3C5.2B[6] - DVI Sense Interrupt Status
114      *             (This bit has a RW1C attribute.) */
115     ViaSeqMask(hwp, 0x2B, 0x40, 0x40);
116 
117     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
118                         "Exiting viaTMDSInitRegisters.\n"));
119 }
120 
121 /*
122  * Sets the polarity of horizontal synchronization and vertical
123  * synchronization.
124  */
125 static void
viaTMDSSetSyncPolarity(ScrnInfoPtr pScrn,DisplayModePtr mode)126 viaTMDSSetSyncPolarity(ScrnInfoPtr pScrn, DisplayModePtr mode)
127 {
128     vgaHWPtr hwp = VGAHWPTR(pScrn);
129     CARD8 cr97;
130 
131     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
132                         "Entered viaTMDSSetSyncPolarity.\n"));
133 
134     /* 3X5.97[6] - DVI (TMDS) VSYNC Polarity
135      *             0: Positive
136      *             1: Negative
137      * 3X5.97[5] - DVI (TMDS) HSYNC Polarity
138      *             0: Positive
139      *             1: Negative */
140     cr97 = hwp->readCrtc(hwp, 0x97);
141     if (mode->Flags & V_NHSYNC) {
142         cr97 |= 0x20;
143     } else {
144         cr97 &= (~0x20);
145     }
146 
147     if (mode->Flags & V_NVSYNC) {
148         cr97 |= 0x40;
149     } else {
150         cr97 &= (~0x40);
151     }
152 
153     ViaCrtcMask(hwp, 0x97, cr97, 0x60);
154 
155     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
156                         "Exiting viaTMDSSetSyncPolarity.\n"));
157 }
158 
159 /*
160  * Sets IGA1 or IGA2 as the display output source for VIA Technologies IGP
161  * integrated TMDS transmitter.
162  */
163 static void
viaTMDSSetSource(ScrnInfoPtr pScrn,CARD8 displaySource)164 viaTMDSSetSource(ScrnInfoPtr pScrn, CARD8 displaySource)
165 {
166     vgaHWPtr hwp = VGAHWPTR(pScrn);
167     CARD8 temp = displaySource;
168 
169     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
170                         "Entered viaTMDSSetSource.\n"));
171 
172     /* Set integrated TMDS transmitter display output source.
173      * The integrated TMDS transmitter appears to utilize LVDS1's data
174      * source selection bit (3X5.99[4]). */
175     /* 3X5.99[4] - LVDS Channel1 Data Source Selection
176      *             0: Primary Display
177      *             1: Secondary Display */
178     ViaCrtcMask(hwp, 0x99, temp << 4, 0x10);
179     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
180                 "Integrated TMDS Transmitter Display Output Source: IGA%d\n",
181                 (temp & 0x01) + 1);
182 
183     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
184                         "Exiting viaTMDSSetSource.\n"));
185 }
186 
187 /*
188  * Returns TMDS receiver detection state for VIA Technologies IGP
189  * integrated TMDS transmitter.
190  */
191 static Bool
viaTMDSSense(ScrnInfoPtr pScrn)192 viaTMDSSense(ScrnInfoPtr pScrn)
193 {
194     vgaHWPtr hwp = VGAHWPTR(pScrn);
195     VIAPtr pVia = VIAPTR(pScrn);
196     CARD8 tmdsReceiverDetected = 0x00;
197 
198     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
199                         "Entered viaTMDSSense.\n"));
200 
201     /* For now, faking DVI detection.*/
202     tmdsReceiverDetected = 0x01;
203 
204     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
205                 "Integrated TMDS transmitter %s a TMDS receiver.\n",
206                 (tmdsReceiverDetected & 0x01) ? "detected" : "did not detect");
207 
208     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
209                         "Exiting viaTMDSSense.\n"));
210     return tmdsReceiverDetected;
211 }
212 
213 static void
viaTMDSPower(ScrnInfoPtr pScrn,Bool powerState)214 viaTMDSPower(ScrnInfoPtr pScrn, Bool powerState)
215 {
216     vgaHWPtr hwp = VGAHWPTR(pScrn);
217 
218     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
219                         "Entered viaTMDSPower.\n"));
220 
221     if (powerState) {
222         /* 3X5.91[7] - Software Direct On / Off Display Period
223                        in the Panel Path
224                        0: On
225                        1: Off */
226         ViaCrtcMask(hwp, 0x91, 0x00, 0x80);
227 
228         /* 3X5.91[0] - Hardware or Software Control Power Sequence
229                        1: Software Control */
230         ViaCrtcMask(hwp, 0x91, 0x01, 0x01);
231 
232         usleep(TD0);
233 
234         /* 3X5.91[4] - Software VDD On
235                        0: Off
236                        1: On */
237         ViaCrtcMask(hwp, 0x91, 0x10, 0x10);
238 
239         usleep(TD1);
240 
241         /* 3X5.91[3] - Software Data On
242                        0: Off
243                        1: On */
244         ViaCrtcMask(hwp, 0x91, 0x08, 0x08);
245 
246         /* 3X5.D2[3] - Power Down (Active High) for DVI
247          *             0: TMDS power on
248          *             1: TMDS power down */
249         ViaCrtcMask(hwp, 0xD2, 0x00, 0x08);
250     } else {
251         ViaCrtcMask(hwp, 0xD2, 0x08, 0x08);
252 
253         ViaCrtcMask(hwp, 0x91, 0x00, 0x08);
254 
255         usleep(TD1);
256 
257         ViaCrtcMask(hwp, 0x91, 0x00, 0x10);
258     }
259 
260     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
261                 "Integrated TMDS (DVI) Power: %s\n",
262                 powerState ? "On" : "Off");
263 
264     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
265                         "Exiting viaTMDSPower.\n"));
266 }
267 
268 static void
viaTMDSIOPadSetting(ScrnInfoPtr pScrn,Bool ioPadOn)269 viaTMDSIOPadSetting(ScrnInfoPtr pScrn, Bool ioPadOn)
270 {
271     vgaHWPtr hwp = VGAHWPTR(pScrn);
272     VIAPtr pVia = VIAPTR(pScrn);
273     CARD8 sr12, sr13, sr5a;
274 
275     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
276                         "Entered viaTMDSIOPadSetting.\n"));
277 
278     if ((pVia->Chipset == VIA_CX700)
279         || (pVia->Chipset == VIA_VX800)
280         || (pVia->Chipset == VIA_VX855)
281         || (pVia->Chipset == VIA_VX900)) {
282 
283         sr5a = hwp->readSeq(hwp, 0x5A);
284         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
285                             "SR5A: 0x%02X\n", sr5a));
286         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
287                             "Setting 3C5.5A[0] to 0.\n"));
288         ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
289     }
290 
291     sr12 = hwp->readSeq(hwp, 0x12);
292     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
293                         "SR12: 0x%02X\n", sr12));
294     sr13 = hwp->readSeq(hwp, 0x13);
295     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
296                         "SR13: 0x%02X\n", sr13));
297 
298     switch (pVia->Chipset) {
299     case VIA_CX700:
300     case VIA_VX800:
301     case VIA_VX855:
302     case VIA_VX900:
303         /* 3C5.13[7:6] - DVP1D15 and DVP1D14 pin strappings
304          *               00: LVDS1 + LVDS2
305          *               01: DVI + LVDS2
306          *               10: Dual LVDS (LVDS1 + LVDS2 used
307          *                   simultaneously)
308          *               11: DVI only */
309         if ((((~(sr13 & 0x80)) && (sr13 & 0x40))
310              || ((sr13 & 0x80) && (sr13 & 0x40)))
311            || (pVia->isVIANanoBook)) {
312 
313             viaLVDS1SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00);
314         }
315 
316         break;
317     default:
318         break;
319     }
320 
321     if ((pVia->Chipset == VIA_CX700)
322         || (pVia->Chipset == VIA_VX800)
323         || (pVia->Chipset == VIA_VX855)
324         || (pVia->Chipset == VIA_VX900)) {
325 
326         hwp->writeSeq(hwp, 0x5A, sr5a);
327         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
328                             "Restoring 3C5.5A[0].\n"));
329     }
330 
331     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
332                         "Exiting viaTMDSIOPadSetting.\n"));
333 }
334 
335 void
viaExtTMDSSetDisplaySource(ScrnInfoPtr pScrn,CARD8 displaySource)336 viaExtTMDSSetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
337 {
338     vgaHWPtr hwp = VGAHWPTR(pScrn);
339     VIAPtr pVia = VIAPTR(pScrn);
340     CARD8 sr12, sr13, sr5a;
341 
342     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
343                         "Entered viaExtTMDSSetDisplaySource.\n"));
344 
345     if ((pVia->Chipset == VIA_CX700)
346         || (pVia->Chipset == VIA_VX800)
347         || (pVia->Chipset == VIA_VX855)
348         || (pVia->Chipset == VIA_VX900)) {
349 
350         sr5a = hwp->readSeq(hwp, 0x5A);
351         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
352                             "SR5A: 0x%02X\n", sr5a));
353         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
354                             "Setting 3C5.5A[0] to 0.\n"));
355         ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
356     }
357 
358     sr12 = hwp->readSeq(hwp, 0x12);
359     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
360                         "SR12: 0x%02X\n", sr12));
361     sr13 = hwp->readSeq(hwp, 0x13);
362     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
363                         "SR13: 0x%02X\n", sr13));
364     switch (pVia->Chipset) {
365     case VIA_CLE266:
366         /* 3C5.12[5] - FPD18 pin strapping
367          *             0: DIP0 (Digital Interface Port 0) is used by
368          *                a TMDS transmitter (DVI)
369          *             1: DIP0 (Digital Interface Port 0) is used by
370          *                a TV encoder */
371         if (!(sr12 & 0x20)) {
372             viaDIP0SetDisplaySource(pScrn, displaySource);
373         } else {
374             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
375                         "DIP0 was not set up for "
376                         "TMDS transmitter use.\n");
377         }
378 
379         break;
380     case VIA_KM400:
381     case VIA_K8M800:
382     case VIA_PM800:
383     case VIA_P4M800PRO:
384         /* 3C5.13[3] - DVP0D8 pin strapping
385          *             0: AGP pins are used for AGP
386          *             1: AGP pins are used by FPDP
387          *                (Flat Panel Display Port)
388          * 3C5.12[6] - DVP0D6 pin strapping
389          *             0: Disable DVP0 (Digital Video Port 0)
390          *             1: Enable DVP0 (Digital Video Port 0)
391          * 3C5.12[5] - DVP0D5 pin strapping
392          *             0: DVP0 is used by a TMDS transmitter (DVI)
393          *             1: DVP0 is used by a TV encoder
394          * 3C5.12[4] - DVP0D4 pin strapping
395          *             0: Dual 12-bit FPDP (Flat Panel Display Port)
396          *             1: 24-bit FPDP (Flat Panel Display Port) */
397         if ((sr12 & 0x40) && (!(sr12 & 0x20))) {
398             viaDVP0SetDisplaySource(pScrn, displaySource);
399         } else if ((sr13 & 0x08) && (!(sr12 & 0x10))) {
400             viaDFPLowSetDisplaySource(pScrn, displaySource);
401         } else {
402             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
403                         "None of the external ports were set up for "
404                         "TMDS transmitter use.\n");
405         }
406 
407         break;
408     case VIA_P4M890:
409     case VIA_K8M890:
410     case VIA_P4M900:
411         /* 3C5.12[6] - FPD6 pin strapping
412          *             0: Disable DVP0 (Digital Video Port 0)
413          *             1: Enable DVP0 (Digital Video Port 0)
414          * 3C5.12[5] - FPD5 pin strapping
415          *             0: DVP0 is used by a TMDS transmitter (DVI)
416          *             1: DVP0 is used by a TV encoder */
417         if ((sr12 & 0x40) && (!(sr12 & 0x20))) {
418             viaDVP0SetDisplaySource(pScrn, displaySource);
419         } else if (!(sr12 & 0x10)) {
420             viaDFPLowSetDisplaySource(pScrn, displaySource);
421         } else {
422             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
423                         "None of the external ports were set up for "
424                         "TMDS transmitter use.\n");
425         }
426 
427         break;
428     case VIA_CX700:
429     case VIA_VX800:
430     case VIA_VX855:
431     case VIA_VX900:
432         /* 3C5.13[6] - DVP1 DVP / capture port selection
433          *             0: DVP1 is used as a DVP (Digital Video Port)
434          *             1: DVP1 is used as a capture port
435          */
436         if (!(sr13 & 0x40)) {
437             viaDVP1SetDisplaySource(pScrn, displaySource);
438         } else {
439             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
440                         "DVP1 is not set up for TMDS "
441                         "transmitter use.\n");
442         }
443 
444         break;
445     default:
446         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
447                     "Unrecognized IGP for "
448                     "TMDS transmitter use.\n");
449         break;
450     }
451 
452     if ((pVia->Chipset == VIA_CX700)
453         || (pVia->Chipset == VIA_VX800)
454         || (pVia->Chipset == VIA_VX855)
455         || (pVia->Chipset == VIA_VX900)) {
456 
457         hwp->writeSeq(hwp, 0x5A, sr5a);
458         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
459                             "Restoring 3C5.5A[0].\n"));
460     }
461 
462     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
463                         "Exiting viaExtTMDSSetDisplaySource.\n"));
464 }
465 
466 void
viaExtTMDSEnableIOPads(ScrnInfoPtr pScrn,CARD8 ioPadState)467 viaExtTMDSEnableIOPads(ScrnInfoPtr pScrn, CARD8 ioPadState)
468 {
469 
470     vgaHWPtr hwp = VGAHWPTR(pScrn);
471     VIAPtr pVia = VIAPTR(pScrn);
472     CARD8 sr12, sr13, sr5a;
473 
474     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
475                         "Entered viaExtTMDSEnableIOPads.\n"));
476 
477     if ((pVia->Chipset == VIA_CX700)
478         || (pVia->Chipset == VIA_VX800)
479         || (pVia->Chipset == VIA_VX855)
480         || (pVia->Chipset == VIA_VX900)) {
481 
482         sr5a = hwp->readSeq(hwp, 0x5A);
483         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
484                             "SR5A: 0x%02X\n", sr5a));
485         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
486                             "Setting 3C5.5A[0] to 0.\n"));
487         ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
488     }
489 
490     sr12 = hwp->readSeq(hwp, 0x12);
491     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
492                         "SR12: 0x%02X\n", sr12));
493     sr13 = hwp->readSeq(hwp, 0x13);
494     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
495                         "SR13: 0x%02X\n", sr13));
496     switch (pVia->Chipset) {
497     case VIA_CLE266:
498         /* 3C5.12[5] - FPD18 pin strapping
499          *             0: DIP0 (Digital Interface Port 0) is used by
500          *                a TMDS transmitter (DVI)
501          *             1: DIP0 (Digital Interface Port 0) is used by
502          *                a TV encoder */
503         if (!(sr12 & 0x20)) {
504             viaDIP0EnableIOPads(pScrn, ioPadState);
505         } else {
506             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
507                         "DIP0 was not set up for "
508                         "TMDS transmitter use.\n");
509         }
510 
511         break;
512     case VIA_KM400:
513     case VIA_K8M800:
514     case VIA_PM800:
515     case VIA_P4M800PRO:
516         /* 3C5.13[3] - DVP0D8 pin strapping
517          *             0: AGP pins are used for AGP
518          *             1: AGP pins are used by FPDP
519          *                (Flat Panel Display Port)
520          * 3C5.12[6] - DVP0D6 pin strapping
521          *             0: Disable DVP0 (Digital Video Port 0)
522          *             1: Enable DVP0 (Digital Video Port 0)
523          * 3C5.12[5] - DVP0D5 pin strapping
524          *             0: DVP0 is used by a TMDS transmitter (DVI)
525          *             1: DVP0 is used by a TV encoder
526          * 3C5.12[4] - DVP0D4 pin strapping
527          *             0: Dual 12-bit FPDP (Flat Panel Display Port)
528          *             1: 24-bit FPDP (Flat Panel Display Port) */
529         if ((sr12 & 0x40) && (!(sr12 & 0x20))) {
530             viaDVP0EnableIOPads(pScrn, ioPadState);
531         } else if ((sr13 & 0x08) && (!(sr12 & 0x10))) {
532             viaDFPLowEnableIOPads(pScrn, ioPadState);
533         } else {
534             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
535                         "None of the external ports were set up for "
536                         "TMDS transmitter use.\n");
537         }
538 
539         break;
540     case VIA_P4M890:
541     case VIA_K8M890:
542     case VIA_P4M900:
543         /* 3C5.12[6] - FPD6 pin strapping
544          *             0: Disable DVP0 (Digital Video Port 0)
545          *             1: Enable DVP0 (Digital Video Port 0)
546          * 3C5.12[5] - FPD5 pin strapping
547          *             0: DVP0 is used by a TMDS transmitter (DVI)
548          *             1: DVP0 is used by a TV encoder */
549         if ((sr12 & 0x40) && (!(sr12 & 0x20))) {
550             viaDVP0EnableIOPads(pScrn, ioPadState);
551         } else if (!(sr12 & 0x10)) {
552             viaDFPLowEnableIOPads(pScrn, ioPadState);
553         } else {
554             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
555                         "None of the external ports were set up for "
556                         "TMDS transmitter use.\n");
557         }
558 
559         break;
560     case VIA_CX700:
561     case VIA_VX800:
562     case VIA_VX855:
563     case VIA_VX900:
564         /* 3C5.13[6] - DVP1 DVP / capture port selection
565          *             0: DVP1 is used as a DVP (Digital Video Port)
566          *             1: DVP1 is used as a capture port
567          */
568         if (!(sr13 & 0x40)) {
569             viaDVP1EnableIOPads(pScrn, ioPadState);
570         } else {
571             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
572                         "DVP1 is not set up for TMDS "
573                         "transmitter use.\n");
574         }
575 
576         break;
577     default:
578         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
579                     "Unrecognized IGP for "
580                     "TMDS transmitter use.\n");
581         break;
582     }
583 
584     if ((pVia->Chipset == VIA_CX700)
585         || (pVia->Chipset == VIA_VX800)
586         || (pVia->Chipset == VIA_VX855)
587         || (pVia->Chipset == VIA_VX900)) {
588 
589         hwp->writeSeq(hwp, 0x5A, sr5a);
590         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
591                             "Restoring 3C5.5A[0].\n"));
592     }
593 
594     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
595                         "Exiting viaExtTMDSEnableIOPads.\n"));
596 }
597 
598 void
viaExtTMDSSetClockDriveStrength(ScrnInfoPtr pScrn,CARD8 clockDriveStrength)599 viaExtTMDSSetClockDriveStrength(ScrnInfoPtr pScrn, CARD8 clockDriveStrength)
600 {
601     vgaHWPtr hwp = VGAHWPTR(pScrn);
602     VIAPtr pVia = VIAPTR(pScrn);
603     CARD8 sr12, sr13, sr5a;
604 
605     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
606                         "Entered viaExtTMDSSetClockDriveStrength.\n"));
607 
608     if ((pVia->Chipset == VIA_CX700)
609         || (pVia->Chipset == VIA_VX800)
610         || (pVia->Chipset == VIA_VX855)
611         || (pVia->Chipset == VIA_VX900)) {
612 
613         sr5a = hwp->readSeq(hwp, 0x5A);
614         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
615                             "SR5A: 0x%02X\n", sr5a));
616         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
617                             "Setting 3C5.5A[0] to 0.\n"));
618         ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
619     }
620 
621     sr12 = hwp->readSeq(hwp, 0x12);
622     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
623                         "SR12: 0x%02X\n", sr12));
624     sr13 = hwp->readSeq(hwp, 0x13);
625     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
626                         "SR13: 0x%02X\n", sr13));
627     switch (pVia->Chipset) {
628     case VIA_CLE266:
629         /* 3C5.12[5] - FPD18 pin strapping
630          *             0: DIP0 (Digital Interface Port 0) is used by
631          *                a TMDS transmitter (DVI)
632          *             1: DIP0 (Digital Interface Port 0) is used by
633          *                a TV encoder */
634         if (!(sr12 & 0x20)) {
635             viaDIP0SetClockDriveStrength(pScrn, clockDriveStrength);
636         }
637 
638         break;
639     case VIA_KM400:
640     case VIA_K8M800:
641     case VIA_PM800:
642     case VIA_P4M800PRO:
643         /* 3C5.12[6] - DVP0D6 pin strapping
644          *             0: Disable DVP0 (Digital Video Port 0)
645          *             1: Enable DVP0 (Digital Video Port 0)
646          * 3C5.12[5] - DVP0D5 pin strapping
647          *             0: DVP0 is used by a TMDS transmitter (DVI)
648          *             1: DVP0 is used by a TV encoder */
649         if ((sr12 & 0x40) && (!(sr12 & 0x20))) {
650             viaDVP0SetClockDriveStrength(pScrn, clockDriveStrength);
651         }
652 
653         break;
654     case VIA_P4M890:
655     case VIA_K8M890:
656     case VIA_P4M900:
657         /* 3C5.12[6] - FPD6 pin strapping
658          *             0: Disable DVP0 (Digital Video Port 0)
659          *             1: Enable DVP0 (Digital Video Port 0)
660          * 3C5.12[5] - FPD5 pin strapping
661          *             0: DVP0 is used by a TMDS transmitter (DVI)
662          *             1: DVP0 is used by a TV encoder */
663         if ((sr12 & 0x40) && (!(sr12 & 0x20))) {
664             viaDVP0SetClockDriveStrength(pScrn, clockDriveStrength);
665         }
666 
667         break;
668     case VIA_CX700:
669     case VIA_VX800:
670     case VIA_VX855:
671     case VIA_VX900:
672         /* 3C5.13[6] - DVP1 DVP / capture port selection
673          *             0: DVP1 is used as a DVP (Digital Video Port)
674          *             1: DVP1 is used as a capture port */
675         if (!(sr13 & 0x40)) {
676             viaDVP1SetClockDriveStrength(pScrn, clockDriveStrength);
677         }
678 
679         break;
680     default:
681         break;
682     }
683 
684     if ((pVia->Chipset == VIA_CX700)
685         || (pVia->Chipset == VIA_VX800)
686         || (pVia->Chipset == VIA_VX855)
687         || (pVia->Chipset == VIA_VX900)) {
688 
689         hwp->writeSeq(hwp, 0x5A, sr5a);
690         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
691                             "Restoring 3C5.5A[0].\n"));
692     }
693 
694     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
695                         "Exiting viaExtTMDSSetClockDriveStrength.\n"));
696 }
697 
698 void
viaExtTMDSSetDataDriveStrength(ScrnInfoPtr pScrn,CARD8 dataDriveStrength)699 viaExtTMDSSetDataDriveStrength(ScrnInfoPtr pScrn, CARD8 dataDriveStrength)
700 {
701     vgaHWPtr hwp = VGAHWPTR(pScrn);
702     VIAPtr pVia = VIAPTR(pScrn);
703     CARD8 sr12, sr13, sr5a;
704 
705     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
706                         "Entered viaExtTMDSSetDataDriveStrength.\n"));
707 
708     if ((pVia->Chipset == VIA_CX700)
709         || (pVia->Chipset == VIA_VX800)
710         || (pVia->Chipset == VIA_VX855)
711         || (pVia->Chipset == VIA_VX900)) {
712 
713         sr5a = hwp->readSeq(hwp, 0x5A);
714         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
715                             "SR5A: 0x%02X\n", sr5a));
716         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
717                             "Setting 3C5.5A[0] to 0.\n"));
718         ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
719     }
720 
721     sr12 = hwp->readSeq(hwp, 0x12);
722     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
723                         "SR12: 0x%02X\n", sr12));
724     sr13 = hwp->readSeq(hwp, 0x13);
725     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
726                         "SR13: 0x%02X\n", sr13));
727     switch (pVia->Chipset) {
728     case VIA_CLE266:
729         /* 3C5.12[5] - FPD18 pin strapping
730          *             0: DIP0 (Digital Interface Port 0) is used by
731          *                a TMDS transmitter (DVI)
732          *             1: DIP0 (Digital Interface Port 0) is used by
733          *                a TV encoder */
734         if (!(sr12 & 0x20)) {
735             viaDIP0SetDataDriveStrength(pScrn, dataDriveStrength);
736         }
737 
738         break;
739     case VIA_KM400:
740     case VIA_K8M800:
741     case VIA_PM800:
742     case VIA_P4M800PRO:
743         /* 3C5.12[6] - DVP0D6 pin strapping
744          *             0: Disable DVP0 (Digital Video Port 0)
745          *             1: Enable DVP0 (Digital Video Port 0)
746          * 3C5.12[5] - DVP0D5 pin strapping
747          *             0: DVP0 is used by a TMDS transmitter (DVI)
748          *             1: DVP0 is used by a TV encoder */
749         if ((sr12 & 0x40) && (!(sr12 & 0x20))) {
750             viaDVP0SetDataDriveStrength(pScrn, dataDriveStrength);
751         }
752 
753         break;
754     case VIA_P4M890:
755     case VIA_K8M890:
756     case VIA_P4M900:
757         /* 3C5.12[6] - FPD6 pin strapping
758          *             0: Disable DVP0 (Digital Video Port 0)
759          *             1: Enable DVP0 (Digital Video Port 0)
760          * 3C5.12[5] - FPD5 pin strapping
761          *             0: DVP0 is used by a TMDS transmitter (DVI)
762          *             1: DVP0 is used by a TV encoder */
763         if ((sr12 & 0x40) && (!(sr12 & 0x20))) {
764             viaDVP0SetDataDriveStrength(pScrn, dataDriveStrength);
765         }
766 
767         break;
768     case VIA_CX700:
769     case VIA_VX800:
770     case VIA_VX855:
771     case VIA_VX900:
772         /* 3C5.13[6] - DVP1 DVP / capture port selection
773          *             0: DVP1 is used as a DVP (Digital Video Port)
774          *             1: DVP1 is used as a capture port */
775         if (!(sr13 & 0x40)) {
776             viaDVP1SetDataDriveStrength(pScrn, dataDriveStrength);
777         }
778 
779         break;
780     default:
781         break;
782     }
783 
784     if ((pVia->Chipset == VIA_CX700)
785         || (pVia->Chipset == VIA_VX800)
786         || (pVia->Chipset == VIA_VX855)
787         || (pVia->Chipset == VIA_VX900)) {
788 
789         hwp->writeSeq(hwp, 0x5A, sr5a);
790         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
791                             "Restoring 3C5.5A[0].\n"));
792     }
793 
794     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
795                         "Exiting viaExtTMDSSetDataDriveStrength.\n"));
796 }
797 
798 static void
via_tmds_create_resources(xf86OutputPtr output)799 via_tmds_create_resources(xf86OutputPtr output)
800 {
801     ScrnInfoPtr pScrn = output->scrn;
802 
803     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
804                         "Entered via_tmds_create_resources.\n"));
805 
806     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
807                         "Exiting via_tmds_create_resources.\n"));
808 }
809 
810 static void
via_tmds_dpms(xf86OutputPtr output,int mode)811 via_tmds_dpms(xf86OutputPtr output, int mode)
812 {
813     ScrnInfoPtr pScrn = output->scrn;
814 
815     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
816                         "Entered via_tmds_dpms.\n"));
817 
818     switch (mode) {
819     case DPMSModeOn:
820         viaTMDSPower(pScrn, TRUE);
821         viaTMDSIOPadSetting(pScrn, TRUE);
822         break;
823     case DPMSModeStandby:
824     case DPMSModeSuspend:
825     case DPMSModeOff:
826         viaTMDSPower(pScrn, FALSE);
827         viaTMDSIOPadSetting(pScrn, FALSE);
828         break;
829     default:
830         break;
831     }
832 
833     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
834                         "Exiting via_tmds_dpms.\n"));
835 }
836 
837 static void
via_tmds_save(xf86OutputPtr output)838 via_tmds_save(xf86OutputPtr output)
839 {
840     ScrnInfoPtr pScrn = output->scrn;
841 
842     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
843                         "Entered via_tmds_save.\n"));
844 
845     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
846                         "Exiting via_tmds_save.\n"));
847 }
848 
849 static void
via_tmds_restore(xf86OutputPtr output)850 via_tmds_restore(xf86OutputPtr output)
851 {
852     ScrnInfoPtr pScrn = output->scrn;
853 
854     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
855                         "Entered via_tmds_restore.\n"));
856 
857     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
858                         "Exiting via_tmds_restore.\n"));
859 }
860 
861 static int
via_tmds_mode_valid(xf86OutputPtr output,DisplayModePtr pMode)862 via_tmds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
863 {
864     ScrnInfoPtr pScrn = output->scrn;
865     int status;
866 
867     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
868                         "Entered via_tmds_mode_valid.\n"));
869 
870     if (!ViaModeDotClockTranslate(pScrn, pMode)) {
871         status = MODE_NOCLOCK;
872     } else {
873         status = MODE_OK;
874     }
875 
876     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
877                         "Exiting via_tmds_mode_valid.\n"));
878     return status;
879 }
880 
881 static Bool
via_tmds_mode_fixup(xf86OutputPtr output,DisplayModePtr mode,DisplayModePtr adjusted_mode)882 via_tmds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
883                       DisplayModePtr adjusted_mode)
884 {
885     ScrnInfoPtr pScrn = output->scrn;
886 
887     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
888                         "Entered via_tmds_mode_fixup.\n"));
889 
890     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
891                         "Exiting via_tmds_mode_fixup.\n"));
892     return TRUE;
893 }
894 
895 static void
via_tmds_prepare(xf86OutputPtr output)896 via_tmds_prepare(xf86OutputPtr output)
897 {
898     ScrnInfoPtr pScrn = output->scrn;
899 
900     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
901                         "Entered via_tmds_prepare.\n"));
902 
903     viaTMDSPower(pScrn, FALSE);
904     viaTMDSIOPadSetting(pScrn, FALSE);
905 
906     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
907                         "Exiting via_tmds_prepare.\n"));
908 }
909 
910 static void
via_tmds_commit(xf86OutputPtr output)911 via_tmds_commit(xf86OutputPtr output)
912 {
913     ScrnInfoPtr pScrn = output->scrn;
914 
915     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
916                         "Entered via_tmds_commit.\n"));
917 
918     viaTMDSPower(pScrn, TRUE);
919     viaTMDSIOPadSetting(pScrn, TRUE);
920 
921     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
922                         "Exiting via_tmds_commit.\n"));
923 }
924 
925 static void
via_tmds_mode_set(xf86OutputPtr output,DisplayModePtr mode,DisplayModePtr adjusted_mode)926 via_tmds_mode_set(xf86OutputPtr output, DisplayModePtr mode,
927                     DisplayModePtr adjusted_mode)
928 {
929     ScrnInfoPtr pScrn = output->scrn;
930     drmmode_crtc_private_ptr iga = output->crtc->driver_private;
931 
932     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
933                         "Entered via_tmds_mode_set.\n"));
934 
935     /* Initialize VIA IGP integrated TMDS transmitter registers. */
936     viaTMDSInitRegisters(pScrn);
937 
938     /* Set integrated TMDS transmitter synchronization polarity for
939      * both horizontal synchronization and vertical synchronization. */
940     viaTMDSSetSyncPolarity(pScrn, adjusted_mode);
941 
942     if (output->crtc) {
943         viaTMDSSetSource(pScrn, iga->index ? 0x01 : 0x00);
944     }
945 
946     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
947                         "Exiting via_tmds_mode_set.\n"));
948 }
949 
950 static xf86OutputStatus
via_tmds_detect(xf86OutputPtr output)951 via_tmds_detect(xf86OutputPtr output)
952 {
953     xf86MonPtr mon;
954     xf86OutputStatus status = XF86OutputStatusDisconnected;
955     ScrnInfoPtr pScrn = output->scrn;
956     VIAPtr pVia = VIAPTR(pScrn);
957 
958     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
959                         "Entered via_tmds_detect.\n"));
960 
961     /* Check for DVI presence by sensing the TMDS receiver connected
962      * to the integrated TMDS transmitter. */
963     if (viaTMDSSense(pScrn)) {
964 
965         if (!pVia->pI2CBus2) {
966             goto exit;
967         }
968 
969         /* Assume that only I2C bus 2 is used for the DVI connected to the
970          * integrated TMDS transmitter. */
971         if (!xf86I2CProbeAddress(pVia->pI2CBus2, 0xA0)) {
972             xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
973                         "I2C device on I2C Bus 2 does not support EDID.\n");
974             goto exit;
975         }
976 
977         xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
978                     "Obtaining EDID for DVI.\n");
979 
980         /* Since DVI presence was established, access the I2C bus,
981          * in order to obtain EDID from the monitor. */
982         mon = xf86OutputGetEDID(output, pVia->pI2CBus2);
983 
984         /* Is the interface type digital? */
985         if (mon && DIGITAL(mon->features.input_type)) {
986             status = XF86OutputStatusConnected;
987             xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
988                         "Detected a monitor connected to DVI.\n");
989             xf86OutputSetEDID(output, mon);
990         } else {
991             xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
992                         "Could not obtain EDID from a monitor "
993                         "connected to DVI.\n");
994         }
995     }
996 
997 exit:
998     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
999                         "Exiting via_tmds_detect.\n"));
1000     return status;
1001 }
1002 
1003 #ifdef RANDR_12_INTERFACE
1004 static Bool
via_tmds_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)1005 via_tmds_set_property(xf86OutputPtr output, Atom property,
1006                      RRPropertyValuePtr value)
1007 {
1008     ScrnInfoPtr pScrn = output->scrn;
1009 
1010     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1011                         "Entered via_tmds_set_property.\n"));
1012 
1013     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1014                         "Exiting via_tmds_set_property.\n"));
1015     return TRUE;
1016 }
1017 #endif
1018 
1019 #ifdef RANDR_13_INTERFACE
1020 static Bool
via_tmds_get_property(xf86OutputPtr output,Atom property)1021 via_tmds_get_property(xf86OutputPtr output, Atom property)
1022 {
1023     ScrnInfoPtr pScrn = output->scrn;
1024 
1025     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1026                         "Entered via_tmds_get_property.\n"));
1027 
1028     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1029                         "Exiting via_tmds_get_property.\n"));
1030     return FALSE;
1031 }
1032 #endif
1033 
1034 static void
via_tmds_destroy(xf86OutputPtr output)1035 via_tmds_destroy(xf86OutputPtr output)
1036 {
1037     ScrnInfoPtr pScrn = output->scrn;
1038 
1039     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1040                         "Entered via_tmds_destroy.\n"));
1041 
1042     if (output->driver_private) {
1043         free(output->driver_private);
1044     }
1045 
1046     output->driver_private = NULL;
1047 
1048     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1049                         "Exiting via_tmds_destroy.\n"));
1050 }
1051 
1052 
1053 
1054 
1055 static const xf86OutputFuncsRec via_tmds_funcs = {
1056     .create_resources   = via_tmds_create_resources,
1057     .dpms               = via_tmds_dpms,
1058     .save               = via_tmds_save,
1059     .restore            = via_tmds_restore,
1060     .mode_valid         = via_tmds_mode_valid,
1061     .mode_fixup         = via_tmds_mode_fixup,
1062     .prepare            = via_tmds_prepare,
1063     .commit             = via_tmds_commit,
1064     .mode_set           = via_tmds_mode_set,
1065     .detect             = via_tmds_detect,
1066     .get_modes          = xf86OutputGetEDIDModes,
1067 #ifdef RANDR_12_INTERFACE
1068     .set_property       = via_tmds_set_property,
1069 #endif
1070 #ifdef RANDR_13_INTERFACE
1071     .get_property       = via_tmds_get_property,
1072 #endif
1073     .destroy            = via_tmds_destroy,
1074 };
1075 
1076 
1077 Bool
viaTMDSInit(ScrnInfoPtr pScrn)1078 viaTMDSInit(ScrnInfoPtr pScrn)
1079 {
1080     xf86OutputPtr output;
1081     vgaHWPtr hwp = VGAHWPTR(pScrn);
1082     VIAPtr pVia = VIAPTR(pScrn);
1083     VIATMDSRecPtr pVIATMDSRec = NULL;
1084     CARD8 sr13, sr5a;
1085     Bool status = FALSE;
1086     char outputNameBuffer[32];
1087 
1088     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1089                         "Entered viaTMDSInit.\n"));
1090 
1091     sr5a = hwp->readSeq(hwp, 0x5A);
1092     ViaSeqMask(hwp, 0x5A, sr5a | 0x01, 0x01);
1093     sr13 = hwp->readSeq(hwp, 0x13);
1094     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1095                         "SR13: 0x%02X\n", sr13));
1096     hwp->writeSeq(hwp, 0x5A, sr5a);
1097 
1098     /* 3C5.13[7:6] - Integrated LVDS / DVI Mode Select
1099      *               (DVP1D15-14 pin strapping)
1100      *               00: LVDS1 + LVDS2
1101      *               01: DVI + LVDS2
1102      *               10: Dual LVDS Channel (High Resolution Panel)
1103      *               11: One DVI only (decrease the clock jitter) */
1104     /* Check for DVI presence using pin strappings.
1105      * VIA Technologies NanoBook reference design based products
1106      * have their pin strappings set to a wrong setting to communicate
1107      * the presence of DVI, so it requires special handling here. */
1108     if ((((~(sr13 & 0x80)) && (sr13 & 0x40))
1109          || ((sr13 & 0x80) && (sr13 & 0x40)))
1110        || (pVia->isVIANanoBook)) {
1111 
1112         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1113                     "Integrated TMDS transmitter found via pin strapping.\n");
1114     } else {
1115         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1116                     "Integrated TMDS transmitter not found.\n");
1117         goto exit;
1118     }
1119 
1120     pVIATMDSRec = xnfcalloc(1, sizeof(VIATMDSRec));
1121     if (!pVIATMDSRec) {
1122         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1123                     "Failed to allocate working storage for integrated "
1124                     "TMDS transmitter.\n");
1125         goto exit;
1126     }
1127 
1128     /* The code to dynamically designate the particular DVI (i.e., DVI-1,
1129      * DVI-2, etc.) for xrandr was borrowed from xf86-video-r128 DDX. */
1130     sprintf(outputNameBuffer, "DVI-%d", (pVia->numberDVI + 1));
1131     output = xf86OutputCreate(pScrn, &via_tmds_funcs, outputNameBuffer);
1132     if (!output) {
1133         free(pVIATMDSRec);
1134         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1135                     "Failed to allocate X Server display output record for "
1136                     "integrated TMDS transmitter.\n");
1137         goto exit;
1138     }
1139 
1140     output->driver_private = pVIATMDSRec;
1141 
1142     /* Since there are two (2) display controllers registered with the
1143      * X.Org Server and both IGA1 and IGA2 can handle DVI without any
1144      * limitations, possible_crtcs should be set to 0x3 (0b11) so that
1145      * either display controller can get assigned to handle DVI. */
1146     output->possible_crtcs = (1 << 1) | (1 << 0);
1147 
1148     output->possible_clones = 0;
1149     output->interlaceAllowed = FALSE;
1150     output->doubleScanAllowed = FALSE;
1151 
1152     pVia->numberDVI++;
1153     status = TRUE;
1154 exit:
1155     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1156                         "Exiting viaTMDSInit.\n"));
1157     return status;
1158 }
1159 
1160 void
via_dvi_init(ScrnInfoPtr pScrn)1161 via_dvi_init(ScrnInfoPtr pScrn)
1162 {
1163     VIAPtr pVia = VIAPTR(pScrn);
1164 
1165     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1166                         "Entered via_dvi_init.\n"));
1167 
1168     if (!pVia->pI2CBus2 || !pVia->pI2CBus3) {
1169         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1170                     "I2C Bus 2 or I2C Bus 3 does not exist.\n");
1171         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1172                     "Exiting via_dvi_init.\n"));
1173         return;
1174     }
1175 
1176     /* Check to see if we are dealing with the latest VIA chipsets. */
1177     if ((pVia->Chipset == VIA_CX700)
1178         || (pVia->Chipset == VIA_VX800)
1179         || (pVia->Chipset == VIA_VX855)
1180         || (pVia->Chipset == VIA_VX900)) {
1181 
1182         if (!viaTMDSInit(pScrn)) {
1183             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1184                         "Integrated TMDS transmitter for DVI not found.\n");
1185         } else {
1186             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1187                         "Integrated TMDS transmitter for DVI was "
1188                         "initialized successfully.\n");
1189         }
1190     }
1191 
1192     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1193                 "Probing I2C Bus 2 for VT1632.\n");
1194     if (!viaVT1632Init(pScrn, pVia->pI2CBus2)) {
1195         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1196                     "I2C Bus 2 was not initialized for DVI use.\n");
1197     } else {
1198         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1199                     "VT1632 attached to I2C Bus 2 was initialized "
1200                     "successfully for DVI use.\n");
1201     }
1202 
1203     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1204                 "Probing I2C Bus 3 for VT1632.\n");
1205     if (!viaVT1632Init(pScrn, pVia->pI2CBus3)) {
1206         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1207                     "I2C Bus 3 was not initialized for DVI use.\n");
1208     } else {
1209         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1210                     "VT1632 attached to I2C Bus 3 was initialized "
1211                     "successfully for DVI use.\n");
1212     }
1213 
1214     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1215                 "Probing I2C Bus 2 for SiI 164.\n");
1216     if (!viaSiI164Init(pScrn, pVia->pI2CBus2)) {
1217         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1218                     "I2C Bus 2 was not initialized for DVI use.\n");
1219     } else {
1220         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1221                     "SiI 164 attached to I2C Bus 2 was initialized "
1222                     "successfully for DVI use.\n");
1223     }
1224 
1225     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1226                 "Probing I2C Bus 3 for SiI 164.\n");
1227     if (!viaSiI164Init(pScrn, pVia->pI2CBus3)) {
1228         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1229                     "I2C Bus 3 was not initialized for DVI use.\n");
1230     } else {
1231         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1232                     "SiI 164 attached to I2C Bus 3 was initialized "
1233                     "successfully for DVI use.\n");
1234     }
1235 
1236     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1237                         "Exiting via_dvi_init.\n"));
1238 }
1239