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