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