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