1/*
2 * Video bridge detection and configuration for 300, 315 and 330 series
3 *
4 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1) Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2) Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3) The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
29 *
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include "sis.h"
37#define SIS_NEED_inSISREG
38#define SIS_NEED_inSISIDXREG
39#define SIS_NEED_outSISIDXREG
40#define SIS_NEED_orSISIDXREG
41#define SIS_NEED_andSISIDXREG
42#define SIS_NEED_setSISIDXREG
43#include "sis_regs.h"
44#include "sis_dac.h"
45
46void SISCRT1PreInit(ScrnInfoPtr pScrn);
47void SISLCDPreInit(ScrnInfoPtr pScrn, Bool quiet);
48void SISTVPreInit(ScrnInfoPtr pScrn, Bool quiet);
49void SISCRT2PreInit(ScrnInfoPtr pScrn, Bool quiet);
50Bool SISRedetectCRT2Type(ScrnInfoPtr pScrn);
51void SISSense30x(ScrnInfoPtr pScrn, Bool quiet);
52void SISSenseChrontel(ScrnInfoPtr pScrn, Bool quiet);
53void SiSSetupPseudoPanel(ScrnInfoPtr pScrn);
54
55extern Bool   SISDetermineLCDACap(ScrnInfoPtr pScrn);
56extern void   SISSaveDetectedDevices(ScrnInfoPtr pScrn);
57extern void   SISWaitRetraceCRT1(ScrnInfoPtr pScrn);
58extern UChar  SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, UShort offset, UChar value);
59
60/* From init.c, init301.c ---- (use their data types) */
61extern BOOLEAN		SiS_GetPanelID(struct SiS_Private *SiS_Pr);
62extern unsigned short	SiS_SenseLCDDDC(struct SiS_Private *SiS_Pr, SISPtr pSiS);
63extern unsigned short	SiS_SenseVGA2DDC(struct SiS_Private *SiS_Pr, SISPtr pSiS);
64
65typedef struct _SiS_LCD_StStruct
66{
67	ULong VBLCD_lcdflag;
68	UShort LCDwidth;
69	UShort LCDheight;
70} SiS_LCD_StStruct;
71
72static const SiS_LCD_StStruct SiS300_LCD_Type[]=
73{
74	{ VB_LCD_1024x768, 1024,  768 },  /* 0 - invalid */
75	{ VB_LCD_800x600,   800,  600 },  /* 1 */
76	{ VB_LCD_1024x768, 1024,  768 },  /* 2 */
77	{ VB_LCD_1280x1024,1280, 1024 },  /* 3 */
78	{ VB_LCD_1280x960, 1280,  960 },  /* 4 */
79	{ VB_LCD_640x480,   640,  480 },  /* 5 */
80	{ VB_LCD_1024x600, 1024,  600 },  /* 6 */
81	{ VB_LCD_1152x768, 1152,  768 },  /* 7 */
82	{ VB_LCD_1024x768, 1024,  768 },  /* 8 */
83	{ VB_LCD_1024x768, 1024,  768 },  /* 9 */
84	{ VB_LCD_1280x768, 1280,  768 },  /* a */
85	{ VB_LCD_1024x768, 1024,  768 },  /* b */
86	{ VB_LCD_1024x768, 1024,  768 },  /* c */
87	{ VB_LCD_1024x768, 1024,  768 },  /* d */
88	{ VB_LCD_320x480,   320,  480 },  /* e */
89	{ VB_LCD_CUSTOM,      0,    0 }   /* f */
90};
91
92static const SiS_LCD_StStruct SiS315_LCD_Type[]=
93{
94        { VB_LCD_1024x768, 1024,  768 },  /* 0 - invalid */
95	{ VB_LCD_800x600,   800,  600 },  /* 1 */
96	{ VB_LCD_1024x768, 1024,  768 },  /* 2 */
97	{ VB_LCD_1280x1024,1280, 1024 },  /* 3 */
98	{ VB_LCD_640x480,   640,  480 },  /* 4 */
99	{ VB_LCD_1024x600, 1024,  600 },  /* 5 */
100	{ VB_LCD_1152x864, 1152,  864 },  /* 6 */
101	{ VB_LCD_1280x960, 1280,  960 },  /* 7 */
102	{ VB_LCD_1152x768, 1152,  768 },  /* 8 */
103	{ VB_LCD_1400x1050,1400, 1050 },  /* 9 */
104	{ VB_LCD_1280x768, 1280,  768 },  /* a */
105	{ VB_LCD_1600x1200,1600, 1200 },  /* b */
106	{ VB_LCD_640x480_2, 640,  480 },  /* c FSTN */
107	{ VB_LCD_640x480_3, 640,  480 },  /* d FSTN */
108	{ VB_LCD_320x480,   320,  480 },  /* e */
109	{ VB_LCD_CUSTOM,      0,    0 }   /* f */
110};
111
112static const SiS_LCD_StStruct SiS661_LCD_Type[]=
113{
114        { VB_LCD_1024x768, 1024,  768 },  /* 0 - invalid */
115	{ VB_LCD_800x600,   800,  600 },  /* 1 */
116	{ VB_LCD_1024x768, 1024,  768 },  /* 2 */
117	{ VB_LCD_1280x1024,1280, 1024 },  /* 3 */
118	{ VB_LCD_640x480,   640,  480 },  /* 4 */
119	{ VB_LCD_1024x600, 1024,  600 },  /* 5 - temp */
120	{ VB_LCD_1152x864, 1152,  864 },  /* 6 - temp */
121	{ VB_LCD_1280x960, 1280,  960 },  /* 7 */
122	{ VB_LCD_1280x854, 1280,  854 },  /* 8 */
123	{ VB_LCD_1400x1050,1400, 1050 },  /* 9 */
124	{ VB_LCD_1280x768, 1280,  768 },  /* a */
125	{ VB_LCD_1600x1200,1600, 1200 },  /* b */
126	{ VB_LCD_1280x800, 1280,  800 },  /* c */
127	{ VB_LCD_1680x1050,1680, 1050 },  /* d */
128	{ VB_LCD_1280x720, 1280,  720 },  /* e */
129	{ VB_LCD_CUSTOM,      0,    0 }   /* f */
130};
131
132static Bool
133TestDDC1(ScrnInfoPtr pScrn)
134{
135    SISPtr pSiS = SISPTR(pScrn);
136    UShort old;
137    int    count = 48;
138
139    old = SiS_ReadDDC1Bit(pSiS->SiS_Pr);
140    do {
141       if(old != SiS_ReadDDC1Bit(pSiS->SiS_Pr)) break;
142    } while(count--);
143    return (count == -1) ? FALSE : TRUE;
144}
145
146static int
147SiS_SISDetectCRT1(ScrnInfoPtr pScrn)
148{
149    SISPtr pSiS = SISPTR(pScrn);
150    UShort temp = 0xffff;
151    UChar  SR1F, CR63=0, CR17;
152    int    i, ret = 0;
153    Bool   mustwait = FALSE;
154
155    inSISIDXREG(SISSR,0x1F,SR1F);
156    setSISIDXREG(SISSR,0x1F,0x3f,0x04);
157    if(SR1F & 0xc0) mustwait = TRUE;
158
159    if(pSiS->VGAEngine == SIS_315_VGA) {
160       inSISIDXREG(SISCR,pSiS->myCR63,CR63);
161       CR63 &= 0x40;
162       andSISIDXREG(SISCR,pSiS->myCR63,0xbf);
163    }
164
165    inSISIDXREG(SISCR,0x17,CR17);
166    CR17 &= 0x80;
167    if(!CR17) {
168       orSISIDXREG(SISCR,0x17,0x80);
169       mustwait = TRUE;
170       outSISIDXREG(SISSR, 0x00, 0x01);
171       outSISIDXREG(SISSR, 0x00, 0x03);
172    }
173
174    if(mustwait) {
175       for(i=0; i < 10; i++) SISWaitRetraceCRT1(pScrn);
176    }
177
178    if(pSiS->ChipType >= SIS_330) {
179       int watchdog;
180       if(pSiS->ChipType >= SIS_340) {
181          outSISIDXREG(SISCR, 0x57, 0x4a);
182       } else {
183          outSISIDXREG(SISCR, 0x57, 0x5f);
184       }
185       orSISIDXREG(SISCR, 0x53, 0x02);
186       watchdog = 655360;
187       while((!((inSISREG(SISINPSTAT)) & 0x01)) && --watchdog);
188       watchdog = 655360;
189       while(((inSISREG(SISINPSTAT)) & 0x01) && --watchdog);
190       if((inSISREG(SISMISCW)) & 0x10) temp = 1;
191       andSISIDXREG(SISCR, 0x53, 0xfd);
192       outSISIDXREG(SISCR, 0x57, 0x00);
193#ifdef TWDEBUG
194       xf86DrvMsg(0, X_INFO, "330: Found CRT1: %s\n", (temp == 1) ? "yes" : "no");
195#endif
196    }
197
198    if((temp == 0xffff) && (!pSiS->SiS_Pr->DDCPortMixup)) {
199       i = 3;
200       do {
201          temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 0, 0, NULL, pSiS->VBFlags2);
202       } while(((temp == 0) || (temp == 0xffff)) && i--);
203
204       if((temp == 0) || (temp == 0xffff)) {
205          if(TestDDC1(pScrn)) temp = 1;
206       }
207    }
208
209    if((temp) && (temp != 0xffff)) {
210       orSISIDXREG(SISCR,0x32,0x20);
211       ret = 1;
212    } else if(pSiS->ChipType >= SIS_330) {
213       andSISIDXREG(SISCR,0x32,~0x20);
214       ret = 0;
215    }
216
217    if(pSiS->VGAEngine == SIS_315_VGA) {
218       setSISIDXREG(SISCR,pSiS->myCR63,0xBF,CR63);
219    }
220
221    setSISIDXREG(SISCR,0x17,0x7F,CR17);
222
223    outSISIDXREG(SISSR,0x1F,SR1F);
224
225    return ret;
226}
227
228/* Detect CRT1 */
229void SISCRT1PreInit(ScrnInfoPtr pScrn)
230{
231    SISPtr  pSiS = SISPTR(pScrn);
232    UChar CR32;
233    UChar OtherDevices = 0;
234
235    pSiS->CRT1Detected = FALSE;
236
237    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) {
238       pSiS->CRT1Detected = TRUE;
239       pSiS->CRT1off = 0;
240       return;
241    }
242
243#ifdef SISDUALHEAD
244    if(pSiS->DualHeadMode) {
245       pSiS->CRT1Detected = TRUE;
246       pSiS->CRT1off = 0;
247       return;
248    }
249#endif
250
251#ifdef SISMERGED
252    if((pSiS->MergedFB) && (!(pSiS->MergedFBAuto))) {
253       pSiS->CRT1Detected = TRUE;
254       pSiS->CRT1off = 0;
255       return;
256    }
257#endif
258
259    inSISIDXREG(SISCR, 0x32, CR32);
260
261    if(pSiS->ChipType >= SIS_330) {
262       /* Works reliably on 330 and later */
263       pSiS->CRT1Detected = SiS_SISDetectCRT1(pScrn);
264    } else {
265       if(CR32 & 0x20) pSiS->CRT1Detected = TRUE;
266       else            pSiS->CRT1Detected = SiS_SISDetectCRT1(pScrn);
267    }
268
269    if(CR32 & 0x5F) OtherDevices = 1;
270
271    if(pSiS->CRT1off == -1) {
272       if(!pSiS->CRT1Detected) {
273
274	  /* No CRT1 detected. */
275	  /* If other devices exist, switch it off */
276	  if(OtherDevices) pSiS->CRT1off = 1;
277	  else             pSiS->CRT1off = 0;
278
279       } else {
280
281	  /* CRT1 detected, leave/switch it on */
282	  pSiS->CRT1off = 0;
283
284       }
285    }
286
287    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
288		"%sCRT1/VGA detected\n",
289		pSiS->CRT1Detected ? "" : "No ");
290}
291
292/* Detect CRT2-LCD and LCD size */
293void SISLCDPreInit(ScrnInfoPtr pScrn, Bool quiet)
294{
295    SISPtr  pSiS = SISPTR(pScrn);
296    UChar CR32, CR36, CR37, CR7D=0, tmp;
297
298    pSiS->VBFlags &= ~(CRT2_LCD);
299    pSiS->VBLCDFlags = 0;
300    pSiS->LCDwidth   = 0;
301    pSiS->LCDheight  = 0;
302
303    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return;
304
305    inSISIDXREG(SISCR, 0x32, CR32);
306
307    if(CR32 & 0x08) pSiS->VBFlags |= CRT2_LCD;
308
309    /* If no panel has been detected by the BIOS during booting,
310     * we try to detect it ourselves at this point. We do that
311     * if forcecrt2redetection was given, too.
312     * This is useful on machines with DVI connectors where the
313     * panel was connected after booting. This is only supported
314     * on the 315/330 series and the 301/30xB/C bridge (because the
315     * 30xLV don't seem to have a DDC port and operate only LVDS
316     * panels which mostly don't support DDC). We only do this if
317     * there was no secondary VGA detected by the BIOS, because LCD
318     * and VGA2 share the same DDC channel and might be misdetected
319     * as the wrong type (especially if the LCD panel only supports
320     * EDID Version 1).
321     * Addendum: For DVI-I connected panels, this is not ideal.
322     * Therefore, we disregard an eventually detected secondary
323     * VGA if the user forced CRT2 type to LCD.
324     *
325     * By default, CRT2 redetection is forced since 12/09/2003, as
326     * I encountered numerous panels which deliver more or less
327     * bogus DDC data confusing the BIOS. Since our DDC detection
328     * is waaaay better, we prefer it instead of the primitive
329     * and buggy BIOS method.
330     *
331     */
332#ifdef SISDUALHEAD
333    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
334#endif
335       if((pSiS->VGAEngine == SIS_315_VGA) &&
336	  (pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) &&
337	  (!(pSiS->VBFlags2 & VB2_30xBDH)) &&
338	  (pSiS->VESA != 1)) {
339
340	  if(pSiS->forcecrt2redetection) {
341	     pSiS->VBFlags &= ~CRT2_LCD;
342	     /* Do NOT clear CR32[D3] here! */
343	  }
344
345	  if(!(pSiS->nocrt2ddcdetection)) {
346	     if((!(pSiS->VBFlags & CRT2_LCD)) &&
347			( (!(CR32 & 0x10)) ||
348			  (pSiS->ForceCRT2Type == CRT2_LCD) ) ) {
349		if(!quiet) {
350		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
351		      "%s LCD/plasma panel, sensing via DDC\n",
352		      pSiS->forcecrt2redetection ?
353		         "(Re)-detecting" : "BIOS detected no");
354		}
355		if(SiS_SenseLCDDDC(pSiS->SiS_Pr, pSiS)) {
356		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
357		      "DDC error during LCD panel detection\n");
358		} else {
359		   inSISIDXREG(SISCR, 0x32, CR32);
360		   if(CR32 & 0x08) {
361		      pSiS->VBFlags |= CRT2_LCD;
362		      pSiS->postVBCR32 |= 0x08;
363		   } else {
364		      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
365			   "No LCD/plasma panel detected\n");
366		   }
367		}
368	     }
369	  }
370
371       }
372#ifdef SISDUALHEAD
373    }
374#endif
375
376    if(pSiS->VBFlags & CRT2_LCD) {
377       inSISIDXREG(SISCR, 0x36, CR36);
378       if(pSiS->VGAEngine == SIS_300_VGA) {
379	  if(pSiS->VBFlags2 & VB2_301) {
380	     if((CR36 & 0x0f) < 0x0f) CR36 &= 0xf7;
381	  }
382       }
383       if(pSiS->PRGB != -1) {
384	  tmp = 0x37;
385	  if((pSiS->VGAEngine == SIS_315_VGA) &&
386	     (pSiS->ChipType < SIS_661)       &&
387	     (pSiS->ROM661New)                &&
388	     (!(pSiS->SiS_Pr->PanelSelfDetected))) {
389	     tmp = 0x35;
390	  }
391	  if(pSiS->PRGB == 18)      orSISIDXREG(SISCR, tmp, 0x01);
392	  else if(pSiS->PRGB == 24) andSISIDXREG(SISCR, tmp, 0xfe);
393       }
394       inSISIDXREG(SISCR, 0x37, CR37);
395       if(pSiS->ChipType < SIS_661) {
396	  inSISIDXREG(SISCR, 0x3C, CR7D);
397       } else {
398	  inSISIDXREG(SISCR, 0x7D, CR7D);
399       }
400       if(pSiS->SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
401	  pSiS->VBLCDFlags |= VB_LCD_BARCO1366;
402	  pSiS->LCDwidth = 1360;
403	  pSiS->LCDheight = 1024;
404	  if(CR37 & 0x10) pSiS->VBLCDFlags |= VB_LCD_EXPANDING;
405	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
406		"Detected LCD panel (%dx%d, type %d, %sexpanding, RGB%d)\n",
407		pSiS->LCDwidth, pSiS->LCDheight,
408		((CR36 & 0xf0) >> 4),
409		(CR37 & 0x10) ? "" : "non-",
410		(CR37 & 0x01) ? 18 : 24);
411       } else if(pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL848) {
412	  pSiS->VBLCDFlags |= VB_LCD_848x480;
413	  pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX = 848;
414	  pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY = 480;
415	  pSiS->VBLCDFlags |= VB_LCD_EXPANDING;
416	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
417		"Assuming LCD/plasma panel (848x480, expanding, RGB24)\n");
418       } else if(pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL856) {
419	  pSiS->VBLCDFlags |= VB_LCD_856x480;
420	  pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX = 856;
421	  pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY = 480;
422	  pSiS->VBLCDFlags |= VB_LCD_EXPANDING;
423	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
424		"Assuming LCD/plasma panel (856x480, expanding, RGB24)\n");
425       } else if(pSiS->FSTN) {
426	  pSiS->VBLCDFlags |= VB_LCD_320x240;
427	  pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX = 320;
428	  pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY = 240;
429	  pSiS->VBLCDFlags &= ~VB_LCD_EXPANDING;
430	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
431		"Assuming FSTN LCD panel (320x240, non-expanding)\n");
432       } else {
433	  if(CR36 == 0) {
434	     /* Old 650/301LV and ECS A907 BIOS versions "forget" to set CR36, CR37 */
435	     if(pSiS->VGAEngine == SIS_315_VGA) {
436		if(pSiS->ChipType < SIS_661) {
437		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
438		      "BIOS provided invalid panel size, probing...\n");
439		   if(pSiS->VBFlags2 & VB2_LVDS) pSiS->SiS_Pr->SiS_IF_DEF_LVDS = 1;
440		   else pSiS->SiS_Pr->SiS_IF_DEF_LVDS = 0;
441		   SiS_GetPanelID(pSiS->SiS_Pr);
442		   inSISIDXREG(SISCR, 0x36, CR36);
443		   inSISIDXREG(SISCR, 0x37, CR37);
444		} else {
445		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
446		      "Broken BIOS, unable to determine panel size, disabling LCD\n");
447		   pSiS->VBFlags &= ~CRT2_LCD;
448		   return;
449		}
450	     } else if(pSiS->VGAEngine == SIS_300_VGA) {
451		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
452		   "BIOS provided invalid panel size, assuming 1024x768, RGB18\n");
453		setSISIDXREG(SISCR,0x36,0xf0,0x02);
454		setSISIDXREG(SISCR,0x37,0xee,0x01);
455		CR36 = 0x02;
456		inSISIDXREG(SISCR,0x37,CR37);
457	     }
458	  }
459	  if((CR36 & 0x0f) == 0x0f) {
460	     pSiS->VBLCDFlags |= VB_LCD_CUSTOM;
461	     pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY;
462	     pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX;
463	     if(CR37 & 0x10) pSiS->VBLCDFlags |= VB_LCD_EXPANDING;
464	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
465		"Detected LCD/Plasma panel (max. X %d Y %d, pref. %dx%d, RGB%d)\n",
466		pSiS->SiS_Pr->CP_MaxX, pSiS->SiS_Pr->CP_MaxY,
467		pSiS->SiS_Pr->CP_PreferredX, pSiS->SiS_Pr->CP_PreferredY,
468		(CR37 & 0x01) ? 18 : 24);
469	  } else {
470	     if(pSiS->VGAEngine == SIS_300_VGA) {
471		pSiS->VBLCDFlags |= SiS300_LCD_Type[(CR36 & 0x0f)].VBLCD_lcdflag;
472		pSiS->LCDheight = SiS300_LCD_Type[(CR36 & 0x0f)].LCDheight;
473		pSiS->LCDwidth = SiS300_LCD_Type[(CR36 & 0x0f)].LCDwidth;
474		if(CR37 & 0x10) pSiS->VBLCDFlags |= VB_LCD_EXPANDING;
475	     } else if((pSiS->ChipType >= SIS_661) || (pSiS->ROM661New)) {
476		pSiS->VBLCDFlags |= SiS661_LCD_Type[(CR36 & 0x0f)].VBLCD_lcdflag;
477		pSiS->LCDheight = SiS661_LCD_Type[(CR36 & 0x0f)].LCDheight;
478		pSiS->LCDwidth = SiS661_LCD_Type[(CR36 & 0x0f)].LCDwidth;
479		if(CR37 & 0x10) pSiS->VBLCDFlags |= VB_LCD_EXPANDING;
480		if(pSiS->ChipType < SIS_661) {
481		   if(!(pSiS->SiS_Pr->PanelSelfDetected)) {
482		      inSISIDXREG(SISCR,0x35,tmp);
483		      CR37 &= 0xfc;
484		      CR37 |= (tmp & 0x01);
485		   }
486		}
487	     } else {
488		pSiS->VBLCDFlags |= SiS315_LCD_Type[(CR36 & 0x0f)].VBLCD_lcdflag;
489		pSiS->LCDheight = SiS315_LCD_Type[(CR36 & 0x0f)].LCDheight;
490		pSiS->LCDwidth = SiS315_LCD_Type[(CR36 & 0x0f)].LCDwidth;
491		if(CR37 & 0x10) pSiS->VBLCDFlags |= VB_LCD_EXPANDING;
492	     }
493	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
494			"Detected LCD/plasma panel (%dx%d, %d, %sexp., RGB%d [%02x%02x%02x])\n",
495			pSiS->LCDwidth, pSiS->LCDheight,
496			((pSiS->VGAEngine == SIS_315_VGA) && (!pSiS->ROM661New)) ?
497			 	((CR36 & 0x0f) - 1) : ((CR36 & 0xf0) >> 4),
498			(CR37 & 0x10) ? "" : "non-",
499			(CR37 & 0x01) ? 18 : 24,
500			CR36, CR37, CR7D);
501	  }
502       }
503    }
504}
505
506void SiSSetupPseudoPanel(ScrnInfoPtr pScrn)
507{
508    SISPtr pSiS = SISPTR(pScrn);
509    int i;
510
511    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
512	"No LCD detected, but forced to enable digital output\n");
513    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
514    	"Will not be able to properly filter display modes!\n");
515
516    pSiS->VBFlags |= CRT2_LCD;
517    pSiS->SiS_Pr->SiS_CustomT = CUT_UNKNOWNLCD;
518    pSiS->SiS_Pr->CP_PrefClock = 0;
519    pSiS->SiS_Pr->CP_PreferredIndex = -1;
520    pSiS->VBLCDFlags |= (VB_LCD_UNKNOWN | VB_LCD_EXPANDING);
521    pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX = 2048;
522    pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY = 2048;
523    for(i=0; i<7; i++) pSiS->SiS_Pr->CP_DataValid[i] = FALSE;
524    pSiS->SiS_Pr->CP_HaveCustomData = FALSE;
525    pSiS->SiS_Pr->PanelSelfDetected = TRUE;
526    outSISIDXREG(SISCR,0x36,0x0f);
527    setSISIDXREG(SISCR,0x37,0x0e,0x10);
528    orSISIDXREG(SISCR,0x32,0x08);
529}
530
531/* Detect CRT2-TV connector type and PAL/NTSC flag */
532void SISTVPreInit(ScrnInfoPtr pScrn, Bool quiet)
533{
534    SISPtr pSiS = SISPTR(pScrn);
535    UChar SR16, SR38, CR32, CR35=0, CR38=0, CR79, CR39;
536    int temp = 0;
537
538    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return;
539
540    inSISIDXREG(SISCR, 0x32, CR32);
541    inSISIDXREG(SISCR, 0x35, CR35);
542    inSISIDXREG(SISSR, 0x16, SR16);
543    inSISIDXREG(SISSR, 0x38, SR38);
544    switch(pSiS->VGAEngine) {
545    case SIS_300_VGA:
546       if(pSiS->Chipset == PCI_CHIP_SIS630) temp = 0x35;
547       break;
548    case SIS_315_VGA:
549       temp = 0x38;
550       break;
551    }
552    if(temp) {
553       inSISIDXREG(SISCR, temp, CR38);
554    }
555
556#ifdef TWDEBUG
557    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
558    	"(vb.c: SISTVPreInit 1: CR32=%02x SR16=%02x SR38=%02x VBFlags 0x%x)\n",
559	CR32, SR16, SR38, pSiS->VBFlags);
560#endif
561
562    if(CR32 & 0x47) pSiS->VBFlags |= CRT2_TV;
563
564    if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
565       if(CR32 & 0x80) pSiS->VBFlags |= CRT2_TV;
566    } else {
567       CR32 &= 0x7f;
568    }
569
570    if(CR32 & 0x01)
571       pSiS->VBFlags |= TV_AVIDEO;
572    else if(CR32 & 0x02)
573       pSiS->VBFlags |= TV_SVIDEO;
574    else if(CR32 & 0x04)
575       pSiS->VBFlags |= TV_SCART;
576    else if((CR32 & 0x40) && (pSiS->SiS_SD_Flags & SiS_SD_SUPPORTHIVISION))
577       pSiS->VBFlags |= (TV_HIVISION | TV_PAL);
578    else if((CR32 & 0x80) && (pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR)) {
579       pSiS->VBFlags |= TV_YPBPR;
580       if(pSiS->NewCRLayout) {
581          if(CR38 & 0x04) {
582             switch(CR35 & 0xE0) {
583             case 0x20: pSiS->VBFlags |= TV_YPBPR525P; break;
584	     case 0x40: pSiS->VBFlags |= TV_YPBPR750P; break;
585	     case 0x60: pSiS->VBFlags |= TV_YPBPR1080I; break;
586	     default:   pSiS->VBFlags |= TV_YPBPR525I;
587	     }
588          } else        pSiS->VBFlags |= TV_YPBPR525I;
589          inSISIDXREG(SISCR,0x39,CR39);
590	  CR39 &= 0x03;
591	  if(CR39 == 0x00)      pSiS->VBFlags |= TV_YPBPR43LB;
592	  else if(CR39 == 0x01) pSiS->VBFlags |= TV_YPBPR43;
593	  else if(CR39 == 0x02) pSiS->VBFlags |= TV_YPBPR169;
594	  else			pSiS->VBFlags |= TV_YPBPR43;
595       } else if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
596          if(CR38 & 0x08) {
597	     switch(CR38 & 0x30) {
598	     case 0x10: pSiS->VBFlags |= TV_YPBPR525P; break;
599	     case 0x20: pSiS->VBFlags |= TV_YPBPR750P; break;
600	     case 0x30: pSiS->VBFlags |= TV_YPBPR1080I; break;
601	     default:   pSiS->VBFlags |= TV_YPBPR525I;
602	     }
603	  } else        pSiS->VBFlags |= TV_YPBPR525I;
604	  if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPRAR) {
605             inSISIDXREG(SISCR,0x3B,CR39);
606	     CR39 &= 0x03;
607	     if(CR39 == 0x00)      pSiS->VBFlags |= TV_YPBPR43LB;
608	     else if(CR39 == 0x01) pSiS->VBFlags |= TV_YPBPR169;
609	     else if(CR39 == 0x03) pSiS->VBFlags |= TV_YPBPR43;
610	  }
611       }
612    } else if((CR38 & 0x04) && (pSiS->VBFlags2 & VB2_CHRONTEL))
613       pSiS->VBFlags |= (TV_CHSCART | TV_PAL);
614    else if((CR38 & 0x08) && (pSiS->VBFlags2 & VB2_CHRONTEL))
615       pSiS->VBFlags |= (TV_CHYPBPR525I | TV_NTSC);
616
617    if(pSiS->VBFlags & (TV_SCART | TV_SVIDEO | TV_AVIDEO)) {
618       if(pSiS->VGAEngine == SIS_300_VGA) {
619	  /* Should be SR38, but this does not work. */
620	  if(SR16 & 0x20)
621	     pSiS->VBFlags |= TV_PAL;
622          else
623	     pSiS->VBFlags |= TV_NTSC;
624       } else if(pSiS->Chipset == PCI_CHIP_SIS550) {
625          inSISIDXREG(SISCR, 0x7a, CR79);
626	  if(CR79 & 0x08) {
627             inSISIDXREG(SISCR, 0x79, CR79);
628	     CR79 >>= 5;
629	  }
630	  if(CR79 & 0x01) {
631             pSiS->VBFlags |= TV_PAL;
632	     if(CR38 & 0x40)      pSiS->VBFlags |= TV_PALM;
633	     else if(CR38 & 0x80) pSiS->VBFlags |= TV_PALN;
634 	  } else
635	     pSiS->VBFlags |= TV_NTSC;
636       } else if(pSiS->Chipset == PCI_CHIP_SIS650) {
637	  inSISIDXREG(SISCR, 0x79, CR79);
638	  if(CR79 & 0x20) {
639             pSiS->VBFlags |= TV_PAL;
640	     if(CR38 & 0x40)      pSiS->VBFlags |= TV_PALM;
641	     else if(CR38 & 0x80) pSiS->VBFlags |= TV_PALN;
642 	  } else
643	     pSiS->VBFlags |= TV_NTSC;
644       } else if(pSiS->NewCRLayout) {
645          if(SR38 & 0x01) {
646	     pSiS->VBFlags |= TV_PAL;
647	     if(CR35 & 0x04)      pSiS->VBFlags |= TV_PALM;
648	     else if(CR35 & 0x08) pSiS->VBFlags |= TV_PALN;
649	  } else {
650	     pSiS->VBFlags |= TV_NTSC;
651	     if(CR35 & 0x02)      pSiS->VBFlags |= TV_NTSCJ;
652	  }
653       } else {	/* 315, 330 */
654	  if(SR38 & 0x01) {
655             pSiS->VBFlags |= TV_PAL;
656	     if(CR38 & 0x40)      pSiS->VBFlags |= TV_PALM;
657	     else if(CR38 & 0x80) pSiS->VBFlags |= TV_PALN;
658 	  } else
659	     pSiS->VBFlags |= TV_NTSC;
660       }
661    }
662
663#ifdef TWDEBUG
664    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
665    	"(vb.c: SISTVPreInit 2: VBFlags 0x%x)\n", pSiS->VBFlags);
666#endif
667
668    if((pSiS->VBFlags & (TV_SCART|TV_SVIDEO|TV_AVIDEO)) && !quiet) {
669       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected default TV standard %s\n",
670          (pSiS->VBFlags & TV_NTSC) ?
671	     ((pSiS->VBFlags & TV_NTSCJ) ? "NTSCJ" : "NTSC") :
672	         ((pSiS->VBFlags & TV_PALM) ? "PALM" :
673		     ((pSiS->VBFlags & TV_PALN) ? "PALN" : "PAL")));
674    }
675
676    if((pSiS->VBFlags & TV_HIVISION) && !quiet) {
677       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "BIOS reports HiVision TV\n");
678    }
679
680    if((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & (TV_CHSCART|TV_CHYPBPR525I)) && !quiet) {
681       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Chrontel: %s forced\n",
682       	(pSiS->VBFlags & TV_CHSCART) ? "SCART (PAL)" : "YPbPr (480i)");
683    }
684
685    if((pSiS->VBFlags & TV_YPBPR) && !quiet) {
686       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected YPbPr TV (by default %s)\n",
687         (pSiS->VBFlags & TV_YPBPR525I) ? "480i" :
688	     ((pSiS->VBFlags & TV_YPBPR525P) ? "480p" :
689	        ((pSiS->VBFlags & TV_YPBPR750P) ? "720p" : "1080i")));
690    }
691}
692
693/* Detect CRT2-VGA */
694void SISCRT2PreInit(ScrnInfoPtr pScrn, Bool quiet)
695{
696    SISPtr pSiS = SISPTR(pScrn);
697    UChar CR32;
698
699    /* CRT2-VGA only supported on these bridges */
700    if(!(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE))
701       return;
702
703    inSISIDXREG(SISCR, 0x32, CR32);
704
705    if(CR32 & 0x10) pSiS->VBFlags |= CRT2_VGA;
706
707    /* See the comment in initextx.c/SiS_SenseVGA2DDC() */
708    if(pSiS->SiS_Pr->DDCPortMixup) return;
709
710#ifdef SISDUALHEAD
711    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
712#endif
713
714       if(pSiS->forcecrt2redetection) {
715          pSiS->VBFlags &= ~CRT2_VGA;
716       }
717
718       /* We don't trust the normal sensing method for VGA2 since
719        * it is performed by the BIOS during POST, and it is
720        * impossible to sense VGA2 if the bridge is disabled.
721        * Therefore, we try sensing VGA2 by DDC as well (if not
722        * detected otherwise and only if there is no LCD panel
723        * which is prone to be misdetected as a secondary VGA)
724        */
725       if(!(pSiS->nocrt2ddcdetection)) {
726          if(!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD))) {
727	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
728	         "%s secondary VGA, sensing via DDC\n",
729	         pSiS->forcecrt2redetection ?
730		      "Forced re-detection of" : "BIOS detected no");
731             if(SiS_SenseVGA2DDC(pSiS->SiS_Pr, pSiS)) {
732    	        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
733	              "DDC error during secondary VGA detection\n");
734	     } else {
735	        inSISIDXREG(SISCR, 0x32, CR32);
736	        if(CR32 & 0x10) {
737	           pSiS->VBFlags |= CRT2_VGA;
738	           pSiS->postVBCR32 |= 0x10;
739		   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
740		         "Detected secondary VGA connection\n");
741	        } else {
742	           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
743		         "No secondary VGA connection detected\n");
744	        }
745	     }
746          }
747       }
748#ifdef SISDUALHEAD
749    }
750#endif
751}
752
753static int
754SISDoSense(ScrnInfoPtr pScrn, UShort type, UShort test)
755{
756    SISPtr pSiS = SISPTR(pScrn);
757    int    temp, mytest, result, i, j;
758
759#ifdef TWDEBUG
760    xf86DrvMsg(0, X_INFO, "Sense: %x %x\n", type, test);
761#endif
762
763    for(j = 0; j < 10; j++) {
764       result = 0;
765       for(i = 0; i < 3; i++) {
766          mytest = test;
767          outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
768          temp = (type >> 8) | (mytest & 0x00ff);
769          setSISIDXREG(SISPART4,0x10,0xe0,temp);
770          SiS_DDC2Delay(pSiS->SiS_Pr, 0x1500);
771          mytest >>= 8;
772          mytest &= 0x7f;
773          inSISIDXREG(SISPART4,0x03,temp);
774          temp ^= 0x0e;
775          temp &= mytest;
776          if(temp == mytest) result++;
777#if 1
778	  outSISIDXREG(SISPART4,0x11,0x00);
779	  andSISIDXREG(SISPART4,0x10,0xe0);
780	  SiS_DDC2Delay(pSiS->SiS_Pr, 0x1000);
781#endif
782       }
783       if((result == 0) || (result >= 2)) break;
784    }
785    return(result);
786}
787
788#define GETROMWORD(w) (pSiS->BIOS[w] | (pSiS->BIOS[w+1] << 8))
789
790/* Sense connected devices on 30x */
791void
792SISSense30x(ScrnInfoPtr pScrn, Bool quiet)
793{
794    SISPtr pSiS = SISPTR(pScrn);
795    UChar  backupP4_0d, backupP2_00, backupP2_4d, backupSR_1e, biosflag=0;
796    UShort svhs=0, svhs_c=0;
797    UShort cvbs=0, cvbs_c=0;
798    UShort vga2=0, vga2_c=0;
799    int    myflag, result; /* , i; */
800
801    if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
802
803#ifdef TWDEBUG
804    inSISIDXREG(SISCR,0x32,backupP2_4d);
805    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
806    	"(vb.c: SISSense30c 1: CR32=%02x, VBFlags 0x%x)\n", backupP2_4d, pSiS->VBFlags);
807#endif
808
809    if(pSiS->VBFlags2 & VB2_301) {
810       svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
811       inSISIDXREG(SISPART4,0x01,myflag);
812       if(myflag & 0x04) {
813	  svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
814       }
815    } else if(pSiS->VBFlags2 & (VB2_301B | VB2_302B)) {
816       svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
817    } else if(pSiS->VBFlags2 & (VB2_301LV | VB2_302LV)) {
818       svhs = 0x0200; cvbs = 0x0100;
819    } else if(pSiS->VBFlags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
820       svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
821    } else return;
822
823    vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
824    if(pSiS->VBFlags2 & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
825       svhs_c = 0x0408; cvbs_c = 0x0808;
826    }
827    biosflag = 2;
828
829    if(pSiS->Chipset == PCI_CHIP_SIS300) {
830       inSISIDXREG(SISSR,0x3b,myflag);
831       if(!(myflag & 0x01)) vga2 = vga2_c = 0;
832    }
833
834    if(pSiS->SiS_Pr->UseROM) {
835       if(pSiS->VGAEngine == SIS_300_VGA) {
836	  if(pSiS->VBFlags2 & VB2_301) {
837	     inSISIDXREG(SISPART4,0x01,myflag);
838	     if(!(myflag & 0x04)) {
839		vga2 = GETROMWORD(0xf8); svhs = GETROMWORD(0xfa); cvbs = GETROMWORD(0xfc);
840	     }
841	  }
842	  biosflag = pSiS->BIOS[0xfe];
843       } else if((pSiS->Chipset == PCI_CHIP_SIS660) ||
844	         (pSiS->Chipset == PCI_CHIP_SIS340)) {
845	  if(pSiS->ROM661New) {
846	     biosflag = 2;
847	     vga2 = GETROMWORD(0x63);
848	     if(pSiS->BIOS[0x6f] & 0x01) {
849	        if(pSiS->VBFlags2 & VB2_SISUMC) vga2 = GETROMWORD(0x4d);
850	     }
851	     svhs = cvbs = GETROMWORD(0x65);
852	     if(pSiS->BIOS[0x5d] & 0x04) biosflag |= 0x01;
853	  }
854       }
855       /* No "else", some BIOSes carry wrong data */
856    }
857
858    if(pSiS->ChipType >= XGI_20) {
859       if(pSiS->HaveXGIBIOS) {
860          biosflag = pSiS->BIOS[0x58] & 0x03;
861       } else {
862          /* These boards have a s-video connector, but its
863	   * pins are routed both the bridge's composite and
864	   * svideo pins. This is for using the S-video plug
865	   * for YPbPr output. Anyway, since a svideo connected
866	   * TV would also been detected as a composite connected
867	   * one, we don't check for composite if svideo is
868	   * detected.
869	   */
870	   biosflag &= ~0x02;
871       }
872    }
873
874    if(!(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
875       vga2 = vga2_c = 0;
876    }
877
878    inSISIDXREG(SISSR,0x1e,backupSR_1e);
879    orSISIDXREG(SISSR,0x1e,0x20);
880
881    inSISIDXREG(SISPART4,0x0d,backupP4_0d);
882    if(pSiS->VBFlags2 & VB2_30xCLV) {
883       setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
884    } else {
885       orSISIDXREG(SISPART4,0x0d,0x04);
886    }
887    SiS_DDC2Delay(pSiS->SiS_Pr, 0x2000);
888
889    inSISIDXREG(SISPART2,0x00,backupP2_00);
890    outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
891
892    inSISIDXREG(SISPART2,0x4d,backupP2_4d);
893    if(pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE) {
894       outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
895    }
896
897    if(!(pSiS->VBFlags2 & VB2_30xCLV)) {
898       SISDoSense(pScrn, 0, 0);
899    }
900
901    andSISIDXREG(SISCR, 0x32, ~0x14);
902    pSiS->postVBCR32 &= ~0x14;
903
904    if(vga2_c || vga2) {
905       if(SISDoSense(pScrn, vga2, vga2_c)) {
906	  if(biosflag & 0x01) {
907	     if(!quiet) {
908	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
909		    "SiS30x: Detected TV connected to SCART output\n");
910	     }
911	     pSiS->VBFlags |= TV_SCART;
912	     orSISIDXREG(SISCR, 0x32, 0x04);
913	     pSiS->postVBCR32 |= 0x04;
914	  } else {
915	     if(!quiet) {
916	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
917		    "SiS30x: Detected secondary VGA connection\n");
918	     }
919	     pSiS->VBFlags |= VGA2_CONNECTED;
920	     orSISIDXREG(SISCR, 0x32, 0x10);
921	     pSiS->postVBCR32 |= 0x10;
922	  }
923       }
924       if(biosflag & 0x01) pSiS->SiS_SD_Flags |= SiS_SD_VBHASSCART;
925    }
926
927    andSISIDXREG(SISCR, 0x32, 0x3f);
928    pSiS->postVBCR32 &= 0x3f;
929
930    if(pSiS->VBFlags2 & VB2_30xCLV) {
931       orSISIDXREG(SISPART4,0x0d,0x04);
932    }
933
934    if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE)) {
935       if(pSiS->SenseYPbPr) {
936	  outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
937	  SiS_DDC2Delay(pSiS->SiS_Pr, 0x2000);
938	  /* New BIOS (2.x) uses vga2 sensing here for all bridges >301LV */
939	  if((result = SISDoSense(pScrn, svhs, 0x0604))) {
940	     if((result = SISDoSense(pScrn, cvbs, 0x0804))) {
941		if(!quiet) {
942		   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
943			"SiS30x: Detected TV connected to YPbPr component output\n");
944		}
945		orSISIDXREG(SISCR,0x32,0x80);
946		pSiS->VBFlags |= TV_YPBPR;
947		pSiS->postVBCR32 |= 0x80;
948	     }
949	  }
950	  outSISIDXREG(SISPART2,0x4d,backupP2_4d);
951       }
952    }
953
954    andSISIDXREG(SISCR, 0x32, ~0x03);
955    pSiS->postVBCR32 &= ~0x03;
956
957    if(!(pSiS->VBFlags & TV_YPBPR)) {
958
959       if((result = SISDoSense(pScrn, svhs, svhs_c))) {
960	  if(!quiet) {
961	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
962		  "SiS30x: Detected TV connected to SVIDEO output\n");
963	  }
964	  pSiS->VBFlags |= TV_SVIDEO;
965	  orSISIDXREG(SISCR, 0x32, 0x02);
966	  pSiS->postVBCR32 |= 0x02;
967       }
968
969       if((biosflag & 0x02) || (!result)) {
970	  if(SISDoSense(pScrn, cvbs, cvbs_c)) {
971	     if(!quiet) {
972	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
973	             "SiS30x: Detected TV connected to COMPOSITE output\n");
974	     }
975	     pSiS->VBFlags |= TV_AVIDEO;
976	     orSISIDXREG(SISCR, 0x32, 0x01);
977	     pSiS->postVBCR32 |= 0x01;
978	  }
979       }
980
981    }
982
983    SISDoSense(pScrn, 0, 0);
984
985    outSISIDXREG(SISPART2,0x00,backupP2_00);
986    outSISIDXREG(SISPART4,0x0d,backupP4_0d);
987    outSISIDXREG(SISSR,0x1e,backupSR_1e);
988
989    if(pSiS->VBFlags2 & VB2_30xCLV) {
990       inSISIDXREG(SISPART2,0x00,biosflag);
991       if(biosflag & 0x20) {
992          for(myflag = 2; myflag > 0; myflag--) {
993	     biosflag ^= 0x20;
994	     outSISIDXREG(SISPART2,0x00,biosflag);
995	  }
996       }
997    }
998
999    outSISIDXREG(SISPART2,0x00,backupP2_00);
1000
1001#ifdef TWDEBUG
1002    inSISIDXREG(SISCR,0x32,backupP2_4d);
1003    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1004    	"(vb.c: SISSense30c 2: CR32=0x%02x, VBFlags 0x%x)\n", backupP2_4d, pSiS->VBFlags);
1005#endif
1006}
1007
1008void
1009SISSenseChrontel(ScrnInfoPtr pScrn, Bool quiet)
1010{
1011    SISPtr  pSiS = SISPTR(pScrn);
1012    int     temp1=0, temp2, i;
1013    UChar test[3];
1014
1015    if(pSiS->SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
1016
1017       /* Chrontel 700x */
1018
1019       /* Read power status */
1020       temp1 = SiS_GetCH700x(pSiS->SiS_Pr, 0x0e);  /* Power status */
1021       if((temp1 & 0x03) != 0x03) {
1022	  /* Power all outputs */
1023	  SiS_SetCH700x(pSiS->SiS_Pr, 0x0e,0x0b);
1024	  SiS_DDC2Delay(pSiS->SiS_Pr, 0x96);
1025       }
1026       /* Sense connected TV devices */
1027       for(i = 0; i < 3; i++) {
1028	  SiS_SetCH700x(pSiS->SiS_Pr, 0x10, 0x01);
1029	  SiS_DDC2Delay(pSiS->SiS_Pr, 0x96);
1030	  SiS_SetCH700x(pSiS->SiS_Pr, 0x10, 0x00);
1031	  SiS_DDC2Delay(pSiS->SiS_Pr, 0x96);
1032	  temp1 = SiS_GetCH700x(pSiS->SiS_Pr, 0x10);
1033	  if(!(temp1 & 0x08))       test[i] = 0x02;
1034	  else if(!(temp1 & 0x02))  test[i] = 0x01;
1035	  else                      test[i] = 0;
1036	  SiS_DDC2Delay(pSiS->SiS_Pr, 0x96);
1037       }
1038
1039       if(test[0] == test[1])      temp1 = test[0];
1040       else if(test[0] == test[2]) temp1 = test[0];
1041       else if(test[1] == test[2]) temp1 = test[1];
1042       else {
1043	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1044	        "Chrontel: TV detection unreliable - test results varied\n");
1045	  temp1 = test[2];
1046       }
1047
1048    } else if(pSiS->SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
1049
1050       /* Chrontel 701x */
1051
1052       /* Backup Power register */
1053       temp1 = SiS_GetCH701x(pSiS->SiS_Pr, 0x49);
1054
1055       /* Enable TV path */
1056       SiS_SetCH701x(pSiS->SiS_Pr, 0x49, 0x20);
1057
1058       SiS_DDC2Delay(pSiS->SiS_Pr, 0x96);
1059
1060       /* Sense connected TV devices */
1061       temp2 = SiS_GetCH701x(pSiS->SiS_Pr, 0x20);
1062       temp2 |= 0x01;
1063       SiS_SetCH701x(pSiS->SiS_Pr, 0x20, temp2);
1064
1065       SiS_DDC2Delay(pSiS->SiS_Pr, 0x96);
1066
1067       temp2 ^= 0x01;
1068       SiS_SetCH701x(pSiS->SiS_Pr, 0x20, temp2);
1069
1070       SiS_DDC2Delay(pSiS->SiS_Pr, 0x96);
1071
1072       temp2 = SiS_GetCH701x(pSiS->SiS_Pr, 0x20);
1073
1074       /* Restore Power register */
1075       SiS_SetCH701x(pSiS->SiS_Pr, 0x49, temp1);
1076
1077       temp1 = 0;
1078       if(temp2 & 0x02) temp1 |= 0x01;
1079       if(temp2 & 0x10) temp1 |= 0x01;
1080       if(temp2 & 0x04) temp1 |= 0x02;
1081
1082       if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
1083
1084    }
1085
1086    switch(temp1) {
1087       case 0x01:
1088          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1089	       "Chrontel: Detected TV connected to COMPOSITE output\n");
1090	  pSiS->VBFlags |= TV_AVIDEO;
1091	  orSISIDXREG(SISCR, 0x32, 0x01);
1092   	  andSISIDXREG(SISCR, 0x32, ~0x06);
1093	  pSiS->postVBCR32 |= 0x01;
1094	  pSiS->postVBCR32 &= ~0x06;
1095          break;
1096       case 0x02:
1097	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1098	       "Chrontel: Detected TV connected to SVIDEO output\n");
1099	  pSiS->VBFlags |= TV_SVIDEO;
1100	  orSISIDXREG(SISCR, 0x32, 0x02);
1101	  andSISIDXREG(SISCR, 0x32, ~0x05);
1102	  pSiS->postVBCR32 |= 0x02;
1103	  pSiS->postVBCR32 &= ~0x05;
1104          break;
1105       case 0x04:
1106	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1107	       "Chrontel: Detected TV connected to SCART or YPBPR output\n");
1108  	  if(pSiS->chtvtype == -1) {
1109	     if(!quiet) {
1110	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1111	            "Chrontel: Use CHTVType option to select either SCART or YPBPR525I\n");
1112	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1113	            "Chrontel: Using SCART by default\n");
1114	     }
1115	     pSiS->chtvtype = 1;
1116	  }
1117	  if(pSiS->chtvtype)
1118	     pSiS->VBFlags |= TV_CHSCART;
1119	  else
1120	     pSiS->VBFlags |= TV_CHYPBPR525I;
1121          break;
1122       default:
1123	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1124	       "Chrontel: No TV detected.\n");
1125	  andSISIDXREG(SISCR, 0x32, ~0x07);
1126	  pSiS->postVBCR32 &= ~0x07;
1127       }
1128}
1129
1130/* Redetect CRT2 devices. Calling this requires a reset
1131 * of the current display mode if TRUE is returned.
1132 */
1133Bool SISRedetectCRT2Type(ScrnInfoPtr pScrn)
1134{
1135    SISPtr pSiS = SISPTR(pScrn);
1136    ULong  VBFlagsBackup = pSiS->VBFlags;
1137    Bool   backup1 = pSiS->forcecrt2redetection;
1138    Bool   backup2 = pSiS->nocrt2ddcdetection;
1139
1140#ifdef SISDUALHEAD
1141    if(pSiS->DualHeadMode) return FALSE;
1142#endif
1143
1144    pSiS->VBFlags &= ~(CRT2_DEFAULT   |
1145		       CRT2_ENABLE    |
1146		       TV_STANDARD    |
1147		       TV_INTERFACE   |
1148		       TV_YPBPRALL    |
1149		       TV_YPBPRAR     |
1150		       TV_CHSCART     |
1151		       TV_CHYPBPR525I |
1152		       CRT1_LCDA      |
1153		       DISPTYPE_CRT1);
1154
1155    /* At first, re-do the sensing for TV and VGA2 */
1156    if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
1157       SISSense30x(pScrn, TRUE);
1158    } else if(pSiS->VBFlags2 & VB2_CHRONTEL) {
1159       SiS_SetChrontelGPIO(pSiS->SiS_Pr, 0x9c);
1160       SISSenseChrontel(pScrn, TRUE);
1161       SiS_SetChrontelGPIO(pSiS->SiS_Pr, 0x00);
1162    }
1163
1164    SISTVPreInit(pScrn, TRUE);
1165
1166    pSiS->forcecrt2redetection = TRUE;
1167    pSiS->nocrt2ddcdetection = FALSE;
1168
1169    /* We only re-detect LCD for the TMDS-SiS-bridges. LVDS
1170     * is practically never being hot-plugged (and even if,
1171     * there is no way of detecting this).
1172     */
1173    if((pSiS->VGAEngine == SIS_315_VGA) &&
1174       (pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) &&
1175       (!(pSiS->VBFlags2 & VB2_30xBDH)) &&
1176       (pSiS->VESA != 1) &&
1177       (pSiS->SiS_Pr->SiS_CustomT != CUT_UNKNOWNLCD)) {
1178       SISLCDPreInit(pScrn, TRUE);
1179    } else {
1180       pSiS->VBFlags |= (pSiS->detectedCRT2Devices & CRT2_LCD);
1181    }
1182
1183    /* Secondary VGA is only supported on these bridges: */
1184    if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
1185       SISCRT2PreInit(pScrn, TRUE);
1186    }
1187
1188    pSiS->forcecrt2redetection = backup1;
1189    pSiS->nocrt2ddcdetection = backup2;
1190
1191    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTLCDA;
1192    if(SISDetermineLCDACap(pScrn)) {
1193       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTLCDA;
1194    }
1195    SISSaveDetectedDevices(pScrn);
1196
1197    pSiS->VBFlags = VBFlagsBackup;
1198
1199    /* If LCD disappeared, don't use it and don't advertise LCDA support. Duh! */
1200    if(!(pSiS->detectedCRT2Devices & CRT2_LCD)) {
1201       pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTLCDA);
1202       if(pSiS->VBFlags & CRT2_LCD) {
1203          /* If CRT2 was LCD, disable CRT2 and adapt display mode flags */
1204          pSiS->VBFlags &= ~(CRT2_LCD | DISPLAY_MODE);
1205	  /* Switch on CRT1 as an emergency measure */
1206	  pSiS->VBFlags |= (SINGLE_MODE | DISPTYPE_CRT1);
1207	  pSiS->CRT1off = 0;
1208       }
1209       /* If CRT1 was LCD, switch to CRT1-VGA. No need to adapt display mode flags. */
1210       pSiS->VBFlags &= ~(CRT1_LCDA);
1211       pSiS->VBFlags_backup = pSiS->VBFlags;
1212    }
1213
1214    pSiS->VBFlagsInit = pSiS->VBFlags;
1215
1216    /* Save new detection result registers to write them back in EnterVT() */
1217    inSISIDXREG(SISCR,0x32,pSiS->myCR32);
1218    inSISIDXREG(SISCR,0x36,pSiS->myCR36);
1219    inSISIDXREG(SISCR,0x37,pSiS->myCR37);
1220
1221    return TRUE;
1222}
1223
1224
1225