1/*
2 * Copyright 2005 Terry Lewis. All Rights Reserved.
3 * Copyright 2005 Philip Langdale. All Rights Reserved. (CH7011 additions)
4 * Copyright 2004 The Unichrome Project  [unichrome.sf.net]
5 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
6 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sub license,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "via_driver.h"
33#include "via_ch7xxx.h"
34#include <unistd.h>
35
36#ifdef HAVE_DEBUG
37/*
38 *
39 */
40static void
41CH7xxxPrintRegs(ScrnInfoPtr pScrn)
42{
43    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
44    CARD8 i, buf;
45
46    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Printing registers for %s\n",
47	       pBIOSInfo->TVI2CDev->DevName);
48
49    for (i = 0; i < pBIOSInfo->TVNumRegs; i++) {
50	xf86I2CReadByte(pBIOSInfo->TVI2CDev, i, &buf);
51	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV%02X: 0x%02X\n", i, buf);
52    }
53
54    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of TV registers.\n");
55}
56#endif /* HAVE_DEBUG */
57
58/*
59 *
60 */
61I2CDevPtr
62ViaCH7xxxDetect(ScrnInfoPtr pScrn, I2CBusPtr pBus, CARD8 Address)
63{
64    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
65    I2CDevPtr pDev = xf86CreateI2CDevRec();
66    CARD8 buf;
67
68    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaCH7xxxDetect\n"));
69
70    pDev->DevName = "CH7xxx";
71    pDev->SlaveAddr = Address;
72    pDev->pI2CBus = pBus;
73
74    if (!xf86I2CDevInit(pDev)) {
75		xf86DestroyI2CDevRec(pDev, TRUE);
76		return NULL;
77    }
78
79    if (!xf86I2CReadByte(pDev, 0x4B, &buf)) {
80        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to read from %s Slave %d.\n",
81                   pBus->BusName, Address);
82        xf86DestroyI2CDevRec(pDev, TRUE);
83        return NULL;
84    }
85
86    switch (buf) {
87        case 0x17:
88            xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Chrontel CH7011 TV Encoder\n");
89            pBIOSInfo->TVEncoder = VIA_CH7011;
90            pDev->DevName="CH7011";
91            break;
92        case 0x19:
93            xf86I2CReadByte(pDev, 0x4A, &buf);
94            if (buf == 0x81) {
95                xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Chrontel CH7019A LVDS Transmitter/TV Encoder\n");
96                pBIOSInfo->TVEncoder = VIA_CH7019A;
97                pDev->DevName="CH7019A";
98            } else {
99                xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Chrontel CH7019B LVDS Transmitter/TV Encoder\n");
100                pBIOSInfo->TVEncoder = VIA_CH7019B;
101                pDev->DevName="CH7019B";
102            }
103            break;
104        case 0x1B:
105            xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Chrontel CH7017 LVDS Transmitter\n");
106            pBIOSInfo->TVEncoder = VIA_CH7017;
107            pDev->DevName="CH7017";
108            break;
109        case 0x3A:
110            /* single init table --> single channel LVDS transmitter ? */
111            xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Chrontel CH7304 LVDS Transmitter\n");
112            pBIOSInfo->TVEncoder = VIA_CH7304;
113            pDev->DevName="CH7304";
114            break;
115        case 0x3B:
116            /* dual init table --> dual channel LVDS transmitter ? */
117            xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Chrontel CH7305 LVDS Transmitter\n");
118            pBIOSInfo->TVEncoder = VIA_CH7305;
119            pDev->DevName="CH7305";
120            break;
121        default:
122            pBIOSInfo->TVEncoder = VIA_NONETV;
123            xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown CH7xxx"
124                       " device found. [%x:0x1B contains %x]\n",
125                       Address, buf);
126            xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Unknown CH7xxx encoder found\n");
127
128            xf86DestroyI2CDevRec(pDev,TRUE);
129            pDev = NULL;
130            break;
131    }
132    return pDev;
133}
134
135/*
136 *
137 */
138
139static void
140CH7xxxSave(ScrnInfoPtr pScrn)
141{
142    int i;
143    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
144
145    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7xxxSave\n"));
146
147    for (i = 0; i < pBIOSInfo->TVNumRegs; i++)
148        xf86I2CReadByte(pBIOSInfo->TVI2CDev, i, &(pBIOSInfo->TVRegs[i]));
149}
150
151
152static void
153CH7xxxRestore(ScrnInfoPtr pScrn)
154{
155    int i;
156    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
157
158    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7xxxRestore\n"));
159
160    for (i = 0; i < pBIOSInfo->TVNumRegs; i++)
161        xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, pBIOSInfo->TVRegs[i]);
162}
163
164static CARD8
165CH7xxxDACSenseI2C(I2CDevPtr pDev)
166{
167    CARD8  save, sense;
168
169    /* Turn all DACP on*/
170    xf86I2CWriteByte(pDev, 0x49, 0x20);
171
172    /* Make sure Bypass mode is disabled (DACBP) bit0 is set to '0' */
173    xf86I2CReadByte(pDev, 0x21, &save);
174    xf86I2CWriteByte(pDev, 0x21, save & ~0x01);
175
176    /* Set Sense bit0 to '1' */
177    xf86I2CReadByte(pDev, 0x20, &save);
178    xf86I2CWriteByte(pDev, 0x20, save | 0x01);
179
180    /* Set Sense bit0 back to '0' */
181    xf86I2CReadByte(pDev, 0x20, &save);
182    xf86I2CWriteByte(pDev, 0x20, save & ~0x01);
183
184    /* Read DACT status bits */
185    xf86I2CReadByte(pDev, 0x20, &sense);
186
187    return (sense & 0x1F);
188}
189
190/*
191 *  A CH7xxx hack. (T. Lewis. S-Video fixed by P. Langdale)
192 *
193 *  CH7xxx Cable types (C+S and YcBcR untested and almost certainly wrong)
194 *		0x10 = Composite
195 *      0x0C = S-Video
196 *      0x02 = Composite+S-Video
197 *      0x04 = YcBcR
198 *      0x00 = Nothing Connected
199 */
200
201static Bool
202CH7xxxDACSense(ScrnInfoPtr pScrn)
203{
204    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
205    CARD8 sense;
206
207    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7xxxDACDetect\n"));
208
209	/* is this needed? IH */
210    if (!pBIOSInfo->TVI2CDev ||
211        !pBIOSInfo->TVEncoder)
212	    return FALSE;
213
214    sense = CH7xxxDACSenseI2C(pBIOSInfo->TVI2CDev);
215
216    /* I'm sure these case values are correct,
217     * but we should get something in any case.
218     * 0x10 (Composite), 0x0C (S-Video) and 0x00 (Nothing connected)
219     * seem to be correct however.
220     */
221	switch (sense) {
222	    case 0x10:
223		pBIOSInfo->TVOutput = TVOUTPUT_COMPOSITE;
224		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CH7xxx: Composite connected.\n");
225		return TRUE;
226	    case 0x0C:
227		pBIOSInfo->TVOutput = TVOUTPUT_SVIDEO;
228		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CH7xxx: S-Video connected.\n");
229		return TRUE;
230	    case 0x02:
231		pBIOSInfo->TVOutput = TVOUTPUT_SC;
232		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CHxxx: Composite+S-Video connected.\n");
233		return TRUE;
234	    case 0x04:
235		pBIOSInfo->TVOutput = TVOUTPUT_YCBCR;
236		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CHxxx: YcBcR Connected.\n");
237		return TRUE;
238	    case 0x00:
239		pBIOSInfo->TVOutput = TVOUTPUT_NONE;
240		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CH7xxx: Nothing connected.\n");
241		return FALSE;
242	    default:
243		pBIOSInfo->TVOutput = TVOUTPUT_NONE;
244		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "CH7xxx: Unknown cable combination: 0x0%2X.\n",sense);
245		return FALSE;
246	}
247}
248
249static CARD8
250CH7011ModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
251{
252    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
253    int i;
254
255    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7011ModeIndex\n"));
256    for (i = 0; CH7011Table[i].Width; i++) {
257        if ((CH7011Table[i].Width == mode->CrtcHDisplay) &&
258            (CH7011Table[i].Height == mode->CrtcVDisplay) &&
259            (CH7011Table[i].Standard == pBIOSInfo->TVType) &&
260            !(strcmp(CH7011Table[i].name, mode->name)))
261            return i;
262    }
263    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "CH7011ModeIndex:"
264               " Mode \"%s\" not found in Table\n", mode->name);
265    return 0xFF;
266}
267
268static CARD8
269CH7019ModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
270{
271    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
272    int i;
273
274    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7019ModeIndex\n"));
275    for (i = 0; CH7019Table[i].Width; i++) {
276        if ((CH7019Table[i].Width == mode->CrtcHDisplay) &&
277            (CH7019Table[i].Height == mode->CrtcVDisplay) &&
278            (CH7019Table[i].Standard == pBIOSInfo->TVType) &&
279            !(strcmp(CH7019Table[i].name, mode->name)))
280            return i;
281    }
282    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "CH7019ModeIndex:"
283               " Mode \"%s\" not found in Table\n", mode->name);
284    return 0xFF;
285}
286
287/*
288 *
289 */
290static ModeStatus
291CH7xxxModeValid(ScrnInfoPtr pScrn, DisplayModePtr mode)
292{
293    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
294
295    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7xxxModeValid\n"));
296
297    if ((mode->PrivSize != sizeof(struct CH7xxxModePrivate)) ||
298        ((mode->Private != (void *) &CH7xxxModePrivateNTSC) &&
299         (mode->Private != (void *) &CH7xxxModePrivatePAL))) {
300        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not a mode defined by the TV Encoder.\n");
301        return MODE_BAD;
302    }
303
304    if ((pBIOSInfo->TVType == TVTYPE_NTSC) &&
305        (mode->Private != (void *) &CH7xxxModePrivateNTSC)) {
306        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standard is NTSC. This is a PAL mode.\n");
307        return MODE_BAD;
308    } else if ((pBIOSInfo->TVType == TVTYPE_PAL) &&
309               (mode->Private != (void *) &CH7xxxModePrivatePAL)) {
310        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standard is PAL. This is a NTSC mode.\n");
311        return MODE_BAD;
312    }
313
314    if (pBIOSInfo->TVEncoder == VIA_CH7011)
315    {
316        if (CH7011ModeIndex(pScrn, mode) != 0xFF)
317            return MODE_OK;
318    }
319    else
320    {
321        if (CH7019ModeIndex(pScrn, mode) != 0xFF)
322            return MODE_OK;
323    }
324    return MODE_BAD;
325}
326
327static void
328CH7xxxModeI2C(ScrnInfoPtr pScrn, DisplayModePtr mode)
329{
330    VIAPtr pVia = VIAPTR(pScrn);
331    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
332
333    CARD8   i, j;
334
335    VIABIOSTVMASKTableRec Mask;
336    struct CH7xxxTableRec Table;
337
338    if (pBIOSInfo->TVEncoder == VIA_CH7011)
339    {
340        Table = CH7011Table[CH7011ModeIndex(pScrn, mode)];
341        Mask = ch7011MaskTable;
342    }
343    else
344    {
345        Table = CH7019Table[CH7019ModeIndex(pScrn, mode)];
346        Mask = ch7019MaskTable;
347    }
348
349    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7011ModeI2C\n"));
350
351    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x49, 0x3E);
352    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1E, 0xD0);
353
354    for (i = 0,j = 0; (j < Mask.numTV) && (i < VIA_BIOS_TABLE_NUM_TV_REG); i++) {
355        if (Mask.TV[i] == 0xFF) {
356            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV[i]);
357            j++;
358        } else {
359            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, pBIOSInfo->TVRegs[i]);
360        }
361    }
362
363    if ((pBIOSInfo->TVType == TVTYPE_NTSC) && pBIOSInfo->TVDotCrawl) {
364        CARD16 *DotCrawl = Table.DotCrawlNTSC;
365        CARD8 address, save;
366
367        for (i = 1; i < (DotCrawl[0] + 1); i++) {
368            address = (CARD8)(DotCrawl[i] & 0xFF);
369
370            save = (CARD8)(DotCrawl[i] >> 8);
371            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, address, save);
372        }
373    }
374
375    /*
376     * Only Composite and SVideo have been tested.
377     */
378    switch(pBIOSInfo->TVOutput){
379        case TVOUTPUT_COMPOSITE:
380            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x49, 0x2E);
381            break;
382        case TVOUTPUT_SVIDEO:
383            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x49, 0x32);
384            break;
385        case TVOUTPUT_SC:
386            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x49, 0x3C);
387            break;
388        case TVOUTPUT_YCBCR:
389            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x49, 0x3A);
390            break;
391        default:
392            break;
393    }
394
395    if (pVia->IsSecondary) { /* Patch as setting 2nd path */
396        j = (CARD8)(Mask.misc2 >> 5);
397        for (i = 0; i < j; i++)
398            xf86I2CWriteByte(pBIOSInfo->TVI2CDev, Table.Patch2[i] & 0xFF, Table.Patch2[i] >> 8);
399    }
400}
401
402static void
403CH7xxxModeCrtc(xf86CrtcPtr crtc, DisplayModePtr mode)
404{
405	ScrnInfoPtr pScrn = crtc->scrn;
406	vgaHWPtr hwp = VGAHWPTR(pScrn);
407	VIAPtr pVia =  VIAPTR(pScrn);
408	VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
409	CARD8  *CRTC, *Misc;
410	int  i, j;
411
412    VIABIOSTVMASKTableRec Mask;
413    struct CH7xxxTableRec Table;
414
415    if (pBIOSInfo->TVEncoder == VIA_CH7011)
416    {
417        Table = CH7011Table[CH7011ModeIndex(pScrn, mode)];
418        Mask = ch7011MaskTable;
419    }
420    else
421    {
422        Table = CH7019Table[CH7019ModeIndex(pScrn, mode)];
423        Mask = ch7019MaskTable;
424    }
425
426    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7xxxModeCrtc\n"));
427
428    if (pVia->IsSecondary) {
429        switch (pScrn->bitsPerPixel) {
430            case 16:
431                CRTC = Table.CRTC2_16BPP;
432                break;
433            case 24:
434            case 32:
435                CRTC = Table.CRTC2_32BPP;
436                break;
437            case 8:
438            default:
439                CRTC = Table.CRTC2_8BPP;
440                break;
441        }
442        Misc = Table.Misc2;
443
444        for (i = 0, j = 0; i < Mask.numCRTC2; j++) {
445            if (Mask.CRTC2[j] == 0xFF) {
446                hwp->writeCrtc(hwp, j + 0x50, CRTC[j]);
447                i++;
448            }
449        }
450
451        if (Mask.misc2 & 0x18) {
452            pBIOSInfo->Clock = (Misc[3] << 8) & Misc[4];
453            /* VIASetUseExternalClock(hwp); */
454        }
455
456        ViaCrtcMask(hwp, 0x6A, 0xC0, 0xC0);
457        ViaCrtcMask(hwp, 0x6B, 0x01, 0x01);
458        ViaCrtcMask(hwp, 0x6C, 0x01, 0x01);
459
460        /* Disable LCD Scaling */
461        if (!pVia->SAMM || pVia->FirstInit)
462            hwp->writeCrtc(hwp, 0x79, 0x00);}
463    else {
464
465        CRTC = Table.CRTC1;
466        Misc = Table.Misc1;
467
468        for (i = 0, j = 0; i < Mask.numCRTC1; j++) {
469            if (Mask.CRTC1[j] == 0xFF) {
470                hwp->writeCrtc(hwp, j, CRTC[j]);
471                i++;
472            }
473        }
474
475        ViaCrtcMask(hwp, 0x33, Misc[0], 0x20);
476        hwp->writeCrtc(hwp, 0x6A, Misc[1]);
477
478        if ((pVia->Chipset == VIA_CLE266) &&
479            CLE266_REV_IS_AX(pVia->ChipRev)) {
480            hwp->writeCrtc(hwp, 0x6B, Misc[2] | 0x81);
481            /* Fix TV clock Polarity for CLE266A2 */
482            if (pVia->ChipRev == 0x02)
483                hwp->writeCrtc(hwp, 0x6C, Misc[3] | 0x01);
484        } else
485            hwp->writeCrtc(hwp, 0x6B, Misc[2] | 0x01);
486
487        if (Mask.misc1 & 0x30) {
488            /* CLE266Ax use 2x XCLK */
489            if ((pVia->Chipset == VIA_CLE266) &&
490                CLE266_REV_IS_AX(pVia->ChipRev))
491                pBIOSInfo->Clock = 0x471C;
492            else
493                pBIOSInfo->Clock = (Misc[4] << 8) | Misc[5];
494        }
495
496        ViaCrtcMask(hwp, 0x6A, 0x40, 0x40);
497        ViaCrtcMask(hwp, 0x6B, 0x01, 0x01);
498        ViaCrtcMask(hwp, 0x6C, 0x01, 0x01);
499    }
500
501    ViaSeqMask(hwp, 0x1E, 0xC0, 0xC0); /* Enable DI0/DVP0 */
502}
503
504
505/*
506 *
507 */
508static void
509CH7xxxTVPower(ScrnInfoPtr pScrn, Bool On)
510{
511	VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
512
513	if (On){
514		DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7xxxTVPower: On\n"));
515		xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x49, 0x20);
516	}else{
517		DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7xxxTVPower: Off\n"));
518		xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x49, 0x3E);
519		xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1E, 0xD0);
520    }
521}
522
523static void
524CH7019LCDPower(ScrnInfoPtr pScrn, Bool On)
525{
526	VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
527	CARD8 W_Buffer[2], R_Buffer[1];
528	int i;
529
530	if (On){
531		DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7xxxLCDPower: On\n"));
532		W_Buffer[0] = 0x63;
533		W_Buffer[1] = 0x4B;
534		xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,2, NULL,0);
535		W_Buffer[0] = 0x66;
536		W_Buffer[1] = 0x20;
537		xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,2, NULL,0);
538
539		for (i = 0; i < 10; i++) {
540			W_Buffer[0] = 0x63;
541			xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,1, R_Buffer,1);
542			usleep(100);
543			W_Buffer[0] = 0x63;
544			W_Buffer[1] = (R_Buffer[0] | 0x40);
545			xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,2, NULL,0);
546			DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
547                             "CH7xxxLCDPower: [%d]write 0x63 = %X!\n", i+1, W_Buffer[1]));
548			usleep(1);
549			W_Buffer[0] = 0x63;
550			W_Buffer[1] &= ~0x40;
551			xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,2, NULL,0);
552			DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
553                             "CH7xxxLCDPower: [%d]write 0x63 = %X!\n", i+1, W_Buffer[1]));
554			usleep(100);
555			W_Buffer[0] = 0x66;
556			xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,1, R_Buffer,1);
557
558			if (((R_Buffer[0] & 0x44) == 0x44) || (i >= 9)) {
559				/* PLL lock OK, Turn on VDD */
560				usleep(500);
561				W_Buffer[1] = R_Buffer[0] | 0x01;
562				xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,2, NULL,0);
563				DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
564						 "CH7xxxLCDPower: CH7019 PLL lock ok!\n"));
565				/* reset data path */
566				W_Buffer[0] = 0x48;
567				xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,1, R_Buffer,1);
568				W_Buffer[1] = R_Buffer[0] & ~0x08;
569				xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,2, NULL,0);
570				usleep(1);
571				W_Buffer[1] = R_Buffer[0];
572				xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,2, NULL,0);
573				break;
574			}
575
576            DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
577                             "CH7xxxLCDPower: [%d]CH7019 PLL lock fail!\n", i+1));
578            DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
579                             "CH7xxxLCDPower: [%d]0x66 = %X!\n", i+1, R_Buffer[0]));
580		}
581	}else{
582		DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CH7xxxLCDPower: Off\n"));
583		/* Turn off VDD (Turn off backlignt only) */
584		W_Buffer[0] = 0x66;
585		xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,1, R_Buffer,1);
586		W_Buffer[1] &= ~0x01;
587		xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,2, NULL,0);
588		usleep(100);
589		/* Turn off LVDS path */
590		W_Buffer[0] = 0x63;
591		xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,1, R_Buffer,1);
592		W_Buffer[1] = (R_Buffer[0] | 0x40);
593		xf86I2CWriteRead(pBIOSInfo->TVI2CDev, W_Buffer,2, NULL,0);
594	}
595}
596
597/*
598 *
599 */
600void
601ViaCH7xxxInit(ScrnInfoPtr pScrn)
602{
603    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
604
605    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaCH7xxxInit\n"));
606
607    switch (pBIOSInfo->TVEncoder) {
608        case VIA_CH7011:
609            pBIOSInfo->TVSave = CH7xxxSave;
610            pBIOSInfo->TVRestore = CH7xxxRestore;
611            pBIOSInfo->TVDACSense = CH7xxxDACSense;
612            pBIOSInfo->TVModeValid = CH7xxxModeValid;
613            pBIOSInfo->TVModeI2C = CH7xxxModeI2C;
614            pBIOSInfo->TVModeCrtc = CH7xxxModeCrtc;
615            pBIOSInfo->TVPower = CH7xxxTVPower;
616            pBIOSInfo->TVModes = CH7011Modes;
617            pBIOSInfo->TVNumModes = sizeof(CH7011Modes) / sizeof(DisplayModeRec);
618            pBIOSInfo->LCDPower = NULL;
619            pBIOSInfo->TVNumRegs = CH_7011_MAX_NUM_REG;
620#ifdef HAVE_DEBUG
621            pBIOSInfo->TVPrintRegs = CH7xxxPrintRegs;
622#endif
623            break;
624        case VIA_CH7019A:
625        case VIA_CH7019B:
626            pBIOSInfo->TVDACSense = CH7xxxDACSense;
627            pBIOSInfo->TVSave = CH7xxxSave;
628            pBIOSInfo->TVRestore = CH7xxxRestore;
629            pBIOSInfo->TVModeValid = CH7xxxModeValid;
630            pBIOSInfo->TVModeI2C = CH7xxxModeI2C;
631            pBIOSInfo->TVModeCrtc = CH7xxxModeCrtc;
632            pBIOSInfo->TVPower = CH7xxxTVPower;
633            pBIOSInfo->TVModes = CH7019Modes;
634            pBIOSInfo->TVNumModes = sizeof(CH7019Modes) / sizeof(DisplayModeRec);
635            pBIOSInfo->LCDPower = CH7019LCDPower;
636            pBIOSInfo->TVNumRegs = CH_7019_MAX_NUM_REG;
637#ifdef HAVE_DEBUG
638            pBIOSInfo->TVPrintRegs = CH7xxxPrintRegs;
639#endif
640            break;
641        default:
642            DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ViaCH7xxxInit missing\n"));
643            break;
644    }
645
646    /* Save before continuing */
647    if (pBIOSInfo->TVSave)
648        pBIOSInfo->TVSave(pScrn);
649}
650