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  */
40 static void
CH7xxxPrintRegs(ScrnInfoPtr pScrn)41 CH7xxxPrintRegs(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  */
61 I2CDevPtr
ViaCH7xxxDetect(ScrnInfoPtr pScrn,I2CBusPtr pBus,CARD8 Address)62 ViaCH7xxxDetect(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 
139 static void
CH7xxxSave(ScrnInfoPtr pScrn)140 CH7xxxSave(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 
152 static void
CH7xxxRestore(ScrnInfoPtr pScrn)153 CH7xxxRestore(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 
164 static CARD8
CH7xxxDACSenseI2C(I2CDevPtr pDev)165 CH7xxxDACSenseI2C(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 
201 static Bool
CH7xxxDACSense(ScrnInfoPtr pScrn)202 CH7xxxDACSense(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 
249 static CARD8
CH7011ModeIndex(ScrnInfoPtr pScrn,DisplayModePtr mode)250 CH7011ModeIndex(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 
268 static CARD8
CH7019ModeIndex(ScrnInfoPtr pScrn,DisplayModePtr mode)269 CH7019ModeIndex(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  */
290 static ModeStatus
CH7xxxModeValid(ScrnInfoPtr pScrn,DisplayModePtr mode)291 CH7xxxModeValid(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 
327 static void
CH7xxxModeI2C(ScrnInfoPtr pScrn,DisplayModePtr mode)328 CH7xxxModeI2C(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 
402 static void
CH7xxxModeCrtc(xf86CrtcPtr crtc,DisplayModePtr mode)403 CH7xxxModeCrtc(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  */
508 static void
CH7xxxTVPower(ScrnInfoPtr pScrn,Bool On)509 CH7xxxTVPower(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 
523 static void
CH7019LCDPower(ScrnInfoPtr pScrn,Bool On)524 CH7019LCDPower(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  */
600 void
ViaCH7xxxInit(ScrnInfoPtr pScrn)601 ViaCH7xxxInit(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