via_vt162x.c revision 90b17f1b
17e6fb56fSmrg/*
27e6fb56fSmrg * Copyright 2004-2005 The Unichrome Project  [unichrome.sf.net]
37e6fb56fSmrg * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
47e6fb56fSmrg * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
57e6fb56fSmrg *
67e6fb56fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
77e6fb56fSmrg * copy of this software and associated documentation files (the "Software"),
87e6fb56fSmrg * to deal in the Software without restriction, including without limitation
97e6fb56fSmrg * the rights to use, copy, modify, merge, publish, distribute, sub license,
107e6fb56fSmrg * and/or sell copies of the Software, and to permit persons to whom the
117e6fb56fSmrg * Software is furnished to do so, subject to the following conditions:
127e6fb56fSmrg *
137e6fb56fSmrg * The above copyright notice and this permission notice (including the
147e6fb56fSmrg * next paragraph) shall be included in all copies or substantial portions
157e6fb56fSmrg * of the Software.
167e6fb56fSmrg *
177e6fb56fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187e6fb56fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197e6fb56fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
207e6fb56fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
217e6fb56fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
227e6fb56fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
237e6fb56fSmrg * DEALINGS IN THE SOFTWARE.
247e6fb56fSmrg */
257e6fb56fSmrg
267e6fb56fSmrg#ifdef HAVE_CONFIG_H
277e6fb56fSmrg#include "config.h"
287e6fb56fSmrg#endif
297e6fb56fSmrg
307e6fb56fSmrg#include "via_driver.h"
317e6fb56fSmrg#include "via_vt162x.h"
327e6fb56fSmrg
337e6fb56fSmrgstatic void
3490b17f1bSmrgViaSetTVClockSource(xf86CrtcPtr crtc)
357e6fb56fSmrg{
3690b17f1bSmrg	drmmode_crtc_private_ptr iga = crtc->driver_private;
3790b17f1bSmrg	ScrnInfoPtr pScrn = crtc->scrn;
3890b17f1bSmrg	VIAPtr pVia = VIAPTR(pScrn);
3990b17f1bSmrg	VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
4090b17f1bSmrg	vgaHWPtr hwp = VGAHWPTR(pScrn);
4190b17f1bSmrg
4290b17f1bSmrg	DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaSetTVClockSource\n"));
4390b17f1bSmrg
4490b17f1bSmrg    switch(pBIOSInfo->TVEncoder) {
4590b17f1bSmrg        case VIA_VT1625:
4690b17f1bSmrg            /* External TV: */
4790b17f1bSmrg            switch(pVia->Chipset) {
4890b17f1bSmrg                case VIA_CX700:
4990b17f1bSmrg                case VIA_VX800:
5090b17f1bSmrg                case VIA_VX855:
5190b17f1bSmrg					/* IGA1 */
5290b17f1bSmrg                    if (!iga->index) {
5390b17f1bSmrg                        if(pBIOSInfo->TVDIPort == VIA_DI_PORT_DVP1)
5490b17f1bSmrg                            ViaCrtcMask(hwp, 0x6C, 0xB0, 0xF0);
5590b17f1bSmrg                        else if(pBIOSInfo->TVDIPort == VIA_DI_PORT_DVP0)
5690b17f1bSmrg                            ViaCrtcMask(hwp, 0x6C, 0x90, 0xF0);
5790b17f1bSmrg                    } else {
5890b17f1bSmrg                        /* IGA2 */
5990b17f1bSmrg                        if(pBIOSInfo->TVDIPort == VIA_DI_PORT_DVP1)
6090b17f1bSmrg                            ViaCrtcMask(hwp, 0x6C, 0x0B, 0x0F);
6190b17f1bSmrg                        else if(pBIOSInfo->TVDIPort == VIA_DI_PORT_DVP0)
6290b17f1bSmrg                            ViaCrtcMask(hwp, 0x6C, 0x09, 0x0F);
6390b17f1bSmrg                    }
6490b17f1bSmrg                    break;
6590b17f1bSmrg                default:
6690b17f1bSmrg                    if (!iga->index)
6790b17f1bSmrg                        ViaCrtcMask(hwp, 0x6C, 0x21, 0x21);
6890b17f1bSmrg                    else
6990b17f1bSmrg                        ViaCrtcMask(hwp, 0x6C, 0xA1, 0xA1);
7090b17f1bSmrg                    break;
717e6fb56fSmrg            }
727e6fb56fSmrg            break;
737e6fb56fSmrg        default:
7490b17f1bSmrg			if (!iga->index)
7590b17f1bSmrg				ViaCrtcMask(hwp, 0x6C, 0x50, 0xF0);
7690b17f1bSmrg			else
7790b17f1bSmrg				ViaCrtcMask(hwp, 0x6C, 0x05, 0x0F);
787e6fb56fSmrg            break;
797e6fb56fSmrg    }
8090b17f1bSmrg
817e6fb56fSmrg}
827e6fb56fSmrg
837e6fb56fSmrgstatic void
847e6fb56fSmrgVT162xPrintRegs(ScrnInfoPtr pScrn)
857e6fb56fSmrg{
867e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
877e6fb56fSmrg    CARD8 i, buf;
887e6fb56fSmrg
897e6fb56fSmrg
907e6fb56fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Printing registers for %s\n",
917e6fb56fSmrg               pBIOSInfo->TVI2CDev->DevName);
927e6fb56fSmrg
937e6fb56fSmrg    for (i = 0; i < pBIOSInfo->TVNumRegs; i++) {
947e6fb56fSmrg        xf86I2CReadByte(pBIOSInfo->TVI2CDev, i, &buf);
957e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV%02X: 0x%02X\n", i, buf);
967e6fb56fSmrg    }
977e6fb56fSmrg
987e6fb56fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of TV registers.\n");
997e6fb56fSmrg}
1007e6fb56fSmrg
1017e6fb56fSmrg
1027e6fb56fSmrgI2CDevPtr
1037e6fb56fSmrgViaVT162xDetect(ScrnInfoPtr pScrn, I2CBusPtr pBus, CARD8 Address)
1047e6fb56fSmrg{
1057e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
1067e6fb56fSmrg    I2CDevPtr pDev = xf86CreateI2CDevRec();
1077e6fb56fSmrg    CARD8 buf;
1087e6fb56fSmrg
1097e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaVT162xDetect\n"));
1107e6fb56fSmrg
1117e6fb56fSmrg    pDev->DevName = "VT162x";
1127e6fb56fSmrg    pDev->SlaveAddr = Address;
1137e6fb56fSmrg    pDev->pI2CBus = pBus;
1147e6fb56fSmrg
1157e6fb56fSmrg    if (!xf86I2CDevInit(pDev)) {
1167e6fb56fSmrg        xf86DestroyI2CDevRec(pDev, TRUE);
1177e6fb56fSmrg        return NULL;
1187e6fb56fSmrg    }
1197e6fb56fSmrg
1207e6fb56fSmrg    if (!xf86I2CReadByte(pDev, 0x1B, &buf)) {
1217e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1227e6fb56fSmrg                   "Unable to read from %s Slave %d.\n",
1237e6fb56fSmrg                   pBus->BusName, Address);
1247e6fb56fSmrg        xf86DestroyI2CDevRec(pDev, TRUE);
1257e6fb56fSmrg        return NULL;
1267e6fb56fSmrg    }
1277e6fb56fSmrg
1287e6fb56fSmrg    switch (buf) {
1297e6fb56fSmrg        case 0x02:
1307e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1317e6fb56fSmrg                       "Detected VIA Technologies VT1621 TV Encoder\n");
1327e6fb56fSmrg            pBIOSInfo->TVEncoder = VIA_VT1621;
1337e6fb56fSmrg            pDev->DevName = "VT1621";
1347e6fb56fSmrg            break;
1357e6fb56fSmrg        case 0x03:
1367e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1377e6fb56fSmrg                       "Detected VIA Technologies VT1622 TV Encoder\n");
1387e6fb56fSmrg            pBIOSInfo->TVEncoder = VIA_VT1622;
1397e6fb56fSmrg            pDev->DevName = "VT1622";
1407e6fb56fSmrg            break;
1417e6fb56fSmrg        case 0x10:
1427e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1437e6fb56fSmrg                       "Detected VIA Technologies VT1622A/VT1623 TV Encoder\n");
1447e6fb56fSmrg            pBIOSInfo->TVEncoder = VIA_VT1623;
1457e6fb56fSmrg            pDev->DevName = "VT1623";
1467e6fb56fSmrg            break;
1477e6fb56fSmrg        case 0x50:
1487e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1497e6fb56fSmrg                       "Detected VIA Technologies VT1625 TV Encoder\n");
1507e6fb56fSmrg            pBIOSInfo->TVEncoder = VIA_VT1625;
1517e6fb56fSmrg            pDev->DevName = "VT1625";
1527e6fb56fSmrg            break;
1537e6fb56fSmrg        default:
1547e6fb56fSmrg            pBIOSInfo->TVEncoder = VIA_NONETV;
1557e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1567e6fb56fSmrg                       "Unknown TV Encoder found at %s %X.\n",
1577e6fb56fSmrg                       pBus->BusName, Address);
1587e6fb56fSmrg            xf86DestroyI2CDevRec(pDev, TRUE);
1597e6fb56fSmrg            pDev = NULL;
1607e6fb56fSmrg            break;
1617e6fb56fSmrg    }
1627e6fb56fSmrg
1637e6fb56fSmrg    return pDev;
1647e6fb56fSmrg}
1657e6fb56fSmrg
1667e6fb56fSmrg
1677e6fb56fSmrgstatic void
1687e6fb56fSmrgVT162xSave(ScrnInfoPtr pScrn)
1697e6fb56fSmrg{
1707e6fb56fSmrg    int i;
1717e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
1727e6fb56fSmrg
1737e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT162xSave\n"));
1747e6fb56fSmrg
1757e6fb56fSmrg    for (i = 0; i < pBIOSInfo->TVNumRegs; i++)
1767e6fb56fSmrg        xf86I2CReadByte(pBIOSInfo->TVI2CDev, i, &(pBIOSInfo->TVRegs[i]));
1777e6fb56fSmrg
1787e6fb56fSmrg}
1797e6fb56fSmrg
1807e6fb56fSmrgstatic void
1817e6fb56fSmrgVT162xRestore(ScrnInfoPtr pScrn)
1827e6fb56fSmrg{
1837e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
1847e6fb56fSmrg    int i;
1857e6fb56fSmrg
1867e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT162xRestore\n"));
1877e6fb56fSmrg
1887e6fb56fSmrg    for (i = 0; i < pBIOSInfo->TVNumRegs; i++)
1897e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, pBIOSInfo->TVRegs[i]);
1907e6fb56fSmrg}
1917e6fb56fSmrg
1927e6fb56fSmrg
1937e6fb56fSmrg/*
1947e6fb56fSmrg * For VT1621 the same as for VT1622/VT1622A/VT1623, but result is different.
1957e6fb56fSmrg * Still needs testing on VT1621, of course.
1967e6fb56fSmrg */
1977e6fb56fSmrgstatic CARD8
1987e6fb56fSmrgVT162xDACSenseI2C(I2CDevPtr pDev)
1997e6fb56fSmrg{
2007e6fb56fSmrg    CARD8 save, sense;
2017e6fb56fSmrg
2027e6fb56fSmrg    xf86I2CReadByte(pDev, 0x0E, &save);
2037e6fb56fSmrg    xf86I2CWriteByte(pDev, 0x0E, 0x00);
2047e6fb56fSmrg    xf86I2CWriteByte(pDev, 0x0E, 0x80);
2057e6fb56fSmrg    xf86I2CWriteByte(pDev, 0x0E, 0x00);
2067e6fb56fSmrg    xf86I2CReadByte(pDev, 0x0F, &sense);
2077e6fb56fSmrg    xf86I2CWriteByte(pDev, 0x0E, save);
2087e6fb56fSmrg
2097e6fb56fSmrg    return (sense & 0x0F);
2107e6fb56fSmrg}
2117e6fb56fSmrg
2127e6fb56fSmrg/*
21390b17f1bSmrg * VT1625/VT1625S sense connected TV outputs.
21490b17f1bSmrg *
21590b17f1bSmrg * The lower six bits of the return byte stand for each of the six DACs:
21690b17f1bSmrg *  - bit 0: DACf (Cb)
21790b17f1bSmrg *  - bit 1: DACe (Cr)
21890b17f1bSmrg *  - bit 2: DACd (Y)
21990b17f1bSmrg *  - bit 3: DACc (Composite)
22090b17f1bSmrg *  - bit 4: DACb (S-Video C)
22190b17f1bSmrg *  - bit 5: DACa (S-Video Y)
22290b17f1bSmrg *
22390b17f1bSmrg * If a bit is 0 it means a cable is connected. Note the VT1625S only has
22490b17f1bSmrg * four DACs, corresponding to bit 0-3 above.
2257e6fb56fSmrg */
2267e6fb56fSmrgstatic CARD8
2277e6fb56fSmrgVT1625DACSenseI2C(I2CDevPtr pDev)
2287e6fb56fSmrg{
22990b17f1bSmrg    CARD8 power, status, overflow, dacPresent;
23090b17f1bSmrg
23190b17f1bSmrg    xf86I2CReadByte(pDev, 0x0E, &power);     // save power state
23290b17f1bSmrg
23390b17f1bSmrg    // VT1625S will always report 0 for bits 4 and 5 of the status register as
23490b17f1bSmrg    // it only has four DACs instead of six. This will result in a false
23590b17f1bSmrg    // positive for the S-Video cable. It will also do this on the power
23690b17f1bSmrg    // register, which is abused to check which DACs are actually present.
23790b17f1bSmrg    xf86I2CWriteByte(pDev, 0x0E, 0xFF);
23890b17f1bSmrg    xf86I2CReadByte(pDev, 0x0E, &dacPresent);
23990b17f1bSmrg
24090b17f1bSmrg    xf86I2CWriteByte(pDev, 0x0E, 0x00);      // power on DACs/circuits
24190b17f1bSmrg    xf86I2CReadByte(pDev, 0x1C, &overflow);  // save overflow reg
24290b17f1bSmrg                                             // (DAC sense bit should be off)
24390b17f1bSmrg    xf86I2CWriteByte(pDev, 0x1C, 0x80);      // enable DAC sense bit
24490b17f1bSmrg    xf86I2CWriteByte(pDev, 0x1C, overflow);  // disable DAC sense bit
24590b17f1bSmrg    xf86I2CReadByte(pDev, 0x0F, &status);    // read connection status
24690b17f1bSmrg    xf86I2CWriteByte(pDev, 0x0E, power);     // restore power state
24790b17f1bSmrg    status |= ~dacPresent;
24890b17f1bSmrg
24990b17f1bSmrg    return (status & 0x3F);
2507e6fb56fSmrg}
2517e6fb56fSmrg
2527e6fb56fSmrg/*
2537e6fb56fSmrg * VT1621 only knows composite and s-video.
2547e6fb56fSmrg */
2557e6fb56fSmrgstatic Bool
2567e6fb56fSmrgVT1621DACSense(ScrnInfoPtr pScrn)
2577e6fb56fSmrg{
2587e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
2597e6fb56fSmrg    CARD8 sense;
2607e6fb56fSmrg
2617e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621DACSense\n"));
2627e6fb56fSmrg
2637e6fb56fSmrg    sense = VT162xDACSenseI2C(pBIOSInfo->TVI2CDev);
2647e6fb56fSmrg    switch (sense) {
2657e6fb56fSmrg        case 0x00:
2667e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_SC;
2677e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2687e6fb56fSmrg                       "VT1621: S-Video & Composite connected.\n");
2697e6fb56fSmrg            return TRUE;
2707e6fb56fSmrg        case 0x01:
2717e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_COMPOSITE;
2727e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2737e6fb56fSmrg                       "VT1621: Composite connected.\n");
2747e6fb56fSmrg            return TRUE;
2757e6fb56fSmrg        case 0x02:
2767e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_SVIDEO;
2777e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2787e6fb56fSmrg                       "VT1621: S-Video connected.\n");
2797e6fb56fSmrg            return TRUE;
2807e6fb56fSmrg        case 0x03:
2817e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
2827e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2837e6fb56fSmrg                       "VT1621: Nothing connected.\n");
2847e6fb56fSmrg            return FALSE;
2857e6fb56fSmrg        default:
2867e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
2877e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2887e6fb56fSmrg                       "VT1621: Unknown cable combination: 0x0%2X.\n", sense);
2897e6fb56fSmrg            return FALSE;
2907e6fb56fSmrg    }
2917e6fb56fSmrg}
2927e6fb56fSmrg
2937e6fb56fSmrg/*
2947e6fb56fSmrg * VT1622, VT1622A and VT1623 know composite, s-video, RGB and YCBCR.
2957e6fb56fSmrg */
2967e6fb56fSmrgstatic Bool
2977e6fb56fSmrgVT1622DACSense(ScrnInfoPtr pScrn)
2987e6fb56fSmrg{
2997e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
3007e6fb56fSmrg    CARD8 sense;
3017e6fb56fSmrg
3027e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622DACSense\n"));
3037e6fb56fSmrg
3047e6fb56fSmrg    sense = VT162xDACSenseI2C(pBIOSInfo->TVI2CDev);
3057e6fb56fSmrg    switch (sense) {
3067e6fb56fSmrg        case 0x00:  /* DAC A,B,C,D */
3077e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_RGB;
3087e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3097e6fb56fSmrg                       "VT162x: RGB connected.\n");
3107e6fb56fSmrg            return TRUE;
3117e6fb56fSmrg        case 0x01:  /* DAC A,B,C */
3127e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_SC;
3137e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3147e6fb56fSmrg                       "VT162x: S-Video & Composite connected.\n");
3157e6fb56fSmrg            return TRUE;
3167e6fb56fSmrg        case 0x07:  /* DAC A */
3177e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_COMPOSITE;
3187e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3197e6fb56fSmrg                       "VT162x: Composite connected.\n");
3207e6fb56fSmrg            return TRUE;
3217e6fb56fSmrg        case 0x08:  /* DAC B,C,D */
3227e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_YCBCR;
3237e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3247e6fb56fSmrg                       "VT162x: YcBcR connected.\n");
3257e6fb56fSmrg            return TRUE;
3267e6fb56fSmrg        case 0x09:  /* DAC B,C */
3277e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_SVIDEO;
3287e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3297e6fb56fSmrg                       "VT162x: S-Video connected.\n");
3307e6fb56fSmrg            return TRUE;
3317e6fb56fSmrg        case 0x0F:
3327e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
3337e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3347e6fb56fSmrg                       "VT162x: Nothing connected.\n");
3357e6fb56fSmrg            return FALSE;
3367e6fb56fSmrg        default:
3377e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
3387e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3397e6fb56fSmrg                       "VT162x: Unknown cable combination: 0x0%2X.\n", sense);
3407e6fb56fSmrg            return FALSE;
3417e6fb56fSmrg    }
3427e6fb56fSmrg}
3437e6fb56fSmrg
3447e6fb56fSmrg/*
3457e6fb56fSmrg * VT1625 knows composite, s-video, RGB and YCBCR.
3467e6fb56fSmrg */
3477e6fb56fSmrgstatic Bool
3487e6fb56fSmrgVT1625DACSense(ScrnInfoPtr pScrn)
3497e6fb56fSmrg{
3507e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
3517e6fb56fSmrg    CARD8 sense;
3527e6fb56fSmrg
3537e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1625DACSense\n"));
3547e6fb56fSmrg
3557e6fb56fSmrg    sense = VT1625DACSenseI2C(pBIOSInfo->TVI2CDev);
3567e6fb56fSmrg    switch (sense) {
3577e6fb56fSmrg        case 0x00:  /* DAC A,B,C,D,E,F */
3587e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_RGB;
3597e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3607e6fb56fSmrg                       "VT1625: RGB connected.\n");
3617e6fb56fSmrg            return TRUE;
3627e6fb56fSmrg        case 0x07:  /* DAC A,B,C */
3637e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_SC;
3647e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3657e6fb56fSmrg                       "VT1625: S-Video & Composite connected.\n");
3667e6fb56fSmrg            return TRUE;
3677e6fb56fSmrg        case 0x37:  /* DAC C */
3687e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_COMPOSITE;
3697e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3707e6fb56fSmrg                       "VT1625: Composite connected.\n");
3717e6fb56fSmrg            return TRUE;
3727e6fb56fSmrg        case 0x38:  /* DAC D,E,F */
3737e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_YCBCR;
3747e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3757e6fb56fSmrg                       "VT1625: YCbCr connected.\n");
3767e6fb56fSmrg            return TRUE;
3777e6fb56fSmrg        case 0x0F:  /* DAC A,B */
3787e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_SVIDEO;
3797e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3807e6fb56fSmrg                       "VT1625: S-Video connected.\n");
3817e6fb56fSmrg            return TRUE;
3827e6fb56fSmrg        case 0x3F:
3837e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
3847e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3857e6fb56fSmrg                       "VT1625: Nothing connected.\n");
3867e6fb56fSmrg            return FALSE;
3877e6fb56fSmrg        default:
3887e6fb56fSmrg            pBIOSInfo->TVOutput = TVOUTPUT_NONE;
3897e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3907e6fb56fSmrg                       "VT1625: Unknown cable combination: 0x0%2X.\n", sense);
3917e6fb56fSmrg            return FALSE;
3927e6fb56fSmrg    }
3937e6fb56fSmrg}
3947e6fb56fSmrg
3957e6fb56fSmrgstatic CARD8
3967e6fb56fSmrgVT1621ModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
3977e6fb56fSmrg{
3987e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
3997e6fb56fSmrg    int i;
4007e6fb56fSmrg
4017e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621ModeIndex\n"));
4027e6fb56fSmrg
4037e6fb56fSmrg    for (i = 0; VT1621Table[i].Width; i++) {
4047e6fb56fSmrg        if ((VT1621Table[i].Width == mode->CrtcHDisplay) &&
4057e6fb56fSmrg            (VT1621Table[i].Height == mode->CrtcVDisplay) &&
4067e6fb56fSmrg            (VT1621Table[i].Standard == pBIOSInfo->TVType) &&
4077e6fb56fSmrg            !(strcmp(VT1621Table[i].name, mode->name)))
4087e6fb56fSmrg            return i;
4097e6fb56fSmrg    }
4107e6fb56fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VT1621ModeIndex:"
4117e6fb56fSmrg               " Mode \"%s\" not found in Table\n", mode->name);
4127e6fb56fSmrg    return 0xFF;
4137e6fb56fSmrg}
4147e6fb56fSmrg
4157e6fb56fSmrgstatic ModeStatus
4167e6fb56fSmrgVT1621ModeValid(ScrnInfoPtr pScrn, DisplayModePtr mode)
4177e6fb56fSmrg{
4187e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
4197e6fb56fSmrg
4207e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621ModeValid\n"));
4217e6fb56fSmrg
4227e6fb56fSmrg    if ((mode->PrivSize != sizeof(struct VT162xModePrivate)) ||
4237e6fb56fSmrg        ((mode->Private != (void *)&VT162xModePrivateNTSC) &&
4247e6fb56fSmrg         (mode->Private != (void *)&VT162xModePrivatePAL))) {
4257e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4267e6fb56fSmrg                   "Not a mode defined by the TV Encoder.\n");
4277e6fb56fSmrg        return MODE_BAD;
4287e6fb56fSmrg    }
4297e6fb56fSmrg
4307e6fb56fSmrg    if ((pBIOSInfo->TVType == TVTYPE_NTSC) &&
4317e6fb56fSmrg        (mode->Private != (void *)&VT162xModePrivateNTSC)) {
4327e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4337e6fb56fSmrg                   "TV standard is NTSC. This is a PAL mode.\n");
4347e6fb56fSmrg        return MODE_BAD;
4357e6fb56fSmrg    } else if ((pBIOSInfo->TVType == TVTYPE_PAL) &&
4367e6fb56fSmrg               (mode->Private != (void *)&VT162xModePrivatePAL)) {
4377e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4387e6fb56fSmrg                   "TV standard is PAL. This is a NTSC mode.\n");
4397e6fb56fSmrg        return MODE_BAD;
4407e6fb56fSmrg    }
4417e6fb56fSmrg
4427e6fb56fSmrg    if (VT1621ModeIndex(pScrn, mode) != 0xFF)
4437e6fb56fSmrg        return MODE_OK;
4447e6fb56fSmrg    return MODE_BAD;
4457e6fb56fSmrg}
4467e6fb56fSmrg
4477e6fb56fSmrgstatic CARD8
4487e6fb56fSmrgVT1622ModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
4497e6fb56fSmrg{
4507e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
4517e6fb56fSmrg    struct VT162XTableRec *Table;
4527e6fb56fSmrg    int i;
4537e6fb56fSmrg
4547e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622ModeIndex\n"));
4557e6fb56fSmrg
4567e6fb56fSmrg    if (pBIOSInfo->TVEncoder == VIA_VT1622)
4577e6fb56fSmrg        Table = VT1622Table;
4587e6fb56fSmrg    else if (pBIOSInfo->TVEncoder == VIA_VT1625)
4597e6fb56fSmrg        Table = VT1625Table;
4607e6fb56fSmrg    else
4617e6fb56fSmrg        Table = VT1623Table;
4627e6fb56fSmrg
4637e6fb56fSmrg    for (i = 0; Table[i].Width; i++) {
4647e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4657e6fb56fSmrg                   "width=%d:%d, height=%d:%d, std=%d:%d, name=%s:%s.\n",
4667e6fb56fSmrg                   Table[i].Width, mode->CrtcHDisplay,
4677e6fb56fSmrg                   Table[i].Height, mode->CrtcVDisplay,
4687e6fb56fSmrg                   Table[i].Standard, pBIOSInfo->TVType,
4697e6fb56fSmrg                   Table[i].name, mode->name);
4707e6fb56fSmrg
4717e6fb56fSmrg        if ((Table[i].Width == mode->CrtcHDisplay) &&
4727e6fb56fSmrg            (Table[i].Height == mode->CrtcVDisplay) &&
4737e6fb56fSmrg            (Table[i].Standard == pBIOSInfo->TVType) &&
4747e6fb56fSmrg            !strcmp(Table[i].name, mode->name))
4757e6fb56fSmrg            return i;
4767e6fb56fSmrg    }
4777e6fb56fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VT1622ModeIndex:"
4787e6fb56fSmrg               " Mode \"%s\" not found in Table\n", mode->name);
4797e6fb56fSmrg    return 0xFF;
4807e6fb56fSmrg}
4817e6fb56fSmrg
4827e6fb56fSmrgstatic ModeStatus
4837e6fb56fSmrgVT1622ModeValid(ScrnInfoPtr pScrn, DisplayModePtr mode)
4847e6fb56fSmrg{
4857e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
4867e6fb56fSmrg
4877e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622ModeValid\n"));
4887e6fb56fSmrg
4897e6fb56fSmrg    if ((mode->PrivSize != sizeof(struct VT162xModePrivate)) ||
4907e6fb56fSmrg        ((mode->Private != (void *)&VT162xModePrivateNTSC) &&
4917e6fb56fSmrg         (mode->Private != (void *)&VT162xModePrivatePAL))) {
4927e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4937e6fb56fSmrg                   "Not a mode defined by the TV Encoder.\n");
4947e6fb56fSmrg        return MODE_BAD;
4957e6fb56fSmrg    }
4967e6fb56fSmrg
4977e6fb56fSmrg    if ((pBIOSInfo->TVType == TVTYPE_NTSC) &&
4987e6fb56fSmrg        (mode->Private != (void *)&VT162xModePrivateNTSC)) {
4997e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5007e6fb56fSmrg                   "TV standard is NTSC. This is a PAL mode.\n");
5017e6fb56fSmrg        return MODE_BAD;
5027e6fb56fSmrg    } else if ((pBIOSInfo->TVType == TVTYPE_PAL) &&
5037e6fb56fSmrg               (mode->Private != (void *)&VT162xModePrivatePAL)) {
5047e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5057e6fb56fSmrg                   "TV standard is PAL. This is a NTSC mode.\n");
5067e6fb56fSmrg        return MODE_BAD;
5077e6fb56fSmrg    }
5087e6fb56fSmrg
5097e6fb56fSmrg    if (VT1622ModeIndex(pScrn, mode) != 0xFF)
5107e6fb56fSmrg        return MODE_OK;
5117e6fb56fSmrg    return MODE_BAD;
5127e6fb56fSmrg}
5137e6fb56fSmrg
5147e6fb56fSmrgstatic ModeStatus
5157e6fb56fSmrgVT1625ModeValid(ScrnInfoPtr pScrn, DisplayModePtr mode)
5167e6fb56fSmrg{
5177e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
5187e6fb56fSmrg
5197e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1625ModeValid\n"));
5207e6fb56fSmrg
5217e6fb56fSmrg    if ((mode->PrivSize != sizeof(struct VT162xModePrivate)) ||
5227e6fb56fSmrg        ((mode->Private != (void *)&VT162xModePrivateNTSC) &&
5237e6fb56fSmrg         (mode->Private != (void *)&VT162xModePrivatePAL) &&
5247e6fb56fSmrg         (mode->Private != (void *)&VT162xModePrivate480P) &&
5257e6fb56fSmrg         (mode->Private != (void *)&VT162xModePrivate576P) &&
5267e6fb56fSmrg         (mode->Private != (void *)&VT162xModePrivate720P) &&
5277e6fb56fSmrg         (mode->Private != (void *)&VT162xModePrivate1080I))) {
5287e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5297e6fb56fSmrg                   "Not a mode defined by the TV Encoder.\n");
5307e6fb56fSmrg        return MODE_BAD;
5317e6fb56fSmrg    }
5327e6fb56fSmrg
5337e6fb56fSmrg    if ((pBIOSInfo->TVType == TVTYPE_NTSC) &&
5347e6fb56fSmrg        (mode->Private != (void *)&VT162xModePrivateNTSC)) {
5357e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5367e6fb56fSmrg                   "TV standard is NTSC. This is an incompatible mode.\n");
5377e6fb56fSmrg        return MODE_BAD;
5387e6fb56fSmrg    } else if ((pBIOSInfo->TVType == TVTYPE_PAL) &&
5397e6fb56fSmrg               (mode->Private != (void *)&VT162xModePrivatePAL)) {
5407e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5417e6fb56fSmrg                   "TV standard is PAL. This is an incompatible mode.\n");
5427e6fb56fSmrg        return MODE_BAD;
5437e6fb56fSmrg    } else if ((pBIOSInfo->TVType == TVTYPE_480P) &&
5447e6fb56fSmrg               (mode->Private != (void *)&VT162xModePrivate480P)) {
5457e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5467e6fb56fSmrg                   "TV standard is 480P. This is an incompatible mode.\n");
5477e6fb56fSmrg        return MODE_BAD;
5487e6fb56fSmrg    } else if ((pBIOSInfo->TVType == TVTYPE_576P) &&
5497e6fb56fSmrg               (mode->Private != (void *)&VT162xModePrivate576P)) {
5507e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5517e6fb56fSmrg                   "TV standard is 576P. This is an incompatible mode.\n");
5527e6fb56fSmrg        return MODE_BAD;
5537e6fb56fSmrg    } else if ((pBIOSInfo->TVType == TVTYPE_720P) &&
5547e6fb56fSmrg               (mode->Private != (void *)&VT162xModePrivate720P)) {
5557e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5567e6fb56fSmrg                   "TV standard is 720P. This is an incompatible mode.\n");
5577e6fb56fSmrg        return MODE_BAD;
5587e6fb56fSmrg    } else if ((pBIOSInfo->TVType == TVTYPE_1080I) &&
5597e6fb56fSmrg               (mode->Private != (void *)&VT162xModePrivate1080I)) {
5607e6fb56fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5617e6fb56fSmrg                   "TV standard is 1080I. This is an incompatible mode.\n");
5627e6fb56fSmrg        return MODE_BAD;
5637e6fb56fSmrg    }
5647e6fb56fSmrg
5657e6fb56fSmrg    if (VT1622ModeIndex(pScrn, mode) != 0xFF)
5667e6fb56fSmrg        return MODE_OK;
5677e6fb56fSmrg    return MODE_BAD;
5687e6fb56fSmrg}
5697e6fb56fSmrg
5707e6fb56fSmrg
5717e6fb56fSmrgstatic void
5727e6fb56fSmrgVT162xSetSubCarrier(I2CDevPtr pDev, CARD32 SubCarrier)
5737e6fb56fSmrg{
5747e6fb56fSmrg    xf86I2CWriteByte(pDev, 0x16, SubCarrier & 0xFF);
5757e6fb56fSmrg    xf86I2CWriteByte(pDev, 0x17, (SubCarrier >> 8) & 0xFF);
5767e6fb56fSmrg    xf86I2CWriteByte(pDev, 0x18, (SubCarrier >> 16) & 0xFF);
5777e6fb56fSmrg    xf86I2CWriteByte(pDev, 0x19, (SubCarrier >> 24) & 0xFF);
5787e6fb56fSmrg}
5797e6fb56fSmrg
5807e6fb56fSmrgstatic void
5817e6fb56fSmrgVT1621ModeI2C(ScrnInfoPtr pScrn, DisplayModePtr mode)
5827e6fb56fSmrg{
5837e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
5847e6fb56fSmrg    struct VT1621TableRec Table = VT1621Table[VT1621ModeIndex(pScrn, mode)];
5857e6fb56fSmrg    CARD8 i;
5867e6fb56fSmrg
5877e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621ModeI2C\n"));
5887e6fb56fSmrg
5897e6fb56fSmrg    for (i = 0; i < 0x16; i++)
5907e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV[i]);
5917e6fb56fSmrg
5927e6fb56fSmrg    VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.SubCarrier);
5937e6fb56fSmrg
5947e6fb56fSmrg    /* Skip reserved (1A) and version ID (1B). */
5957e6fb56fSmrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1C, Table.TV[0x1C]);
5967e6fb56fSmrg
5977e6fb56fSmrg    /* Skip software reset (1D). */
5987e6fb56fSmrg    for (i = 0x1E; i < 0x24; i++)
5997e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV[i]);
6007e6fb56fSmrg
6017e6fb56fSmrg    /* Write some zeroes? */
6027e6fb56fSmrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x24, 0x00);
6037e6fb56fSmrg    for (i = 0; i < 0x08; i++)
6047e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A + i, 0x00);
6057e6fb56fSmrg
6067e6fb56fSmrg    if (pBIOSInfo->TVOutput == TVOUTPUT_COMPOSITE)
6077e6fb56fSmrg        for (i = 0; i < 0x10; i++)
6087e6fb56fSmrg            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x52 + i, Table.TVC[i]);
6097e6fb56fSmrg    else
6107e6fb56fSmrg        for (i = 0; i < 0x10; i++)
6117e6fb56fSmrg            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x52 + i, Table.TVS[i]);
6127e6fb56fSmrg
6137e6fb56fSmrg    /* Turn on all Composite and S-Video output. */
6147e6fb56fSmrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
6157e6fb56fSmrg
6167e6fb56fSmrg    if (pBIOSInfo->TVDotCrawl) {
6177e6fb56fSmrg        if (Table.DotCrawlSubCarrier) {
6187e6fb56fSmrg            xf86I2CReadByte(pBIOSInfo->TVI2CDev, 0x11, &i);
6197e6fb56fSmrg            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x11, i | 0x08);
6207e6fb56fSmrg
6217e6fb56fSmrg            VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.DotCrawlSubCarrier);
6227e6fb56fSmrg        } else
6237e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO, "This mode does not currently "
6247e6fb56fSmrg                       "support DotCrawl suppression.\n");
6257e6fb56fSmrg    }
6267e6fb56fSmrg}
6277e6fb56fSmrg
6287e6fb56fSmrgstatic void
62990b17f1bSmrgVT1621ModeCrtc(xf86CrtcPtr crtc, DisplayModePtr mode)
6307e6fb56fSmrg{
63190b17f1bSmrg	ScrnInfoPtr pScrn = crtc->scrn;
63290b17f1bSmrg	vgaHWPtr hwp = VGAHWPTR(pScrn);
63390b17f1bSmrg	VIAPtr pVia = VIAPTR(pScrn);
63490b17f1bSmrg	VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
63590b17f1bSmrg	struct VT1621TableRec Table = VT1621Table[VT1621ModeIndex(pScrn, mode)];
6367e6fb56fSmrg
6377e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621ModeCrtc\n"));
6387e6fb56fSmrg
6397e6fb56fSmrg    if (pVia->IsSecondary) {
6407e6fb56fSmrg        hwp->writeCrtc(hwp, 0x6A, 0x80);
6417e6fb56fSmrg        hwp->writeCrtc(hwp, 0x6B, 0x20);
6427e6fb56fSmrg        hwp->writeCrtc(hwp, 0x6C, 0x80);
6437e6fb56fSmrg
6447e6fb56fSmrg        /* Disable LCD Scaling */
6457e6fb56fSmrg        if (!pVia->SAMM || pVia->FirstInit)
6467e6fb56fSmrg            hwp->writeCrtc(hwp, 0x79, 0x00);
6477e6fb56fSmrg
6487e6fb56fSmrg    } else {
6497e6fb56fSmrg        hwp->writeCrtc(hwp, 0x6A, 0x00);
6507e6fb56fSmrg        hwp->writeCrtc(hwp, 0x6B, 0x80);
6517e6fb56fSmrg        hwp->writeCrtc(hwp, 0x6C, Table.PrimaryCR6C);
6527e6fb56fSmrg    }
6537e6fb56fSmrg    pBIOSInfo->ClockExternal = TRUE;
6547e6fb56fSmrg    ViaCrtcMask(hwp, 0x6A, 0x40, 0x40);
6557e6fb56fSmrg    ViaCrtcMask(hwp, 0x6C, 0x01, 0x01);
6567e6fb56fSmrg}
6577e6fb56fSmrg
6587e6fb56fSmrg/*
6597e6fb56fSmrg * Also suited for VT1622A, VT1623, VT1625.
6607e6fb56fSmrg */
6617e6fb56fSmrgstatic void
6627e6fb56fSmrgVT1622ModeI2C(ScrnInfoPtr pScrn, DisplayModePtr mode)
6637e6fb56fSmrg{
6647e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
6657e6fb56fSmrg    struct VT162XTableRec Table;
6667e6fb56fSmrg    CARD8 save, i;
6677e6fb56fSmrg
6687e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622ModeI2C\n"));
6697e6fb56fSmrg
6707e6fb56fSmrg    if (pBIOSInfo->TVEncoder == VIA_VT1622)
6717e6fb56fSmrg        Table = VT1622Table[VT1622ModeIndex(pScrn, mode)];
6727e6fb56fSmrg    else if (pBIOSInfo->TVEncoder == VIA_VT1625)
6737e6fb56fSmrg        Table = VT1625Table[VT1622ModeIndex(pScrn, mode)];
6747e6fb56fSmrg    else        /* VT1622A/VT1623 */
6757e6fb56fSmrg        Table = VT1623Table[VT1622ModeIndex(pScrn, mode)];
6767e6fb56fSmrg
6777e6fb56fSmrg    /* TV reset. */
6787e6fb56fSmrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x00);
6797e6fb56fSmrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x80);
6807e6fb56fSmrg
6817e6fb56fSmrg    for (i = 0; i < 0x16; i++)
6827e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV1[i]);
6837e6fb56fSmrg
6847e6fb56fSmrg    VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.SubCarrier);
6857e6fb56fSmrg
6867e6fb56fSmrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1A, Table.TV1[0x1A]);
6877e6fb56fSmrg
6887e6fb56fSmrg    /* Skip version ID. */
6897e6fb56fSmrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1C, Table.TV1[0x1C]);
6907e6fb56fSmrg
6917e6fb56fSmrg    /* Skip software reset. */
6927e6fb56fSmrg    for (i = 0x1E; i < 0x30; i++)
6937e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV1[i]);
6947e6fb56fSmrg
6957e6fb56fSmrg    for (i = 0; i < 0x1B; i++)
6967e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A + i, Table.TV2[i]);
6977e6fb56fSmrg
6987e6fb56fSmrg    /* Turn on all Composite and S-Video output. */
6997e6fb56fSmrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
7007e6fb56fSmrg
7017e6fb56fSmrg    if (pBIOSInfo->TVDotCrawl) {
7027e6fb56fSmrg        if (Table.DotCrawlSubCarrier) {
7037e6fb56fSmrg            xf86I2CReadByte(pBIOSInfo->TVI2CDev, 0x11, &save);
7047e6fb56fSmrg            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x11, save | 0x08);
7057e6fb56fSmrg
7067e6fb56fSmrg            VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.DotCrawlSubCarrier);
7077e6fb56fSmrg        } else
7087e6fb56fSmrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO, "This mode does not currently "
7097e6fb56fSmrg                       "support DotCrawl suppression.\n");
7107e6fb56fSmrg    }
7117e6fb56fSmrg
7127e6fb56fSmrg    if (pBIOSInfo->TVOutput == TVOUTPUT_RGB) {
7137e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x2A);
7147e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x65, Table.RGB[0]);
7157e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x66, Table.RGB[1]);
7167e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x67, Table.RGB[2]);
7177e6fb56fSmrg        if (Table.RGB[3])
7187e6fb56fSmrg            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x27, Table.RGB[3]);
7197e6fb56fSmrg        if (Table.RGB[4])
7207e6fb56fSmrg            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x2B, Table.RGB[4]);
7217e6fb56fSmrg        if (Table.RGB[5])
7227e6fb56fSmrg            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x2C, Table.RGB[5]);
7237e6fb56fSmrg        if (pBIOSInfo->TVEncoder == VIA_VT1625) {
7247e6fb56fSmrg            if (pBIOSInfo->TVType < TVTYPE_480P) {
7257e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x12);
7267e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x23, 0x7E);
7277e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A, 0x85);
7287e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4B, 0x0A);
7297e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4E, 0x00);
7307e6fb56fSmrg            } else {
7317e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x12);
7327e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A, 0x85);
7337e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4B, 0x0A);
7347e6fb56fSmrg            }
7357e6fb56fSmrg        }
7367e6fb56fSmrg    } else if (pBIOSInfo->TVOutput == TVOUTPUT_YCBCR) {
7377e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x03);
7387e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x65, Table.YCbCr[0]);
7397e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x66, Table.YCbCr[1]);
7407e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x67, Table.YCbCr[2]);
7417e6fb56fSmrg        if (pBIOSInfo->TVEncoder == VIA_VT1625) {
7427e6fb56fSmrg            if (pBIOSInfo->TVType < TVTYPE_480P) {
7437e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x23, 0x7E);
7447e6fb56fSmrg                xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4E, 0x00);
7457e6fb56fSmrg            }
7467e6fb56fSmrg        }
7477e6fb56fSmrg    }
7487e6fb56fSmrg
7497e6fb56fSmrg    /* Configure flicker filter. */
7507e6fb56fSmrg    xf86I2CReadByte(pBIOSInfo->TVI2CDev, 0x03, &save);
7517e6fb56fSmrg    save &= 0xFC;
7527e6fb56fSmrg    if (pBIOSInfo->TVDeflicker == 1)
7537e6fb56fSmrg        save |= 0x01;
7547e6fb56fSmrg    else if (pBIOSInfo->TVDeflicker == 2)
7557e6fb56fSmrg        save |= 0x02;
7567e6fb56fSmrg    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x03, save);
7577e6fb56fSmrg}
7587e6fb56fSmrg
7597e6fb56fSmrg/*
7607e6fb56fSmrg * Also suited for VT1622A, VT1623, VT1625.
7617e6fb56fSmrg */
7627e6fb56fSmrgstatic void
76390b17f1bSmrgVT1622ModeCrtc(xf86CrtcPtr crtc, DisplayModePtr mode)
7647e6fb56fSmrg{
76590b17f1bSmrg	ScrnInfoPtr pScrn = crtc->scrn;
76690b17f1bSmrg	vgaHWPtr hwp = VGAHWPTR(pScrn);
76790b17f1bSmrg	VIAPtr pVia = VIAPTR(pScrn);
76890b17f1bSmrg	VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
76990b17f1bSmrg	struct VT162XTableRec Table;
7707e6fb56fSmrg
7717e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622ModeCrtc\n"));
7727e6fb56fSmrg
7737e6fb56fSmrg    if (pBIOSInfo->TVEncoder == VIA_VT1622)
7747e6fb56fSmrg        Table = VT1622Table[VT1622ModeIndex(pScrn, mode)];
7757e6fb56fSmrg    else if (pBIOSInfo->TVEncoder == VIA_VT1625)
7767e6fb56fSmrg        Table = VT1625Table[VT1622ModeIndex(pScrn, mode)];
7777e6fb56fSmrg    else        /* VT1622A/VT1623 */
7787e6fb56fSmrg        Table = VT1623Table[VT1622ModeIndex(pScrn, mode)];
7797e6fb56fSmrg
7807e6fb56fSmrg    hwp->writeCrtc(hwp, 0x6A, 0x00);
7817e6fb56fSmrg    hwp->writeCrtc(hwp, 0x6B, 0x00);
7827e6fb56fSmrg    hwp->writeCrtc(hwp, 0x6C, 0x00);
7837e6fb56fSmrg
7847e6fb56fSmrg    if (pVia->IsSecondary) {
7857e6fb56fSmrg        hwp->writeCrtc(hwp, 0x6C, Table.SecondaryCR6C);
7867e6fb56fSmrg
7877e6fb56fSmrg        ViaCrtcMask(hwp, 0x6A, 0x80, 0x80);
7887e6fb56fSmrg        ViaCrtcMask(hwp, 0x6C, 0x80, 0x80);
7897e6fb56fSmrg
7907e6fb56fSmrg        /* CLE266Ax use 2x XCLK. */
7917e6fb56fSmrg        if ((pVia->Chipset == VIA_CLE266) && CLE266_REV_IS_AX(pVia->ChipRev)) {
7927e6fb56fSmrg            ViaCrtcMask(hwp, 0x6B, 0x20, 0x20);
7937e6fb56fSmrg
7947e6fb56fSmrg            /* Fix TV clock polarity for CLE266A2. */
7957e6fb56fSmrg            if (pVia->ChipRev == 0x02)
7967e6fb56fSmrg                ViaCrtcMask(hwp, 0x6C, 0x1C, 0x1C);
7977e6fb56fSmrg        }
7987e6fb56fSmrg
7997e6fb56fSmrg        /* Disable LCD scaling. */
8007e6fb56fSmrg        if (!pVia->SAMM || pVia->FirstInit)
8017e6fb56fSmrg            hwp->writeCrtc(hwp, 0x79, 0x00);
8027e6fb56fSmrg
8037e6fb56fSmrg    } else {
8047e6fb56fSmrg        if ((pVia->Chipset == VIA_CLE266) && CLE266_REV_IS_AX(pVia->ChipRev)) {
8057e6fb56fSmrg            ViaCrtcMask(hwp, 0x6B, 0x80, 0x80);
8067e6fb56fSmrg
8077e6fb56fSmrg            /* Fix TV clock polarity for CLE266A2. */
8087e6fb56fSmrg            if (pVia->ChipRev == 0x02)
8097e6fb56fSmrg                hwp->writeCrtc(hwp, 0x6C, Table.PrimaryCR6C);
8107e6fb56fSmrg        }
8117e6fb56fSmrg    }
8127e6fb56fSmrg    pBIOSInfo->ClockExternal = TRUE;
8137e6fb56fSmrg    ViaCrtcMask(hwp, 0x6A, 0x40, 0x40);
81490b17f1bSmrg    ViaSetTVClockSource(crtc);
8157e6fb56fSmrg}
8167e6fb56fSmrg
8177e6fb56fSmrg
8187e6fb56fSmrgstatic void
8197e6fb56fSmrgVT1621Power(ScrnInfoPtr pScrn, Bool On)
8207e6fb56fSmrg{
8217e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
8227e6fb56fSmrg
8237e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621Power\n"));
8247e6fb56fSmrg
8257e6fb56fSmrg    if (On)
8267e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
8277e6fb56fSmrg    else
8287e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x03);
8297e6fb56fSmrg}
8307e6fb56fSmrg
8317e6fb56fSmrgstatic void
8327e6fb56fSmrgVT1622Power(ScrnInfoPtr pScrn, Bool On)
8337e6fb56fSmrg{
8347e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
8357e6fb56fSmrg
8367e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622Power\n"));
8377e6fb56fSmrg
8387e6fb56fSmrg    if (On)
8397e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
8407e6fb56fSmrg    else
8417e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x0F);
8427e6fb56fSmrg}
8437e6fb56fSmrg
8447e6fb56fSmrgstatic void
8457e6fb56fSmrgVT1625Power(ScrnInfoPtr pScrn, Bool On)
8467e6fb56fSmrg{
8477e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
8487e6fb56fSmrg
8497e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1625Power\n"));
8507e6fb56fSmrg
8517e6fb56fSmrg    if (On)
8527e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00);
8537e6fb56fSmrg    else
8547e6fb56fSmrg        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x3F);
8557e6fb56fSmrg}
8567e6fb56fSmrg
8577e6fb56fSmrg
8587e6fb56fSmrgvoid
8597e6fb56fSmrgViaVT162xInit(ScrnInfoPtr pScrn)
8607e6fb56fSmrg{
8617e6fb56fSmrg    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
8627e6fb56fSmrg
8637e6fb56fSmrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaVT162xInit\n"));
8647e6fb56fSmrg
8657e6fb56fSmrg    switch (pBIOSInfo->TVEncoder) {
8667e6fb56fSmrg        case VIA_VT1621:
8677e6fb56fSmrg            pBIOSInfo->TVSave = VT162xSave;
8687e6fb56fSmrg            pBIOSInfo->TVRestore = VT162xRestore;
8697e6fb56fSmrg            pBIOSInfo->TVDACSense = VT1621DACSense;
8707e6fb56fSmrg            pBIOSInfo->TVModeValid = VT1621ModeValid;
8717e6fb56fSmrg            pBIOSInfo->TVModeI2C = VT1621ModeI2C;
8727e6fb56fSmrg            pBIOSInfo->TVModeCrtc = VT1621ModeCrtc;
8737e6fb56fSmrg            pBIOSInfo->TVPower = VT1621Power;
8747e6fb56fSmrg            pBIOSInfo->TVModes = VT1621Modes;
87590b17f1bSmrg            pBIOSInfo->TVNumModes = sizeof(VT1621Modes) / sizeof(DisplayModeRec);
8767e6fb56fSmrg            pBIOSInfo->TVPrintRegs = VT162xPrintRegs;
8777e6fb56fSmrg            pBIOSInfo->TVNumRegs = 0x68;
8787e6fb56fSmrg            break;
8797e6fb56fSmrg        case VIA_VT1622:
8807e6fb56fSmrg            pBIOSInfo->TVSave = VT162xSave;
8817e6fb56fSmrg            pBIOSInfo->TVRestore = VT162xRestore;
8827e6fb56fSmrg            pBIOSInfo->TVDACSense = VT1622DACSense;
8837e6fb56fSmrg            pBIOSInfo->TVModeValid = VT1622ModeValid;
8847e6fb56fSmrg            pBIOSInfo->TVModeI2C = VT1622ModeI2C;
8857e6fb56fSmrg            pBIOSInfo->TVModeCrtc = VT1622ModeCrtc;
8867e6fb56fSmrg            pBIOSInfo->TVPower = VT1622Power;
8877e6fb56fSmrg            pBIOSInfo->TVModes = VT1622Modes;
88890b17f1bSmrg            pBIOSInfo->TVNumModes = sizeof(VT1622Modes) / sizeof(DisplayModeRec);
8897e6fb56fSmrg            pBIOSInfo->TVPrintRegs = VT162xPrintRegs;
8907e6fb56fSmrg            pBIOSInfo->TVNumRegs = 0x68;
8917e6fb56fSmrg            break;
8927e6fb56fSmrg        case VIA_VT1623:
8937e6fb56fSmrg            pBIOSInfo->TVSave = VT162xSave;
8947e6fb56fSmrg            pBIOSInfo->TVRestore = VT162xRestore;
8957e6fb56fSmrg            pBIOSInfo->TVDACSense = VT1622DACSense;
8967e6fb56fSmrg            pBIOSInfo->TVModeValid = VT1622ModeValid;
8977e6fb56fSmrg            pBIOSInfo->TVModeI2C = VT1622ModeI2C;
8987e6fb56fSmrg            pBIOSInfo->TVModeCrtc = VT1622ModeCrtc;
8997e6fb56fSmrg            pBIOSInfo->TVPower = VT1622Power;
9007e6fb56fSmrg            pBIOSInfo->TVModes = VT1623Modes;
90190b17f1bSmrg            pBIOSInfo->TVNumModes = sizeof(VT1623Modes) / sizeof(DisplayModeRec);
9027e6fb56fSmrg            pBIOSInfo->TVPrintRegs = VT162xPrintRegs;
9037e6fb56fSmrg            pBIOSInfo->TVNumRegs = 0x6C;
9047e6fb56fSmrg            break;
9057e6fb56fSmrg        case VIA_VT1625:
9067e6fb56fSmrg            pBIOSInfo->TVSave = VT162xSave;
9077e6fb56fSmrg            pBIOSInfo->TVRestore = VT162xRestore;
9087e6fb56fSmrg            pBIOSInfo->TVDACSense = VT1625DACSense;
9097e6fb56fSmrg            pBIOSInfo->TVModeValid = VT1625ModeValid;
9107e6fb56fSmrg            pBIOSInfo->TVModeI2C = VT1622ModeI2C;
9117e6fb56fSmrg            pBIOSInfo->TVModeCrtc = VT1622ModeCrtc;
9127e6fb56fSmrg            pBIOSInfo->TVPower = VT1625Power;
9137e6fb56fSmrg            pBIOSInfo->TVModes = VT1625Modes;
91490b17f1bSmrg            pBIOSInfo->TVNumModes = sizeof(VT1625Modes) / sizeof(DisplayModeRec);
9157e6fb56fSmrg            pBIOSInfo->TVPrintRegs = VT162xPrintRegs;
91690b17f1bSmrg            pBIOSInfo->TVNumRegs = 0x82;
9177e6fb56fSmrg            break;
9187e6fb56fSmrg        default:
9197e6fb56fSmrg            break;
9207e6fb56fSmrg    }
9217e6fb56fSmrg}
922