1/*
2 * Copyright 2004-2005 The Unichrome Project  [unichrome.sf.net]
3 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
4 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sub license,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include "via_driver.h"
31#include "via_vt162x.h"
32
33static void
34ViaSetTVClockSource(xf86CrtcPtr crtc)
35{
36	drmmode_crtc_private_ptr iga = crtc->driver_private;
37	ScrnInfoPtr pScrn = crtc->scrn;
38	VIAPtr pVia = VIAPTR(pScrn);
39	VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
40	vgaHWPtr hwp = VGAHWPTR(pScrn);
41
42	DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaSetTVClockSource\n"));
43
44    switch(pBIOSInfo->TVEncoder) {
45        case VIA_VT1625:
46            /* External TV: */
47            switch(pVia->Chipset) {
48                case VIA_CX700:
49                case VIA_VX800:
50                case VIA_VX855:
51                case VIA_VX900:
52                    /* IGA1 */
53                    if (!iga->index) {
54                        /* Fixing it to DVP1 for IGA1. */
55                        ViaCrtcMask(hwp, 0x6C, 0xB0, 0xF0);
56                    /* IGA2 */
57                    } else {
58                        /* Fixing it to DVP1 for IGA2. */
59                        ViaCrtcMask(hwp, 0x6C, 0x0B, 0x0F);
60                    }
61                    break;
62                default:
63                    if (!iga->index)
64                        ViaCrtcMask(hwp, 0x6C, 0x21, 0x21);
65                    else
66                        ViaCrtcMask(hwp, 0x6C, 0xA1, 0xA1);
67                    break;
68            }
69            break;
70        default:
71			if (!iga->index)
72				ViaCrtcMask(hwp, 0x6C, 0x50, 0xF0);
73			else
74				ViaCrtcMask(hwp, 0x6C, 0x05, 0x0F);
75            break;
76    }
77
78}
79
80static void
81VT162xPrintRegs(ScrnInfoPtr pScrn)
82{
83    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
84    CARD8 i, buf;
85
86
87    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Printing registers for %s\n",
88               pBIOSInfo->TVI2CDev->DevName);
89
90    for (i = 0; i < pBIOSInfo->TVNumRegs; i++) {
91        xf86I2CReadByte(pBIOSInfo->TVI2CDev, i, &buf);
92        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV%02X: 0x%02X\n", i, buf);
93    }
94
95    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of TV registers.\n");
96}
97
98
99I2CDevPtr
100ViaVT162xDetect(ScrnInfoPtr pScrn, I2CBusPtr pBus, CARD8 Address)
101{
102    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
103    I2CDevPtr pDev = xf86CreateI2CDevRec();
104    CARD8 buf;
105
106    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaVT162xDetect\n"));
107
108    pDev->DevName = "VT162x";
109    pDev->SlaveAddr = Address;
110    pDev->pI2CBus = pBus;
111
112    if (!xf86I2CDevInit(pDev)) {
113        xf86DestroyI2CDevRec(pDev, TRUE);
114        return NULL;
115    }
116
117    if (!xf86I2CReadByte(pDev, 0x1B, &buf)) {
118        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
119                   "Unable to read from %s Slave %d.\n",
120                   pBus->BusName, Address);
121        xf86DestroyI2CDevRec(pDev, TRUE);
122        return NULL;
123    }
124
125    switch (buf) {
126        case 0x02:
127            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
128                       "Detected VIA Technologies VT1621 TV Encoder\n");
129            pBIOSInfo->TVEncoder = VIA_VT1621;
130            pDev->DevName = "VT1621";
131            break;
132        case 0x03:
133            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
134                       "Detected VIA Technologies VT1622 TV Encoder\n");
135            pBIOSInfo->TVEncoder = VIA_VT1622;
136            pDev->DevName = "VT1622";
137            break;
138        case 0x10:
139            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
140                       "Detected VIA Technologies VT1622A/VT1623 TV Encoder\n");
141            pBIOSInfo->TVEncoder = VIA_VT1623;
142            pDev->DevName = "VT1623";
143            break;
144        case 0x50:
145            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
146                       "Detected VIA Technologies VT1625 TV Encoder\n");
147            pBIOSInfo->TVEncoder = VIA_VT1625;
148            pDev->DevName = "VT1625";
149            break;
150        default:
151            pBIOSInfo->TVEncoder = VIA_NONETV;
152            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
153                       "Unknown TV Encoder found at %s %X.\n",
154                       pBus->BusName, Address);
155            xf86DestroyI2CDevRec(pDev, TRUE);
156            pDev = NULL;
157            break;
158    }
159
160    return pDev;
161}
162
163
164static void
165VT162xSave(ScrnInfoPtr pScrn)
166{
167    int i;
168    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
169
170    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT162xSave\n"));
171
172    for (i = 0; i < pBIOSInfo->TVNumRegs; i++)
173        xf86I2CReadByte(pBIOSInfo->TVI2CDev, i, &(pBIOSInfo->TVRegs[i]));
174
175}
176
177static void
178VT162xRestore(ScrnInfoPtr pScrn)
179{
180    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
181    int i;
182
183    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT162xRestore\n"));
184
185    for (i = 0; i < pBIOSInfo->TVNumRegs; i++)
186        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, pBIOSInfo->TVRegs[i]);
187}
188
189
190/*
191 * For VT1621 the same as for VT1622/VT1622A/VT1623, but result is different.
192 * Still needs testing on VT1621, of course.
193 */
194static CARD8
195VT162xDACSenseI2C(I2CDevPtr pDev)
196{
197    CARD8 save, sense;
198
199    xf86I2CReadByte(pDev, 0x0E, &save);
200    xf86I2CWriteByte(pDev, 0x0E, 0x00);
201    xf86I2CWriteByte(pDev, 0x0E, 0x80);
202    xf86I2CWriteByte(pDev, 0x0E, 0x00);
203    xf86I2CReadByte(pDev, 0x0F, &sense);
204    xf86I2CWriteByte(pDev, 0x0E, save);
205
206    return (sense & 0x0F);
207}
208
209/*
210 * VT1625/VT1625S sense connected TV outputs.
211 *
212 * The lower six bits of the return byte stand for each of the six DACs:
213 *  - bit 0: DACf (Cb)
214 *  - bit 1: DACe (Cr)
215 *  - bit 2: DACd (Y)
216 *  - bit 3: DACc (Composite)
217 *  - bit 4: DACb (S-Video C)
218 *  - bit 5: DACa (S-Video Y)
219 *
220 * If a bit is 0 it means a cable is connected. Note the VT1625S only has
221 * four DACs, corresponding to bit 0-3 above.
222 */
223static CARD8
224VT1625DACSenseI2C(I2CDevPtr pDev)
225{
226    CARD8 power, status, overflow, dacPresent;
227
228    xf86I2CReadByte(pDev, 0x0E, &power);     // save power state
229
230    // VT1625S will always report 0 for bits 4 and 5 of the status register as
231    // it only has four DACs instead of six. This will result in a false
232    // positive for the S-Video cable. It will also do this on the power
233    // register, which is abused to check which DACs are actually present.
234    xf86I2CWriteByte(pDev, 0x0E, 0xFF);
235    xf86I2CReadByte(pDev, 0x0E, &dacPresent);
236
237    xf86I2CWriteByte(pDev, 0x0E, 0x00);      // power on DACs/circuits
238    xf86I2CReadByte(pDev, 0x1C, &overflow);  // save overflow reg
239                                             // (DAC sense bit should be off)
240    xf86I2CWriteByte(pDev, 0x1C, 0x80);      // enable DAC sense bit
241    xf86I2CWriteByte(pDev, 0x1C, overflow);  // disable DAC sense bit
242    xf86I2CReadByte(pDev, 0x0F, &status);    // read connection status
243    xf86I2CWriteByte(pDev, 0x0E, power);     // restore power state
244    status |= ~dacPresent;
245
246    return (status & 0x3F);
247}
248
249/*
250 * VT1621 only knows composite and s-video.
251 */
252static Bool
253VT1621DACSense(ScrnInfoPtr pScrn)
254{
255    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
256    CARD8 sense;
257
258    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621DACSense\n"));
259
260    sense = VT162xDACSenseI2C(pBIOSInfo->TVI2CDev);
261    switch (sense) {
262        case 0x00:
263            pBIOSInfo->TVOutput = TVOUTPUT_SC;
264            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
265                       "VT1621: S-Video & Composite connected.\n");
266            return TRUE;
267        case 0x01:
268            pBIOSInfo->TVOutput = TVOUTPUT_COMPOSITE;
269            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
270                       "VT1621: Composite connected.\n");
271            return TRUE;
272        case 0x02:
273            pBIOSInfo->TVOutput = TVOUTPUT_SVIDEO;
274            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
275                       "VT1621: S-Video connected.\n");
276            return TRUE;
277        case 0x03:
278            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
279            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
280                       "VT1621: Nothing connected.\n");
281            return FALSE;
282        default:
283            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
284            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
285                       "VT1621: Unknown cable combination: 0x0%2X.\n", sense);
286            return FALSE;
287    }
288}
289
290/*
291 * VT1622, VT1622A and VT1623 know composite, s-video, RGB and YCBCR.
292 */
293static Bool
294VT1622DACSense(ScrnInfoPtr pScrn)
295{
296    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
297    CARD8 sense;
298
299    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622DACSense\n"));
300
301    sense = VT162xDACSenseI2C(pBIOSInfo->TVI2CDev);
302    switch (sense) {
303        case 0x00:  /* DAC A,B,C,D */
304            pBIOSInfo->TVOutput = TVOUTPUT_RGB;
305            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
306                       "VT162x: RGB connected.\n");
307            return TRUE;
308        case 0x01:  /* DAC A,B,C */
309            pBIOSInfo->TVOutput = TVOUTPUT_SC;
310            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
311                       "VT162x: S-Video & Composite connected.\n");
312            return TRUE;
313        case 0x07:  /* DAC A */
314            pBIOSInfo->TVOutput = TVOUTPUT_COMPOSITE;
315            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
316                       "VT162x: Composite connected.\n");
317            return TRUE;
318        case 0x08:  /* DAC B,C,D */
319            pBIOSInfo->TVOutput = TVOUTPUT_YCBCR;
320            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
321                       "VT162x: YcBcR connected.\n");
322            return TRUE;
323        case 0x09:  /* DAC B,C */
324            pBIOSInfo->TVOutput = TVOUTPUT_SVIDEO;
325            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
326                       "VT162x: S-Video connected.\n");
327            return TRUE;
328        case 0x0F:
329            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
330            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
331                       "VT162x: Nothing connected.\n");
332            return FALSE;
333        default:
334            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
335            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
336                       "VT162x: Unknown cable combination: 0x0%2X.\n", sense);
337            return FALSE;
338    }
339}
340
341/*
342 * VT1625 knows composite, s-video, RGB and YCBCR.
343 */
344static Bool
345VT1625DACSense(ScrnInfoPtr pScrn)
346{
347    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
348    CARD8 sense;
349
350    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1625DACSense\n"));
351
352    sense = VT1625DACSenseI2C(pBIOSInfo->TVI2CDev);
353    switch (sense) {
354        case 0x00:  /* DAC A,B,C,D,E,F */
355            pBIOSInfo->TVOutput = TVOUTPUT_RGB;
356            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
357                       "VT1625: RGB connected.\n");
358            return TRUE;
359        case 0x07:  /* DAC A,B,C */
360            pBIOSInfo->TVOutput = TVOUTPUT_SC;
361            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
362                       "VT1625: S-Video & Composite connected.\n");
363            return TRUE;
364        case 0x37:  /* DAC C */
365            pBIOSInfo->TVOutput = TVOUTPUT_COMPOSITE;
366            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
367                       "VT1625: Composite connected.\n");
368            return TRUE;
369        case 0x38:  /* DAC D,E,F */
370            pBIOSInfo->TVOutput = TVOUTPUT_YCBCR;
371            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
372                       "VT1625: YCbCr connected.\n");
373            return TRUE;
374        case 0x0F:  /* DAC A,B */
375            pBIOSInfo->TVOutput = TVOUTPUT_SVIDEO;
376            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
377                       "VT1625: S-Video connected.\n");
378            return TRUE;
379        case 0x3F:
380            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
381            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
382                       "VT1625: Nothing connected.\n");
383            return FALSE;
384        default:
385            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
386            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
387                       "VT1625: Unknown cable combination: 0x0%2X.\n", sense);
388            return FALSE;
389    }
390}
391
392static CARD8
393VT1621ModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
394{
395    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
396    int i;
397
398    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621ModeIndex\n"));
399
400    for (i = 0; VT1621Table[i].Width; i++) {
401        if ((VT1621Table[i].Width == mode->CrtcHDisplay) &&
402            (VT1621Table[i].Height == mode->CrtcVDisplay) &&
403            (VT1621Table[i].Standard == pBIOSInfo->TVType) &&
404            !(strcmp(VT1621Table[i].name, mode->name)))
405            return i;
406    }
407    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VT1621ModeIndex:"
408               " Mode \"%s\" not found in Table\n", mode->name);
409    return 0xFF;
410}
411
412static ModeStatus
413VT1621ModeValid(ScrnInfoPtr pScrn, DisplayModePtr mode)
414{
415    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
416
417    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621ModeValid\n"));
418
419    if ((mode->PrivSize != sizeof(struct VT162xModePrivate)) ||
420        ((mode->Private != (void *)&VT162xModePrivateNTSC) &&
421         (mode->Private != (void *)&VT162xModePrivatePAL))) {
422        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
423                   "Not a mode defined by the TV Encoder.\n");
424        return MODE_BAD;
425    }
426
427    if ((pBIOSInfo->TVType == TVTYPE_NTSC) &&
428        (mode->Private != (void *)&VT162xModePrivateNTSC)) {
429        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
430                   "TV standard is NTSC. This is a PAL mode.\n");
431        return MODE_BAD;
432    } else if ((pBIOSInfo->TVType == TVTYPE_PAL) &&
433               (mode->Private != (void *)&VT162xModePrivatePAL)) {
434        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
435                   "TV standard is PAL. This is a NTSC mode.\n");
436        return MODE_BAD;
437    }
438
439    if (VT1621ModeIndex(pScrn, mode) != 0xFF)
440        return MODE_OK;
441    return MODE_BAD;
442}
443
444static CARD8
445VT1622ModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
446{
447    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
448    struct VT162XTableRec *Table;
449    int i;
450
451    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622ModeIndex\n"));
452
453    if (pBIOSInfo->TVEncoder == VIA_VT1622)
454        Table = VT1622Table;
455    else if (pBIOSInfo->TVEncoder == VIA_VT1625)
456        Table = VT1625Table;
457    else
458        Table = VT1623Table;
459
460    for (i = 0; Table[i].Width; i++) {
461        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
462                   "width=%d:%d, height=%d:%d, std=%d:%d, name=%s:%s.\n",
463                   Table[i].Width, mode->CrtcHDisplay,
464                   Table[i].Height, mode->CrtcVDisplay,
465                   Table[i].Standard, pBIOSInfo->TVType,
466                   Table[i].name, mode->name);
467
468        if ((Table[i].Width == mode->CrtcHDisplay) &&
469            (Table[i].Height == mode->CrtcVDisplay) &&
470            (Table[i].Standard == pBIOSInfo->TVType) &&
471            !strcmp(Table[i].name, mode->name))
472            return i;
473    }
474    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VT1622ModeIndex:"
475               " Mode \"%s\" not found in Table\n", mode->name);
476    return 0xFF;
477}
478
479static ModeStatus
480VT1622ModeValid(ScrnInfoPtr pScrn, DisplayModePtr mode)
481{
482    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
483
484    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622ModeValid\n"));
485
486    if ((mode->PrivSize != sizeof(struct VT162xModePrivate)) ||
487        ((mode->Private != (void *)&VT162xModePrivateNTSC) &&
488         (mode->Private != (void *)&VT162xModePrivatePAL))) {
489        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
490                   "Not a mode defined by the TV Encoder.\n");
491        return MODE_BAD;
492    }
493
494    if ((pBIOSInfo->TVType == TVTYPE_NTSC) &&
495        (mode->Private != (void *)&VT162xModePrivateNTSC)) {
496        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
497                   "TV standard is NTSC. This is a PAL mode.\n");
498        return MODE_BAD;
499    } else if ((pBIOSInfo->TVType == TVTYPE_PAL) &&
500               (mode->Private != (void *)&VT162xModePrivatePAL)) {
501        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
502                   "TV standard is PAL. This is a NTSC mode.\n");
503        return MODE_BAD;
504    }
505
506    if (VT1622ModeIndex(pScrn, mode) != 0xFF)
507        return MODE_OK;
508    return MODE_BAD;
509}
510
511static ModeStatus
512VT1625ModeValid(ScrnInfoPtr pScrn, DisplayModePtr mode)
513{
514    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
515
516    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1625ModeValid\n"));
517
518    if ((mode->PrivSize != sizeof(struct VT162xModePrivate)) ||
519        ((mode->Private != (void *)&VT162xModePrivateNTSC) &&
520         (mode->Private != (void *)&VT162xModePrivatePAL) &&
521         (mode->Private != (void *)&VT162xModePrivate480P) &&
522         (mode->Private != (void *)&VT162xModePrivate576P) &&
523         (mode->Private != (void *)&VT162xModePrivate720P) &&
524         (mode->Private != (void *)&VT162xModePrivate1080I))) {
525        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
526                   "Not a mode defined by the TV Encoder.\n");
527        return MODE_BAD;
528    }
529
530    if ((pBIOSInfo->TVType == TVTYPE_NTSC) &&
531        (mode->Private != (void *)&VT162xModePrivateNTSC)) {
532        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
533                   "TV standard is NTSC. This is an incompatible mode.\n");
534        return MODE_BAD;
535    } else if ((pBIOSInfo->TVType == TVTYPE_PAL) &&
536               (mode->Private != (void *)&VT162xModePrivatePAL)) {
537        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
538                   "TV standard is PAL. This is an incompatible mode.\n");
539        return MODE_BAD;
540    } else if ((pBIOSInfo->TVType == TVTYPE_480P) &&
541               (mode->Private != (void *)&VT162xModePrivate480P)) {
542        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
543                   "TV standard is 480P. This is an incompatible mode.\n");
544        return MODE_BAD;
545    } else if ((pBIOSInfo->TVType == TVTYPE_576P) &&
546               (mode->Private != (void *)&VT162xModePrivate576P)) {
547        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
548                   "TV standard is 576P. This is an incompatible mode.\n");
549        return MODE_BAD;
550    } else if ((pBIOSInfo->TVType == TVTYPE_720P) &&
551               (mode->Private != (void *)&VT162xModePrivate720P)) {
552        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
553                   "TV standard is 720P. This is an incompatible mode.\n");
554        return MODE_BAD;
555    } else if ((pBIOSInfo->TVType == TVTYPE_1080I) &&
556               (mode->Private != (void *)&VT162xModePrivate1080I)) {
557        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
558                   "TV standard is 1080I. This is an incompatible mode.\n");
559        return MODE_BAD;
560    }
561
562    if (VT1622ModeIndex(pScrn, mode) != 0xFF)
563        return MODE_OK;
564    return MODE_BAD;
565}
566
567
568static void
569VT162xSetSubCarrier(I2CDevPtr pDev, CARD32 SubCarrier)
570{
571    xf86I2CWriteByte(pDev, 0x16, SubCarrier & 0xFF);
572    xf86I2CWriteByte(pDev, 0x17, (SubCarrier >> 8) & 0xFF);
573    xf86I2CWriteByte(pDev, 0x18, (SubCarrier >> 16) & 0xFF);
574    xf86I2CWriteByte(pDev, 0x19, (SubCarrier >> 24) & 0xFF);
575}
576
577static void
578VT1621ModeI2C(ScrnInfoPtr pScrn, DisplayModePtr mode)
579{
580    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
581    struct VT1621TableRec Table = VT1621Table[VT1621ModeIndex(pScrn, mode)];
582    CARD8 i;
583
584    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621ModeI2C\n"));
585
586    for (i = 0; i < 0x16; i++)
587        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV[i]);
588
589    VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.SubCarrier);
590
591    /* Skip reserved (1A) and version ID (1B). */
592    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1C, Table.TV[0x1C]);
593
594    /* Skip software reset (1D). */
595    for (i = 0x1E; i < 0x24; i++)
596        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV[i]);
597
598    /* Write some zeroes? */
599    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x24, 0x00);
600    for (i = 0; i < 0x08; i++)
601        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A + i, 0x00);
602
603    if (pBIOSInfo->TVOutput == TVOUTPUT_COMPOSITE)
604        for (i = 0; i < 0x10; i++)
605            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x52 + i, Table.TVC[i]);
606    else
607        for (i = 0; i < 0x10; i++)
608            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x52 + i, Table.TVS[i]);
609
610    /* Turn on all Composite and S-Video output. */
611    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
612
613    if (pBIOSInfo->TVDotCrawl) {
614        if (Table.DotCrawlSubCarrier) {
615            xf86I2CReadByte(pBIOSInfo->TVI2CDev, 0x11, &i);
616            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x11, i | 0x08);
617
618            VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.DotCrawlSubCarrier);
619        } else
620            xf86DrvMsg(pScrn->scrnIndex, X_INFO, "This mode does not currently "
621                       "support DotCrawl suppression.\n");
622    }
623}
624
625static void
626VT1621ModeCrtc(xf86CrtcPtr crtc, DisplayModePtr mode)
627{
628	ScrnInfoPtr pScrn = crtc->scrn;
629	vgaHWPtr hwp = VGAHWPTR(pScrn);
630	VIAPtr pVia = VIAPTR(pScrn);
631	VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
632	struct VT1621TableRec Table = VT1621Table[VT1621ModeIndex(pScrn, mode)];
633
634    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621ModeCrtc\n"));
635
636    if (pVia->IsSecondary) {
637        hwp->writeCrtc(hwp, 0x6A, 0x80);
638        hwp->writeCrtc(hwp, 0x6B, 0x20);
639        hwp->writeCrtc(hwp, 0x6C, 0x80);
640
641        /* Disable LCD Scaling */
642        if (!pVia->SAMM || pVia->FirstInit)
643            hwp->writeCrtc(hwp, 0x79, 0x00);
644
645    } else {
646        hwp->writeCrtc(hwp, 0x6A, 0x00);
647        hwp->writeCrtc(hwp, 0x6B, 0x80);
648        hwp->writeCrtc(hwp, 0x6C, Table.PrimaryCR6C);
649    }
650    pBIOSInfo->ClockExternal = TRUE;
651    ViaCrtcMask(hwp, 0x6A, 0x40, 0x40);
652    ViaCrtcMask(hwp, 0x6C, 0x01, 0x01);
653}
654
655/*
656 * Also suited for VT1622A, VT1623, VT1625.
657 */
658static void
659VT1622ModeI2C(ScrnInfoPtr pScrn, DisplayModePtr mode)
660{
661    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
662    struct VT162XTableRec Table;
663    CARD8 save, i;
664
665    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622ModeI2C\n"));
666
667    if (pBIOSInfo->TVEncoder == VIA_VT1622)
668        Table = VT1622Table[VT1622ModeIndex(pScrn, mode)];
669    else if (pBIOSInfo->TVEncoder == VIA_VT1625)
670        Table = VT1625Table[VT1622ModeIndex(pScrn, mode)];
671    else        /* VT1622A/VT1623 */
672        Table = VT1623Table[VT1622ModeIndex(pScrn, mode)];
673
674    /* TV reset. */
675    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x00);
676    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x80);
677
678    for (i = 0; i < 0x16; i++)
679        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV1[i]);
680
681    VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.SubCarrier);
682
683    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1A, Table.TV1[0x1A]);
684
685    /* Skip version ID. */
686    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1C, Table.TV1[0x1C]);
687
688    /* Skip software reset. */
689    for (i = 0x1E; i < 0x30; i++)
690        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV1[i]);
691
692    for (i = 0; i < 0x1B; i++)
693        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A + i, Table.TV2[i]);
694
695    /* Turn on all Composite and S-Video output. */
696    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
697
698    if (pBIOSInfo->TVDotCrawl) {
699        if (Table.DotCrawlSubCarrier) {
700            xf86I2CReadByte(pBIOSInfo->TVI2CDev, 0x11, &save);
701            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x11, save | 0x08);
702
703            VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.DotCrawlSubCarrier);
704        } else
705            xf86DrvMsg(pScrn->scrnIndex, X_INFO, "This mode does not currently "
706                       "support DotCrawl suppression.\n");
707    }
708
709    if (pBIOSInfo->TVOutput == TVOUTPUT_RGB) {
710        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x2A);
711        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x65, Table.RGB[0]);
712        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x66, Table.RGB[1]);
713        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x67, Table.RGB[2]);
714        if (Table.RGB[3])
715            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x27, Table.RGB[3]);
716        if (Table.RGB[4])
717            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x2B, Table.RGB[4]);
718        if (Table.RGB[5])
719            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x2C, Table.RGB[5]);
720        if (pBIOSInfo->TVEncoder == VIA_VT1625) {
721            if (pBIOSInfo->TVType < TVTYPE_480P) {
722                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x12);
723                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x23, 0x7E);
724                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A, 0x85);
725                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4B, 0x0A);
726                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4E, 0x00);
727            } else {
728                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x12);
729                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A, 0x85);
730                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4B, 0x0A);
731            }
732        }
733    } else if (pBIOSInfo->TVOutput == TVOUTPUT_YCBCR) {
734        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x03);
735        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x65, Table.YCbCr[0]);
736        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x66, Table.YCbCr[1]);
737        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x67, Table.YCbCr[2]);
738        if (pBIOSInfo->TVEncoder == VIA_VT1625) {
739            if (pBIOSInfo->TVType < TVTYPE_480P) {
740                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x23, 0x7E);
741                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4E, 0x00);
742            }
743        }
744    }
745
746    /* Configure flicker filter. */
747    xf86I2CReadByte(pBIOSInfo->TVI2CDev, 0x03, &save);
748    save &= 0xFC;
749    if (pBIOSInfo->TVDeflicker == 1)
750        save |= 0x01;
751    else if (pBIOSInfo->TVDeflicker == 2)
752        save |= 0x02;
753    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x03, save);
754}
755
756/*
757 * Also suited for VT1622A, VT1623, VT1625.
758 */
759static void
760VT1622ModeCrtc(xf86CrtcPtr crtc, DisplayModePtr mode)
761{
762	ScrnInfoPtr pScrn = crtc->scrn;
763	vgaHWPtr hwp = VGAHWPTR(pScrn);
764	VIAPtr pVia = VIAPTR(pScrn);
765	VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
766	struct VT162XTableRec Table;
767
768    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622ModeCrtc\n"));
769
770    if (pBIOSInfo->TVEncoder == VIA_VT1622)
771        Table = VT1622Table[VT1622ModeIndex(pScrn, mode)];
772    else if (pBIOSInfo->TVEncoder == VIA_VT1625)
773        Table = VT1625Table[VT1622ModeIndex(pScrn, mode)];
774    else        /* VT1622A/VT1623 */
775        Table = VT1623Table[VT1622ModeIndex(pScrn, mode)];
776
777    hwp->writeCrtc(hwp, 0x6A, 0x00);
778    hwp->writeCrtc(hwp, 0x6B, 0x00);
779    hwp->writeCrtc(hwp, 0x6C, 0x00);
780
781    if (pVia->IsSecondary) {
782        hwp->writeCrtc(hwp, 0x6C, Table.SecondaryCR6C);
783
784        ViaCrtcMask(hwp, 0x6A, 0x80, 0x80);
785        ViaCrtcMask(hwp, 0x6C, 0x80, 0x80);
786
787        /* CLE266Ax use 2x XCLK. */
788        if ((pVia->Chipset == VIA_CLE266) && CLE266_REV_IS_AX(pVia->ChipRev)) {
789            ViaCrtcMask(hwp, 0x6B, 0x20, 0x20);
790
791            /* Fix TV clock polarity for CLE266A2. */
792            if (pVia->ChipRev == 0x02)
793                ViaCrtcMask(hwp, 0x6C, 0x1C, 0x1C);
794        }
795
796        /* Disable LCD scaling. */
797        if (!pVia->SAMM || pVia->FirstInit)
798            hwp->writeCrtc(hwp, 0x79, 0x00);
799
800    } else {
801        if ((pVia->Chipset == VIA_CLE266) && CLE266_REV_IS_AX(pVia->ChipRev)) {
802            ViaCrtcMask(hwp, 0x6B, 0x80, 0x80);
803
804            /* Fix TV clock polarity for CLE266A2. */
805            if (pVia->ChipRev == 0x02)
806                hwp->writeCrtc(hwp, 0x6C, Table.PrimaryCR6C);
807        }
808    }
809    pBIOSInfo->ClockExternal = TRUE;
810    ViaCrtcMask(hwp, 0x6A, 0x40, 0x40);
811    ViaSetTVClockSource(crtc);
812}
813
814
815static void
816VT1621Power(ScrnInfoPtr pScrn, Bool On)
817{
818    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
819
820    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621Power\n"));
821
822    if (On)
823        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
824    else
825        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x03);
826}
827
828static void
829VT1622Power(ScrnInfoPtr pScrn, Bool On)
830{
831    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
832
833    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622Power\n"));
834
835    if (On)
836        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
837    else
838        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x0F);
839}
840
841static void
842VT1625Power(ScrnInfoPtr pScrn, Bool On)
843{
844    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
845
846    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1625Power\n"));
847
848    if (On)
849        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
850    else
851        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x3F);
852}
853
854
855void
856ViaVT162xInit(ScrnInfoPtr pScrn)
857{
858    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
859
860    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaVT162xInit\n"));
861
862    switch (pBIOSInfo->TVEncoder) {
863        case VIA_VT1621:
864            pBIOSInfo->TVSave = VT162xSave;
865            pBIOSInfo->TVRestore = VT162xRestore;
866            pBIOSInfo->TVDACSense = VT1621DACSense;
867            pBIOSInfo->TVModeValid = VT1621ModeValid;
868            pBIOSInfo->TVModeI2C = VT1621ModeI2C;
869            pBIOSInfo->TVModeCrtc = VT1621ModeCrtc;
870            pBIOSInfo->TVPower = VT1621Power;
871            pBIOSInfo->TVModes = VT1621Modes;
872            pBIOSInfo->TVNumModes = sizeof(VT1621Modes) / sizeof(DisplayModeRec);
873            pBIOSInfo->TVPrintRegs = VT162xPrintRegs;
874            pBIOSInfo->TVNumRegs = 0x68;
875            break;
876        case VIA_VT1622:
877            pBIOSInfo->TVSave = VT162xSave;
878            pBIOSInfo->TVRestore = VT162xRestore;
879            pBIOSInfo->TVDACSense = VT1622DACSense;
880            pBIOSInfo->TVModeValid = VT1622ModeValid;
881            pBIOSInfo->TVModeI2C = VT1622ModeI2C;
882            pBIOSInfo->TVModeCrtc = VT1622ModeCrtc;
883            pBIOSInfo->TVPower = VT1622Power;
884            pBIOSInfo->TVModes = VT1622Modes;
885            pBIOSInfo->TVNumModes = sizeof(VT1622Modes) / sizeof(DisplayModeRec);
886            pBIOSInfo->TVPrintRegs = VT162xPrintRegs;
887            pBIOSInfo->TVNumRegs = 0x68;
888            break;
889        case VIA_VT1623:
890            pBIOSInfo->TVSave = VT162xSave;
891            pBIOSInfo->TVRestore = VT162xRestore;
892            pBIOSInfo->TVDACSense = VT1622DACSense;
893            pBIOSInfo->TVModeValid = VT1622ModeValid;
894            pBIOSInfo->TVModeI2C = VT1622ModeI2C;
895            pBIOSInfo->TVModeCrtc = VT1622ModeCrtc;
896            pBIOSInfo->TVPower = VT1622Power;
897            pBIOSInfo->TVModes = VT1623Modes;
898            pBIOSInfo->TVNumModes = sizeof(VT1623Modes) / sizeof(DisplayModeRec);
899            pBIOSInfo->TVPrintRegs = VT162xPrintRegs;
900            pBIOSInfo->TVNumRegs = 0x6C;
901            break;
902        case VIA_VT1625:
903            pBIOSInfo->TVSave = VT162xSave;
904            pBIOSInfo->TVRestore = VT162xRestore;
905            pBIOSInfo->TVDACSense = VT1625DACSense;
906            pBIOSInfo->TVModeValid = VT1625ModeValid;
907            pBIOSInfo->TVModeI2C = VT1622ModeI2C;
908            pBIOSInfo->TVModeCrtc = VT1622ModeCrtc;
909            pBIOSInfo->TVPower = VT1625Power;
910            pBIOSInfo->TVModes = VT1625Modes;
911            pBIOSInfo->TVNumModes = sizeof(VT1625Modes) / sizeof(DisplayModeRec);
912            pBIOSInfo->TVPrintRegs = VT162xPrintRegs;
913            pBIOSInfo->TVNumRegs = 0x82;
914            break;
915        default:
916            break;
917    }
918}
919