via_tv.c revision 983b4bf2
1983b4bf2Smrg/*
2983b4bf2Smrg * Copyright 2005-2016 The OpenChrome Project
3983b4bf2Smrg *                     [https://www.freedesktop.org/wiki/Openchrome]
4983b4bf2Smrg * Copyright 2004-2005 The Unichrome Project  [unichrome.sf.net]
5983b4bf2Smrg * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
6983b4bf2Smrg * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
7983b4bf2Smrg *
8983b4bf2Smrg * Permission is hereby granted, free of charge, to any person obtaining a
9983b4bf2Smrg * copy of this software and associated documentation files (the "Software"),
10983b4bf2Smrg * to deal in the Software without restriction, including without limitation
11983b4bf2Smrg * the rights to use, copy, modify, merge, publish, distribute, sub license,
12983b4bf2Smrg * and/or sell copies of the Software, and to permit persons to whom the
13983b4bf2Smrg * Software is furnished to do so, subject to the following conditions:
14983b4bf2Smrg *
15983b4bf2Smrg * The above copyright notice and this permission notice (including the
16983b4bf2Smrg * next paragraph) shall be included in all copies or substantial portions
17983b4bf2Smrg * of the Software.
18983b4bf2Smrg *
19983b4bf2Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20983b4bf2Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21983b4bf2Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22983b4bf2Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23983b4bf2Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24983b4bf2Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25983b4bf2Smrg * DEALINGS IN THE SOFTWARE.
26983b4bf2Smrg */
27983b4bf2Smrg
28983b4bf2Smrg/*
29983b4bf2Smrg * via_tv.c
30983b4bf2Smrg *
31983b4bf2Smrg * Handles the initialization and management of TV output related
32983b4bf2Smrg * resources.
33983b4bf2Smrg *
34983b4bf2Smrg */
35983b4bf2Smrg
36983b4bf2Smrg#ifdef HAVE_CONFIG_H
37983b4bf2Smrg#include "config.h"
38983b4bf2Smrg#endif
39983b4bf2Smrg
40983b4bf2Smrg#include "via_driver.h"
41983b4bf2Smrg#include <unistd.h>
42983b4bf2Smrg
43983b4bf2Smrgstatic void
44983b4bf2SmrgviaTVSetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
45983b4bf2Smrg{
46983b4bf2Smrg
47983b4bf2Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
48983b4bf2Smrg    VIAPtr pVia = VIAPTR(pScrn);
49983b4bf2Smrg    CARD8 sr12, sr13, sr5a;
50983b4bf2Smrg
51983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
52983b4bf2Smrg                        "Entered viaTVSetDisplaySource.\n"));
53983b4bf2Smrg
54983b4bf2Smrg    if ((pVia->Chipset == VIA_CX700)
55983b4bf2Smrg        || (pVia->Chipset == VIA_VX800)
56983b4bf2Smrg        || (pVia->Chipset == VIA_VX855)
57983b4bf2Smrg        || (pVia->Chipset == VIA_VX900)) {
58983b4bf2Smrg
59983b4bf2Smrg        sr5a = hwp->readSeq(hwp, 0x5A);
60983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
61983b4bf2Smrg                            "SR5A: 0x%02X\n", sr5a));
62983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
63983b4bf2Smrg                            "Setting 3C5.5A[0] to 0.\n"));
64983b4bf2Smrg        ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
65983b4bf2Smrg    }
66983b4bf2Smrg
67983b4bf2Smrg    sr12 = hwp->readSeq(hwp, 0x12);
68983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
69983b4bf2Smrg                        "SR12: 0x%02X\n", sr12));
70983b4bf2Smrg    sr13 = hwp->readSeq(hwp, 0x13);
71983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
72983b4bf2Smrg                        "SR13: 0x%02X\n", sr13));
73983b4bf2Smrg    switch (pVia->Chipset) {
74983b4bf2Smrg    case VIA_CLE266:
75983b4bf2Smrg        /* 3C5.12[5] - FPD18 pin strapping
76983b4bf2Smrg         *             0: DIP0 (Digital Interface Port 0) is used by
77983b4bf2Smrg         *                a TMDS transmitter (DVI)
78983b4bf2Smrg         *             1: DIP0 (Digital Interface Port 0) is used by
79983b4bf2Smrg         *                a TV encoder */
80983b4bf2Smrg        if (sr12 & 0x20) {
81983b4bf2Smrg            viaDIP0SetDisplaySource(pScrn, displaySource);
82983b4bf2Smrg        } else {
83983b4bf2Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
84983b4bf2Smrg                        "DIP0 was not set up for "
85983b4bf2Smrg                        "an external TV encoder use.\n");
86983b4bf2Smrg        }
87983b4bf2Smrg
88983b4bf2Smrg        break;
89983b4bf2Smrg    case VIA_KM400:
90983b4bf2Smrg    case VIA_K8M800:
91983b4bf2Smrg    case VIA_PM800:
92983b4bf2Smrg    case VIA_P4M800PRO:
93983b4bf2Smrg        /* 3C5.13[3] - DVP0D8 pin strapping
94983b4bf2Smrg         *             0: AGP pins are used for AGP
95983b4bf2Smrg         *             1: AGP pins are used by FPDP
96983b4bf2Smrg         *                (Flat Panel Display Port)
97983b4bf2Smrg         * 3C5.12[6] - DVP0D6 pin strapping
98983b4bf2Smrg         *             0: Disable DVP0 (Digital Video Port 0)
99983b4bf2Smrg         *             1: Enable DVP0 (Digital Video Port 0)
100983b4bf2Smrg         * 3C5.12[5] - DVP0D5 pin strapping
101983b4bf2Smrg         *             0: DVP0 is used by a TMDS transmitter (DVI)
102983b4bf2Smrg         *             1: DVP0 is used by a TV encoder
103983b4bf2Smrg         * 3C5.12[4] - DVP0D4 pin strapping
104983b4bf2Smrg         *             0: Dual 12-bit FPDP (Flat Panel Display Port)
105983b4bf2Smrg         *             1: 24-bit FPDP (Flat Panel Display Port) */
106983b4bf2Smrg        if ((sr12 & 0x40) && (sr12 & 0x20)) {
107983b4bf2Smrg            viaDVP0SetDisplaySource(pScrn, displaySource);
108983b4bf2Smrg        } else if ((sr13 & 0x08) && (!(sr12 & 0x10))) {
109983b4bf2Smrg            viaDFPLowSetDisplaySource(pScrn, displaySource);
110983b4bf2Smrg        } else if (sr13 & 0x08) {
111983b4bf2Smrg            viaDVP1SetDisplaySource(pScrn, displaySource);
112983b4bf2Smrg        } else {
113983b4bf2Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
114983b4bf2Smrg                        "None of the external ports were set up for "
115983b4bf2Smrg                        "external TV encoder use.\n");
116983b4bf2Smrg        }
117983b4bf2Smrg
118983b4bf2Smrg        break;
119983b4bf2Smrg    case VIA_P4M890:
120983b4bf2Smrg    case VIA_K8M890:
121983b4bf2Smrg    case VIA_P4M900:
122983b4bf2Smrg        /* 3C5.12[6] - FPD6 pin strapping
123983b4bf2Smrg         *             0: Disable DVP0 (Digital Video Port 0)
124983b4bf2Smrg         *             1: Enable DVP0 (Digital Video Port 0)
125983b4bf2Smrg         * 3C5.12[5] - FPD5 pin strapping
126983b4bf2Smrg         *             0: DVP0 is used by a TMDS transmitter (DVI)
127983b4bf2Smrg         *             1: DVP0 is used by a TV encoder
128983b4bf2Smrg         * 3C5.12[4] - FPD4 pin strapping
129983b4bf2Smrg         *             0: Dual 12-bit FPDP (Flat Panel Display Port)
130983b4bf2Smrg         *             1: 24-bit FPDP (Flat Panel Display Port) */
131983b4bf2Smrg        if ((sr12 & 0x40) && (sr12 & 0x20) && (!(sr12 & 0x10))) {
132983b4bf2Smrg            viaDVP0SetDisplaySource(pScrn, displaySource);
133983b4bf2Smrg        } else {
134983b4bf2Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
135983b4bf2Smrg                        "Unrecognized external TV encoder use.\n"
136983b4bf2Smrg                        "Contact the developer for assistance.\n");
137983b4bf2Smrg        }
138983b4bf2Smrg
139983b4bf2Smrg        break;
140983b4bf2Smrg    case VIA_CX700:
141983b4bf2Smrg    case VIA_VX800:
142983b4bf2Smrg    case VIA_VX855:
143983b4bf2Smrg    case VIA_VX900:
144983b4bf2Smrg        /* 3C5.13[6] - DVP1 DVP / capture port selection
145983b4bf2Smrg         *             0: DVP1 is used as a DVP (Digital Video Port)
146983b4bf2Smrg         *             1: DVP1 is used as a capture port
147983b4bf2Smrg         */
148983b4bf2Smrg        if (!(sr13 & 0x40)) {
149983b4bf2Smrg            viaDVP1SetDisplaySource(pScrn, displaySource);
150983b4bf2Smrg        } else {
151983b4bf2Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
152983b4bf2Smrg                        "DVP1 is not set up for external TV "
153983b4bf2Smrg                        "encoder use.\n");
154983b4bf2Smrg        }
155983b4bf2Smrg
156983b4bf2Smrg        break;
157983b4bf2Smrg    default:
158983b4bf2Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
159983b4bf2Smrg                    "Unrecognized IGP for "
160983b4bf2Smrg                    "an external TV encoder use.\n");
161983b4bf2Smrg        break;
162983b4bf2Smrg    }
163983b4bf2Smrg
164983b4bf2Smrg    if ((pVia->Chipset == VIA_CX700)
165983b4bf2Smrg        || (pVia->Chipset == VIA_VX800)
166983b4bf2Smrg        || (pVia->Chipset == VIA_VX855)
167983b4bf2Smrg        || (pVia->Chipset == VIA_VX900)) {
168983b4bf2Smrg
169983b4bf2Smrg        hwp->writeSeq(hwp, 0x5A, sr5a);
170983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
171983b4bf2Smrg                            "Restoring 3C5.5A[0].\n"));
172983b4bf2Smrg    }
173983b4bf2Smrg
174983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
175983b4bf2Smrg                        "Exiting viaTVSetDisplaySource.\n"));
176983b4bf2Smrg}
177983b4bf2Smrg
178983b4bf2Smrgstatic void
179983b4bf2SmrgviaTVEnableIOPads(ScrnInfoPtr pScrn, CARD8 ioPadState)
180983b4bf2Smrg{
181983b4bf2Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
182983b4bf2Smrg    VIAPtr pVia = VIAPTR(pScrn);
183983b4bf2Smrg    CARD8 sr12, sr13, sr5a;
184983b4bf2Smrg
185983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
186983b4bf2Smrg                        "Entered viaTVEnableIOPads.\n"));
187983b4bf2Smrg
188983b4bf2Smrg    if ((pVia->Chipset == VIA_CX700)
189983b4bf2Smrg        || (pVia->Chipset == VIA_VX800)
190983b4bf2Smrg        || (pVia->Chipset == VIA_VX855)
191983b4bf2Smrg        || (pVia->Chipset == VIA_VX900)) {
192983b4bf2Smrg
193983b4bf2Smrg        sr5a = hwp->readSeq(hwp, 0x5A);
194983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
195983b4bf2Smrg                            "SR5A: 0x%02X\n", sr5a));
196983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
197983b4bf2Smrg                            "Setting 3C5.5A[0] to 0.\n"));
198983b4bf2Smrg        ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
199983b4bf2Smrg    }
200983b4bf2Smrg
201983b4bf2Smrg    sr12 = hwp->readSeq(hwp, 0x12);
202983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
203983b4bf2Smrg                        "SR12: 0x%02X\n", sr12));
204983b4bf2Smrg    sr13 = hwp->readSeq(hwp, 0x13);
205983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
206983b4bf2Smrg                        "SR13: 0x%02X\n", sr13));
207983b4bf2Smrg    switch (pVia->Chipset) {
208983b4bf2Smrg    case VIA_CLE266:
209983b4bf2Smrg        /* 3C5.12[5] - FPD18 pin strapping
210983b4bf2Smrg         *             0: DIP0 (Digital Interface Port 0) is used by
211983b4bf2Smrg         *                a TMDS transmitter (DVI)
212983b4bf2Smrg         *             1: DIP0 (Digital Interface Port 0) is used by
213983b4bf2Smrg         *                a TV encoder */
214983b4bf2Smrg        if (sr12 & 0x20) {
215983b4bf2Smrg            viaDIP0EnableIOPads(pScrn, ioPadState);
216983b4bf2Smrg        } else {
217983b4bf2Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
218983b4bf2Smrg                        "DIP0 is not set up for "
219983b4bf2Smrg                        "an external TV encoder use.\n");
220983b4bf2Smrg        }
221983b4bf2Smrg
222983b4bf2Smrg        break;
223983b4bf2Smrg    case VIA_KM400:
224983b4bf2Smrg    case VIA_K8M800:
225983b4bf2Smrg    case VIA_PM800:
226983b4bf2Smrg    case VIA_P4M800PRO:
227983b4bf2Smrg        /* 3C5.13[3] - DVP0D8 pin strapping
228983b4bf2Smrg         *             0: AGP pins are used for AGP
229983b4bf2Smrg         *             1: AGP pins are used by FPDP
230983b4bf2Smrg         *                (Flat Panel Display Port)
231983b4bf2Smrg         * 3C5.12[6] - DVP0D6 pin strapping
232983b4bf2Smrg         *             0: Disable DVP0 (Digital Video Port 0)
233983b4bf2Smrg         *             1: Enable DVP0 (Digital Video Port 0)
234983b4bf2Smrg         * 3C5.12[5] - DVP0D5 pin strapping
235983b4bf2Smrg         *             0: DVP0 is used by a TMDS transmitter (DVI)
236983b4bf2Smrg         *             1: DVP0 is used by a TV encoder
237983b4bf2Smrg         * 3C5.12[4] - DVP0D4 pin strapping
238983b4bf2Smrg         *             0: Dual 12-bit FPDP (Flat Panel Display Port)
239983b4bf2Smrg         *             1: 24-bit FPDP (Flat Panel Display Port) */
240983b4bf2Smrg        if ((sr12 & 0x40) && (sr12 & 0x20)) {
241983b4bf2Smrg            viaDVP0EnableIOPads(pScrn, ioPadState);
242983b4bf2Smrg        } else if ((sr13 & 0x08) && (!(sr12 & 0x10))) {
243983b4bf2Smrg            viaDFPLowEnableIOPads(pScrn, ioPadState);
244983b4bf2Smrg        } else if (sr13 & 0x08) {
245983b4bf2Smrg            viaDVP1EnableIOPads(pScrn, ioPadState);
246983b4bf2Smrg        } else {
247983b4bf2Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
248983b4bf2Smrg                        "None of the external ports were set up for "
249983b4bf2Smrg                        "external TV encoder use.\n");
250983b4bf2Smrg        }
251983b4bf2Smrg
252983b4bf2Smrg        break;
253983b4bf2Smrg    case VIA_P4M890:
254983b4bf2Smrg    case VIA_K8M890:
255983b4bf2Smrg    case VIA_P4M900:
256983b4bf2Smrg        /* 3C5.12[6] - FPD6 pin strapping
257983b4bf2Smrg         *             0: Disable DVP0 (Digital Video Port 0)
258983b4bf2Smrg         *             1: Enable DVP0 (Digital Video Port 0)
259983b4bf2Smrg         * 3C5.12[5] - FPD5 pin strapping
260983b4bf2Smrg         *             0: DVP0 is used by a TMDS transmitter (DVI)
261983b4bf2Smrg         *             1: DVP0 is used by a TV encoder
262983b4bf2Smrg         * 3C5.12[4] - FPD4 pin strapping
263983b4bf2Smrg         *             0: Dual 12-bit FPDP (Flat Panel Display Port)
264983b4bf2Smrg         *             1: 24-bit FPDP (Flat Panel Display Port) */
265983b4bf2Smrg        if ((sr12 & 0x40) && (sr12 & 0x20) && (!(sr12 & 0x10))) {
266983b4bf2Smrg            viaDVP0EnableIOPads(pScrn, ioPadState);
267983b4bf2Smrg        } else {
268983b4bf2Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
269983b4bf2Smrg                        "Unrecognized external TV encoder use.\n"
270983b4bf2Smrg                        "Contact the developer for assistance.\n");
271983b4bf2Smrg        }
272983b4bf2Smrg
273983b4bf2Smrg        break;
274983b4bf2Smrg    case VIA_CX700:
275983b4bf2Smrg    case VIA_VX800:
276983b4bf2Smrg    case VIA_VX855:
277983b4bf2Smrg    case VIA_VX900:
278983b4bf2Smrg        /* 3C5.13[6] - DVP1 DVP / capture port selection
279983b4bf2Smrg         *             0: DVP1 is used as a DVP (Digital Video Port)
280983b4bf2Smrg         *             1: DVP1 is used as a capture port
281983b4bf2Smrg         */
282983b4bf2Smrg        if (!(sr13 & 0x40)) {
283983b4bf2Smrg            viaDVP1EnableIOPads(pScrn, ioPadState);
284983b4bf2Smrg        } else {
285983b4bf2Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
286983b4bf2Smrg                        "DVP1 is not set up for external TV "
287983b4bf2Smrg                        "encoder use.\n");
288983b4bf2Smrg        }
289983b4bf2Smrg
290983b4bf2Smrg        break;
291983b4bf2Smrg    default:
292983b4bf2Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
293983b4bf2Smrg                    "Unrecognized IGP for "
294983b4bf2Smrg                    "an external TV encoder use.\n");
295983b4bf2Smrg        break;
296983b4bf2Smrg    }
297983b4bf2Smrg
298983b4bf2Smrg    if ((pVia->Chipset == VIA_CX700)
299983b4bf2Smrg        || (pVia->Chipset == VIA_VX800)
300983b4bf2Smrg        || (pVia->Chipset == VIA_VX855)
301983b4bf2Smrg        || (pVia->Chipset == VIA_VX900)) {
302983b4bf2Smrg
303983b4bf2Smrg        hwp->writeSeq(hwp, 0x5A, sr5a);
304983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
305983b4bf2Smrg                            "Restoring 3C5.5A[0].\n"));
306983b4bf2Smrg    }
307983b4bf2Smrg
308983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
309983b4bf2Smrg                        "Exiting viaTVEnableIOPads.\n"));
310983b4bf2Smrg}
311983b4bf2Smrg
312983b4bf2Smrgstatic void
313983b4bf2SmrgviaTVSetClockDriveStrength(ScrnInfoPtr pScrn, CARD8 clockDriveStrength)
314983b4bf2Smrg{
315983b4bf2Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
316983b4bf2Smrg    VIAPtr pVia = VIAPTR(pScrn);
317983b4bf2Smrg    CARD8 sr12, sr13, sr5a;
318983b4bf2Smrg
319983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
320983b4bf2Smrg                        "Entered viaTVSetClockDriveStrength.\n"));
321983b4bf2Smrg
322983b4bf2Smrg    if ((pVia->Chipset == VIA_CX700)
323983b4bf2Smrg        || (pVia->Chipset == VIA_VX800)
324983b4bf2Smrg        || (pVia->Chipset == VIA_VX855)
325983b4bf2Smrg        || (pVia->Chipset == VIA_VX900)) {
326983b4bf2Smrg
327983b4bf2Smrg        sr5a = hwp->readSeq(hwp, 0x5A);
328983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
329983b4bf2Smrg                            "SR5A: 0x%02X\n", sr5a));
330983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
331983b4bf2Smrg                            "Setting 3C5.5A[0] to 0.\n"));
332983b4bf2Smrg        ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
333983b4bf2Smrg    }
334983b4bf2Smrg
335983b4bf2Smrg    sr12 = hwp->readSeq(hwp, 0x12);
336983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
337983b4bf2Smrg                        "SR12: 0x%02X\n", sr12));
338983b4bf2Smrg    sr13 = hwp->readSeq(hwp, 0x13);
339983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
340983b4bf2Smrg                        "SR13: 0x%02X\n", sr13));
341983b4bf2Smrg    switch (pVia->Chipset) {
342983b4bf2Smrg    case VIA_CLE266:
343983b4bf2Smrg        /* 3C5.12[5] - FPD18 pin strapping
344983b4bf2Smrg         *             0: DIP0 (Digital Interface Port 0) is used by
345983b4bf2Smrg         *                a TMDS transmitter (DVI)
346983b4bf2Smrg         *             1: DIP0 (Digital Interface Port 0) is used by
347983b4bf2Smrg         *                a TV encoder */
348983b4bf2Smrg        if (sr12 & 0x20) {
349983b4bf2Smrg            viaDIP0SetClockDriveStrength(pScrn, clockDriveStrength);
350983b4bf2Smrg        }
351983b4bf2Smrg
352983b4bf2Smrg        break;
353983b4bf2Smrg    case VIA_KM400:
354983b4bf2Smrg    case VIA_K8M800:
355983b4bf2Smrg    case VIA_PM800:
356983b4bf2Smrg    case VIA_P4M800PRO:
357983b4bf2Smrg        /* 3C5.13[3] - DVP0D8 pin strapping
358983b4bf2Smrg         *             0: AGP pins are used for AGP
359983b4bf2Smrg         *             1: AGP pins are used by FPDP
360983b4bf2Smrg         *                (Flat Panel Display Port)
361983b4bf2Smrg         * 3C5.12[6] - DVP0D6 pin strapping
362983b4bf2Smrg         *             0: Disable DVP0 (Digital Video Port 0)
363983b4bf2Smrg         *             1: Enable DVP0 (Digital Video Port 0)
364983b4bf2Smrg         * 3C5.12[5] - DVP0D5 pin strapping
365983b4bf2Smrg         *             0: DVP0 is used by a TMDS transmitter (DVI)
366983b4bf2Smrg         *             1: DVP0 is used by a TV encoder
367983b4bf2Smrg         * 3C5.12[4] - DVP0D4 pin strapping
368983b4bf2Smrg         *             0: Dual 12-bit FPDP (Flat Panel Display Port)
369983b4bf2Smrg         *             1: 24-bit FPDP (Flat Panel Display Port) */
370983b4bf2Smrg        if ((sr12 & 0x40) && (sr12 & 0x20)) {
371983b4bf2Smrg            viaDVP0SetClockDriveStrength(pScrn, clockDriveStrength);
372983b4bf2Smrg        } else if ((sr13 & 0x08) && (!(sr12 & 0x10))) {
373983b4bf2Smrg        } else if (sr13 & 0x08) {
374983b4bf2Smrg            viaDVP1SetClockDriveStrength(pScrn, clockDriveStrength);
375983b4bf2Smrg        }
376983b4bf2Smrg
377983b4bf2Smrg        break;
378983b4bf2Smrg    case VIA_P4M890:
379983b4bf2Smrg    case VIA_K8M890:
380983b4bf2Smrg    case VIA_P4M900:
381983b4bf2Smrg        /* 3C5.12[6] - FPD6 pin strapping
382983b4bf2Smrg         *             0: Disable DVP0 (Digital Video Port 0)
383983b4bf2Smrg         *             1: Enable DVP0 (Digital Video Port 0)
384983b4bf2Smrg         * 3C5.12[5] - FPD5 pin strapping
385983b4bf2Smrg         *             0: DVP0 is used by a TMDS transmitter (DVI)
386983b4bf2Smrg         *             1: DVP0 is used by a TV encoder
387983b4bf2Smrg         * 3C5.12[4] - FPD4 pin strapping
388983b4bf2Smrg         *             0: Dual 12-bit FPDP (Flat Panel Display Port)
389983b4bf2Smrg         *             1: 24-bit FPDP (Flat Panel Display Port) */
390983b4bf2Smrg        if ((sr12 & 0x40) && (sr12 & 0x20) && (!(sr12 & 0x10))) {
391983b4bf2Smrg            viaDVP0SetClockDriveStrength(pScrn, clockDriveStrength);
392983b4bf2Smrg        }
393983b4bf2Smrg
394983b4bf2Smrg        break;
395983b4bf2Smrg    case VIA_CX700:
396983b4bf2Smrg    case VIA_VX800:
397983b4bf2Smrg    case VIA_VX855:
398983b4bf2Smrg    case VIA_VX900:
399983b4bf2Smrg        /* 3C5.13[6] - DVP1 DVP / capture port selection
400983b4bf2Smrg         *             0: DVP1 is used as a DVP (Digital Video Port)
401983b4bf2Smrg         *             1: DVP1 is used as a capture port */
402983b4bf2Smrg        if (!(sr13 & 0x40)) {
403983b4bf2Smrg            viaDVP1SetClockDriveStrength(pScrn, clockDriveStrength);
404983b4bf2Smrg        }
405983b4bf2Smrg
406983b4bf2Smrg        break;
407983b4bf2Smrg    default:
408983b4bf2Smrg        break;
409983b4bf2Smrg    }
410983b4bf2Smrg
411983b4bf2Smrg    if ((pVia->Chipset == VIA_CX700)
412983b4bf2Smrg        || (pVia->Chipset == VIA_VX800)
413983b4bf2Smrg        || (pVia->Chipset == VIA_VX855)
414983b4bf2Smrg        || (pVia->Chipset == VIA_VX900)) {
415983b4bf2Smrg
416983b4bf2Smrg        hwp->writeSeq(hwp, 0x5A, sr5a);
417983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
418983b4bf2Smrg                            "Restoring 3C5.5A[0].\n"));
419983b4bf2Smrg    }
420983b4bf2Smrg
421983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
422983b4bf2Smrg                        "Exiting viaTVSetClockDriveStrength.\n"));
423983b4bf2Smrg}
424983b4bf2Smrg
425983b4bf2Smrgstatic void
426983b4bf2SmrgviaTVSetDataDriveStrength(ScrnInfoPtr pScrn, CARD8 dataDriveStrength)
427983b4bf2Smrg{
428983b4bf2Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
429983b4bf2Smrg    VIAPtr pVia = VIAPTR(pScrn);
430983b4bf2Smrg    CARD8 sr12, sr13, sr5a;
431983b4bf2Smrg
432983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
433983b4bf2Smrg                        "Entered viaTVSetDataDriveStrength.\n"));
434983b4bf2Smrg
435983b4bf2Smrg    if ((pVia->Chipset == VIA_CX700)
436983b4bf2Smrg        || (pVia->Chipset == VIA_VX800)
437983b4bf2Smrg        || (pVia->Chipset == VIA_VX855)
438983b4bf2Smrg        || (pVia->Chipset == VIA_VX900)) {
439983b4bf2Smrg
440983b4bf2Smrg        sr5a = hwp->readSeq(hwp, 0x5A);
441983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
442983b4bf2Smrg                            "SR5A: 0x%02X\n", sr5a));
443983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
444983b4bf2Smrg                            "Setting 3C5.5A[0] to 0.\n"));
445983b4bf2Smrg        ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
446983b4bf2Smrg    }
447983b4bf2Smrg
448983b4bf2Smrg    sr12 = hwp->readSeq(hwp, 0x12);
449983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
450983b4bf2Smrg                        "SR12: 0x%02X\n", sr12));
451983b4bf2Smrg    sr13 = hwp->readSeq(hwp, 0x13);
452983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
453983b4bf2Smrg                        "SR13: 0x%02X\n", sr13));
454983b4bf2Smrg    switch (pVia->Chipset) {
455983b4bf2Smrg    case VIA_CLE266:
456983b4bf2Smrg        /* 3C5.12[5] - FPD18 pin strapping
457983b4bf2Smrg         *             0: DIP0 (Digital Interface Port 0) is used by
458983b4bf2Smrg         *                a TMDS transmitter (DVI)
459983b4bf2Smrg         *             1: DIP0 (Digital Interface Port 0) is used by
460983b4bf2Smrg         *                a TV encoder */
461983b4bf2Smrg        if (sr12 & 0x20) {
462983b4bf2Smrg            viaDIP0SetDataDriveStrength(pScrn, dataDriveStrength);
463983b4bf2Smrg        }
464983b4bf2Smrg
465983b4bf2Smrg        break;
466983b4bf2Smrg    case VIA_KM400:
467983b4bf2Smrg    case VIA_K8M800:
468983b4bf2Smrg    case VIA_PM800:
469983b4bf2Smrg    case VIA_P4M800PRO:
470983b4bf2Smrg        /* 3C5.13[3] - DVP0D8 pin strapping
471983b4bf2Smrg         *             0: AGP pins are used for AGP
472983b4bf2Smrg         *             1: AGP pins are used by FPDP
473983b4bf2Smrg         *                (Flat Panel Display Port)
474983b4bf2Smrg         * 3C5.12[6] - DVP0D6 pin strapping
475983b4bf2Smrg         *             0: Disable DVP0 (Digital Video Port 0)
476983b4bf2Smrg         *             1: Enable DVP0 (Digital Video Port 0)
477983b4bf2Smrg         * 3C5.12[5] - DVP0D5 pin strapping
478983b4bf2Smrg         *             0: DVP0 is used by a TMDS transmitter (DVI)
479983b4bf2Smrg         *             1: DVP0 is used by a TV encoder
480983b4bf2Smrg         * 3C5.12[4] - DVP0D4 pin strapping
481983b4bf2Smrg         *             0: Dual 12-bit FPDP (Flat Panel Display Port)
482983b4bf2Smrg         *             1: 24-bit FPDP (Flat Panel Display Port) */
483983b4bf2Smrg        if ((sr12 & 0x40) && (sr12 & 0x20)) {
484983b4bf2Smrg            viaDVP0SetDataDriveStrength(pScrn, dataDriveStrength);
485983b4bf2Smrg        } else if ((sr13 & 0x08) && (!(sr12 & 0x10))) {
486983b4bf2Smrg        } else if (sr13 & 0x08) {
487983b4bf2Smrg            viaDVP1SetDataDriveStrength(pScrn, dataDriveStrength);
488983b4bf2Smrg        }
489983b4bf2Smrg
490983b4bf2Smrg        break;
491983b4bf2Smrg    case VIA_P4M890:
492983b4bf2Smrg    case VIA_K8M890:
493983b4bf2Smrg    case VIA_P4M900:
494983b4bf2Smrg        /* 3C5.12[6] - FPD6 pin strapping
495983b4bf2Smrg         *             0: Disable DVP0 (Digital Video Port 0)
496983b4bf2Smrg         *             1: Enable DVP0 (Digital Video Port 0)
497983b4bf2Smrg         * 3C5.12[5] - FPD5 pin strapping
498983b4bf2Smrg         *             0: DVP0 is used by a TMDS transmitter (DVI)
499983b4bf2Smrg         *             1: DVP0 is used by a TV encoder
500983b4bf2Smrg         * 3C5.12[4] - FPD4 pin strapping
501983b4bf2Smrg         *             0: Dual 12-bit FPDP (Flat Panel Display Port)
502983b4bf2Smrg         *             1: 24-bit FPDP (Flat Panel Display Port) */
503983b4bf2Smrg        if ((sr12 & 0x40) && (sr12 & 0x20) && (!(sr12 & 0x10))) {
504983b4bf2Smrg            viaDVP0SetDataDriveStrength(pScrn, dataDriveStrength);
505983b4bf2Smrg        }
506983b4bf2Smrg
507983b4bf2Smrg        break;
508983b4bf2Smrg    case VIA_CX700:
509983b4bf2Smrg    case VIA_VX800:
510983b4bf2Smrg    case VIA_VX855:
511983b4bf2Smrg    case VIA_VX900:
512983b4bf2Smrg        /* 3C5.13[6] - DVP1 DVP / capture port selection
513983b4bf2Smrg         *             0: DVP1 is used as a DVP (Digital Video Port)
514983b4bf2Smrg         *             1: DVP1 is used as a capture port */
515983b4bf2Smrg        if (!(sr13 & 0x40)) {
516983b4bf2Smrg            viaDVP1SetDataDriveStrength(pScrn, dataDriveStrength);
517983b4bf2Smrg        }
518983b4bf2Smrg
519983b4bf2Smrg        break;
520983b4bf2Smrg    default:
521983b4bf2Smrg        break;
522983b4bf2Smrg    }
523983b4bf2Smrg
524983b4bf2Smrg    if ((pVia->Chipset == VIA_CX700)
525983b4bf2Smrg        || (pVia->Chipset == VIA_VX800)
526983b4bf2Smrg        || (pVia->Chipset == VIA_VX855)
527983b4bf2Smrg        || (pVia->Chipset == VIA_VX900)) {
528983b4bf2Smrg
529983b4bf2Smrg        hwp->writeSeq(hwp, 0x5A, sr5a);
530983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
531983b4bf2Smrg                            "Restoring 3C5.5A[0].\n"));
532983b4bf2Smrg    }
533983b4bf2Smrg
534983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
535983b4bf2Smrg                        "Exiting viaTVSetDataDriveStrength.\n"));
536983b4bf2Smrg}
537983b4bf2Smrg
538983b4bf2Smrgstatic void
539983b4bf2SmrgViaTVSave(ScrnInfoPtr pScrn)
540983b4bf2Smrg{
541983b4bf2Smrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
542983b4bf2Smrg
543983b4bf2Smrg    if (pBIOSInfo->TVSave)
544983b4bf2Smrg        pBIOSInfo->TVSave(pScrn);
545983b4bf2Smrg}
546983b4bf2Smrg
547983b4bf2Smrgstatic void
548983b4bf2SmrgViaTVRestore(ScrnInfoPtr pScrn)
549983b4bf2Smrg{
550983b4bf2Smrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
551983b4bf2Smrg
552983b4bf2Smrg    if (pBIOSInfo->TVRestore)
553983b4bf2Smrg        pBIOSInfo->TVRestore(pScrn);
554983b4bf2Smrg}
555983b4bf2Smrg
556983b4bf2Smrgstatic Bool
557983b4bf2SmrgViaTVDACSense(ScrnInfoPtr pScrn)
558983b4bf2Smrg{
559983b4bf2Smrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
560983b4bf2Smrg
561983b4bf2Smrg    if (pBIOSInfo->TVDACSense)
562983b4bf2Smrg        return pBIOSInfo->TVDACSense(pScrn);
563983b4bf2Smrg    return FALSE;
564983b4bf2Smrg}
565983b4bf2Smrg
566983b4bf2Smrgstatic void
567983b4bf2SmrgViaTVSetMode(xf86CrtcPtr crtc, DisplayModePtr mode)
568983b4bf2Smrg{
569983b4bf2Smrg    ScrnInfoPtr pScrn = crtc->scrn;
570983b4bf2Smrg    VIAPtr pVia = VIAPTR(pScrn);
571983b4bf2Smrg    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
572983b4bf2Smrg
573983b4bf2Smrg    if (pBIOSInfo->TVModeI2C)
574983b4bf2Smrg        pBIOSInfo->TVModeI2C(pScrn, mode);
575983b4bf2Smrg
576983b4bf2Smrg    if (pBIOSInfo->TVModeCrtc)
577983b4bf2Smrg        pBIOSInfo->TVModeCrtc(crtc, mode);
578983b4bf2Smrg
579983b4bf2Smrg    /* TV reset. */
580983b4bf2Smrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x00);
581983b4bf2Smrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x80);
582983b4bf2Smrg}
583983b4bf2Smrg
584983b4bf2Smrgstatic void
585983b4bf2SmrgViaTVPower(ScrnInfoPtr pScrn, Bool On)
586983b4bf2Smrg{
587983b4bf2Smrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
588983b4bf2Smrg
589983b4bf2Smrg#ifdef HAVE_DEBUG
590983b4bf2Smrg    if (On)
591983b4bf2Smrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaTVPower: On.\n");
592983b4bf2Smrg    else
593983b4bf2Smrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaTVPower: Off.\n");
594983b4bf2Smrg#endif
595983b4bf2Smrg
596983b4bf2Smrg    if (pBIOSInfo->TVPower)
597983b4bf2Smrg        pBIOSInfo->TVPower(pScrn, On);
598983b4bf2Smrg}
599983b4bf2Smrg
600983b4bf2Smrg#ifdef HAVE_DEBUG
601983b4bf2Smrgvoid
602983b4bf2SmrgViaTVPrintRegs(ScrnInfoPtr pScrn)
603983b4bf2Smrg{
604983b4bf2Smrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
605983b4bf2Smrg
606983b4bf2Smrg    if (pBIOSInfo->TVPrintRegs)
607983b4bf2Smrg        pBIOSInfo->TVPrintRegs(pScrn);
608983b4bf2Smrg}
609983b4bf2Smrg#endif /* HAVE_DEBUG */
610983b4bf2Smrg
611983b4bf2Smrgstatic void
612983b4bf2Smrgvia_tv_create_resources(xf86OutputPtr output)
613983b4bf2Smrg{
614983b4bf2Smrg}
615983b4bf2Smrg
616983b4bf2Smrg#ifdef RANDR_12_INTERFACE
617983b4bf2Smrgstatic Bool
618983b4bf2Smrgvia_tv_set_property(xf86OutputPtr output, Atom property,
619983b4bf2Smrg                    RRPropertyValuePtr value)
620983b4bf2Smrg{
621983b4bf2Smrg    return TRUE;
622983b4bf2Smrg}
623983b4bf2Smrg
624983b4bf2Smrgstatic Bool
625983b4bf2Smrgvia_tv_get_property(xf86OutputPtr output, Atom property)
626983b4bf2Smrg{
627983b4bf2Smrg    return FALSE;
628983b4bf2Smrg}
629983b4bf2Smrg#endif
630983b4bf2Smrg
631983b4bf2Smrgstatic void
632983b4bf2Smrgvia_tv_dpms(xf86OutputPtr output, int mode)
633983b4bf2Smrg{
634983b4bf2Smrg    ScrnInfoPtr pScrn = output->scrn;
635983b4bf2Smrg
636983b4bf2Smrg    switch (mode) {
637983b4bf2Smrg    case DPMSModeOn:
638983b4bf2Smrg        ViaTVPower(pScrn, TRUE);
639983b4bf2Smrg        break;
640983b4bf2Smrg
641983b4bf2Smrg    case DPMSModeStandby:
642983b4bf2Smrg    case DPMSModeSuspend:
643983b4bf2Smrg    case DPMSModeOff:
644983b4bf2Smrg        ViaTVPower(pScrn, FALSE);
645983b4bf2Smrg        break;
646983b4bf2Smrg    }
647983b4bf2Smrg}
648983b4bf2Smrg
649983b4bf2Smrgstatic void
650983b4bf2Smrgvia_tv_save(xf86OutputPtr output)
651983b4bf2Smrg{
652983b4bf2Smrg    ScrnInfoPtr pScrn = output->scrn;
653983b4bf2Smrg
654983b4bf2Smrg    ViaTVSave(pScrn);
655983b4bf2Smrg}
656983b4bf2Smrg
657983b4bf2Smrgstatic void
658983b4bf2Smrgvia_tv_restore(xf86OutputPtr output)
659983b4bf2Smrg{
660983b4bf2Smrg    ScrnInfoPtr pScrn = output->scrn;
661983b4bf2Smrg
662983b4bf2Smrg    ViaTVRestore(pScrn);
663983b4bf2Smrg}
664983b4bf2Smrg
665983b4bf2Smrgstatic int
666983b4bf2Smrgvia_tv_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
667983b4bf2Smrg{
668983b4bf2Smrg    ScrnInfoPtr pScrn = output->scrn;
669983b4bf2Smrg    int ret = MODE_OK;
670983b4bf2Smrg
671983b4bf2Smrg    if (!ViaModeDotClockTranslate(pScrn, pMode))
672983b4bf2Smrg        return MODE_NOCLOCK;
673983b4bf2Smrg
674983b4bf2Smrg    return ret;
675983b4bf2Smrg}
676983b4bf2Smrg
677983b4bf2Smrgstatic Bool
678983b4bf2Smrgvia_tv_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
679983b4bf2Smrg                  DisplayModePtr adjusted_mode)
680983b4bf2Smrg{
681983b4bf2Smrg    return TRUE;
682983b4bf2Smrg}
683983b4bf2Smrg
684983b4bf2Smrgstatic void
685983b4bf2Smrgvia_tv_prepare(xf86OutputPtr output)
686983b4bf2Smrg{
687983b4bf2Smrg    via_tv_dpms(output, DPMSModeOff);
688983b4bf2Smrg}
689983b4bf2Smrg
690983b4bf2Smrgstatic void
691983b4bf2Smrgvia_tv_commit(xf86OutputPtr output)
692983b4bf2Smrg{
693983b4bf2Smrg    via_tv_dpms(output, DPMSModeOn);
694983b4bf2Smrg}
695983b4bf2Smrg
696983b4bf2Smrgstatic void
697983b4bf2Smrgvia_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
698983b4bf2Smrg                DisplayModePtr adjusted_mode)
699983b4bf2Smrg{
700983b4bf2Smrg    ScrnInfoPtr pScrn = output->scrn;
701983b4bf2Smrg    drmmode_crtc_private_ptr iga = output->crtc->driver_private;
702983b4bf2Smrg    VIAPtr pVia = VIAPTR(pScrn);
703983b4bf2Smrg
704983b4bf2Smrg    /* TV on FirstCrtc */
705983b4bf2Smrg    if (output->crtc) {
706983b4bf2Smrg        viaTVSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00);
707983b4bf2Smrg
708983b4bf2Smrg        /* Set I/O pads to automatic on / off mode. */
709983b4bf2Smrg        viaTVEnableIOPads(pScrn, 0x03);
710983b4bf2Smrg
711983b4bf2Smrg        viaTVSetClockDriveStrength(pScrn, 0x03);
712983b4bf2Smrg        viaTVSetDataDriveStrength(pScrn, 0x03);
713983b4bf2Smrg
714983b4bf2Smrg        ViaTVSetMode(output->crtc, adjusted_mode);
715983b4bf2Smrg    }
716983b4bf2Smrg
717983b4bf2Smrg    pVia->FirstInit = FALSE;
718983b4bf2Smrg}
719983b4bf2Smrg
720983b4bf2Smrgstatic xf86OutputStatus
721983b4bf2Smrgvia_tv_detect(xf86OutputPtr output)
722983b4bf2Smrg{
723983b4bf2Smrg    xf86OutputStatus status = XF86OutputStatusDisconnected;
724983b4bf2Smrg    ScrnInfoPtr pScrn = output->scrn;
725983b4bf2Smrg
726983b4bf2Smrg    if (ViaTVDACSense(pScrn))
727983b4bf2Smrg        status = XF86OutputStatusConnected;
728983b4bf2Smrg    return status;
729983b4bf2Smrg}
730983b4bf2Smrg
731983b4bf2Smrgstatic DisplayModePtr
732983b4bf2Smrgvia_tv_get_modes(xf86OutputPtr output)
733983b4bf2Smrg{
734983b4bf2Smrg    DisplayModePtr modes = NULL, mode = NULL;
735983b4bf2Smrg    ScrnInfoPtr pScrn = output->scrn;
736983b4bf2Smrg    VIAPtr pVia = VIAPTR(pScrn);
737983b4bf2Smrg    int i;
738983b4bf2Smrg
739983b4bf2Smrg    for (i = 0; i < pVia->pBIOSInfo->TVNumModes; i++) {
740983b4bf2Smrg        mode = xf86DuplicateMode(&pVia->pBIOSInfo->TVModes[i]);
741983b4bf2Smrg        modes = xf86ModesAdd(modes, mode);
742983b4bf2Smrg    }
743983b4bf2Smrg    return modes;
744983b4bf2Smrg}
745983b4bf2Smrg
746983b4bf2Smrgstatic void
747983b4bf2Smrgvia_tv_destroy(xf86OutputPtr output)
748983b4bf2Smrg{
749983b4bf2Smrg}
750983b4bf2Smrg
751983b4bf2Smrgstatic const xf86OutputFuncsRec via_tv_funcs = {
752983b4bf2Smrg    .create_resources   = via_tv_create_resources,
753983b4bf2Smrg#ifdef RANDR_12_INTERFACE
754983b4bf2Smrg    .set_property       = via_tv_set_property,
755983b4bf2Smrg#endif
756983b4bf2Smrg#ifdef RANDR_13_INTERFACE
757983b4bf2Smrg    .get_property       = via_tv_get_property,
758983b4bf2Smrg#endif
759983b4bf2Smrg    .dpms               = via_tv_dpms,
760983b4bf2Smrg    .save               = via_tv_save,
761983b4bf2Smrg    .restore            = via_tv_restore,
762983b4bf2Smrg    .mode_valid         = via_tv_mode_valid,
763983b4bf2Smrg    .mode_fixup         = via_tv_mode_fixup,
764983b4bf2Smrg    .prepare            = via_tv_prepare,
765983b4bf2Smrg    .commit             = via_tv_commit,
766983b4bf2Smrg    .mode_set           = via_tv_mode_set,
767983b4bf2Smrg    .detect             = via_tv_detect,
768983b4bf2Smrg    .get_modes          = via_tv_get_modes,
769983b4bf2Smrg    .destroy            = via_tv_destroy,
770983b4bf2Smrg};
771983b4bf2Smrg
772983b4bf2Smrg/*
773983b4bf2Smrg *
774983b4bf2Smrg */
775983b4bf2SmrgBool
776983b4bf2Smrgvia_tv_init(ScrnInfoPtr pScrn)
777983b4bf2Smrg{
778983b4bf2Smrg    VIAPtr pVia = VIAPTR(pScrn);
779983b4bf2Smrg    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
780983b4bf2Smrg    xf86OutputPtr output = NULL;
781983b4bf2Smrg
782983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
783983b4bf2Smrg                        "Entered via_tv_init.\n"));
784983b4bf2Smrg
785983b4bf2Smrg    /* preset some pBIOSInfo TV related values -- move up */
786983b4bf2Smrg    pBIOSInfo->TVEncoder = VIA_NONETV;
787983b4bf2Smrg    pBIOSInfo->TVI2CDev = NULL;
788983b4bf2Smrg    pBIOSInfo->TVSave = NULL;
789983b4bf2Smrg    pBIOSInfo->TVRestore = NULL;
790983b4bf2Smrg    pBIOSInfo->TVDACSense = NULL;
791983b4bf2Smrg    pBIOSInfo->TVModeValid = NULL;
792983b4bf2Smrg    pBIOSInfo->TVModeI2C = NULL;
793983b4bf2Smrg    pBIOSInfo->TVModeCrtc = NULL;
794983b4bf2Smrg    pBIOSInfo->TVPower = NULL;
795983b4bf2Smrg    pBIOSInfo->TVModes = NULL;
796983b4bf2Smrg    pBIOSInfo->TVPrintRegs = NULL;
797983b4bf2Smrg    pBIOSInfo->LCDPower = NULL;
798983b4bf2Smrg    pBIOSInfo->TVNumRegs = 0;
799983b4bf2Smrg
800983b4bf2Smrg    /*
801983b4bf2Smrg     * On an SK43G (KM400/Ch7011), false positive detections at a VT162x
802983b4bf2Smrg     * chip were observed, so try to detect the Ch7011 first.
803983b4bf2Smrg     */
804983b4bf2Smrg    if (pVia->pI2CBus2 && xf86I2CProbeAddress(pVia->pI2CBus2, 0xEC))
805983b4bf2Smrg        pBIOSInfo->TVI2CDev = ViaCH7xxxDetect(pScrn, pVia->pI2CBus2, 0xEC);
806983b4bf2Smrg    else if (pVia->pI2CBus2 && xf86I2CProbeAddress(pVia->pI2CBus2, 0x40))
807983b4bf2Smrg        pBIOSInfo->TVI2CDev = ViaVT162xDetect(pScrn, pVia->pI2CBus2, 0x40);
808983b4bf2Smrg    else if (pVia->pI2CBus3 && xf86I2CProbeAddress(pVia->pI2CBus3, 0x40))
809983b4bf2Smrg        pBIOSInfo->TVI2CDev = ViaVT162xDetect(pScrn, pVia->pI2CBus3, 0x40);
810983b4bf2Smrg    else if (pVia->pI2CBus2 && xf86I2CProbeAddress(pVia->pI2CBus2, 0xEA))
811983b4bf2Smrg        pBIOSInfo->TVI2CDev = ViaCH7xxxDetect(pScrn, pVia->pI2CBus2, 0xEA);
812983b4bf2Smrg    else if (pVia->pI2CBus3 && xf86I2CProbeAddress(pVia->pI2CBus3, 0xEA))
813983b4bf2Smrg        pBIOSInfo->TVI2CDev = ViaCH7xxxDetect(pScrn, pVia->pI2CBus3, 0xEA);
814983b4bf2Smrg
815983b4bf2Smrg    if (!pBIOSInfo->TVI2CDev) {
816983b4bf2Smrg        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
817983b4bf2Smrg                    "Did not detect a TV encoder.\n");
818983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
819983b4bf2Smrg                            "Exiting via_tv_init.\n"));
820983b4bf2Smrg
821983b4bf2Smrg        return FALSE;
822983b4bf2Smrg    }
823983b4bf2Smrg
824983b4bf2Smrg    switch (pBIOSInfo->TVEncoder) {
825983b4bf2Smrg        case VIA_VT1621:
826983b4bf2Smrg        case VIA_VT1622:
827983b4bf2Smrg        case VIA_VT1623:
828983b4bf2Smrg        case VIA_VT1625:
829983b4bf2Smrg            ViaVT162xInit(pScrn);
830983b4bf2Smrg            break;
831983b4bf2Smrg        case VIA_CH7011:
832983b4bf2Smrg        case VIA_CH7019A:
833983b4bf2Smrg        case VIA_CH7019B:
834983b4bf2Smrg            ViaCH7xxxInit(pScrn);
835983b4bf2Smrg            break;
836983b4bf2Smrg        default:
837983b4bf2Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
838983b4bf2Smrg                        "Was not able to initialize a known TV encoder.\n");
839983b4bf2Smrg            DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
840983b4bf2Smrg                                "Exiting via_tv_init.\n"));
841983b4bf2Smrg            return FALSE;
842983b4bf2Smrg            break;
843983b4bf2Smrg    }
844983b4bf2Smrg
845983b4bf2Smrg    if (!pBIOSInfo->TVSave || !pBIOSInfo->TVRestore
846983b4bf2Smrg        || !pBIOSInfo->TVDACSense || !pBIOSInfo->TVModeValid
847983b4bf2Smrg        || !pBIOSInfo->TVModeI2C || !pBIOSInfo->TVModeCrtc
848983b4bf2Smrg        || !pBIOSInfo->TVPower || !pBIOSInfo->TVModes
849983b4bf2Smrg        || !pBIOSInfo->TVPrintRegs) {
850983b4bf2Smrg
851983b4bf2Smrg        xf86DestroyI2CDevRec(pBIOSInfo->TVI2CDev, TRUE);
852983b4bf2Smrg
853983b4bf2Smrg        pBIOSInfo->TVI2CDev = NULL;
854983b4bf2Smrg        pBIOSInfo->TVOutput = TVOUTPUT_NONE;
855983b4bf2Smrg        pBIOSInfo->TVEncoder = VIA_NONETV;
856983b4bf2Smrg        pBIOSInfo->TVI2CDev = NULL;
857983b4bf2Smrg        pBIOSInfo->TVSave = NULL;
858983b4bf2Smrg        pBIOSInfo->TVRestore = NULL;
859983b4bf2Smrg        pBIOSInfo->TVDACSense = NULL;
860983b4bf2Smrg        pBIOSInfo->TVModeValid = NULL;
861983b4bf2Smrg        pBIOSInfo->TVModeI2C = NULL;
862983b4bf2Smrg        pBIOSInfo->TVModeCrtc = NULL;
863983b4bf2Smrg        pBIOSInfo->TVPower = NULL;
864983b4bf2Smrg        pBIOSInfo->TVModes = NULL;
865983b4bf2Smrg        pBIOSInfo->TVPrintRegs = NULL;
866983b4bf2Smrg        pBIOSInfo->TVNumRegs = 0;
867983b4bf2Smrg
868983b4bf2Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
869983b4bf2Smrg                   "TV encoder was not properly initialized.\n");
870983b4bf2Smrg        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
871983b4bf2Smrg                            "Exiting via_tv_init.\n"));
872983b4bf2Smrg        return FALSE;
873983b4bf2Smrg    }
874983b4bf2Smrg
875983b4bf2Smrg    output = xf86OutputCreate(pScrn, &via_tv_funcs, "TV-1");
876983b4bf2Smrg    pVia->FirstInit = TRUE;
877983b4bf2Smrg
878983b4bf2Smrg    if (output) {
879983b4bf2Smrg        /* Allow tv output on both crtcs, set bit 0 and 1. */
880983b4bf2Smrg        output->possible_crtcs = 0x3;
881983b4bf2Smrg    } else {
882983b4bf2Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
883983b4bf2Smrg                   "Failed to register TV-1.\n");
884983b4bf2Smrg    }
885983b4bf2Smrg
886983b4bf2Smrg    pBIOSInfo->tv = output;
887983b4bf2Smrg    /* Save now */
888983b4bf2Smrg    pBIOSInfo->TVSave(pScrn);
889983b4bf2Smrg
890983b4bf2Smrg#ifdef HAVE_DEBUG
891983b4bf2Smrg    if (VIAPTR(pScrn)->PrintTVRegs)
892983b4bf2Smrg        pBIOSInfo->TVPrintRegs(pScrn);
893983b4bf2Smrg#endif
894983b4bf2Smrg
895983b4bf2Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
896983b4bf2Smrg                        "Exiting via_tv_init.\n"));
897983b4bf2Smrg    return TRUE;
898983b4bf2Smrg}
899