Don't include config.h in all files but in the *_include.h files. That's what they...
[nouveau] / src / nv_setup.c
1  /***************************************************************************\
2 |*                                                                           *|
3 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
4 |*                                                                           *|
5 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
6 |*     international laws.  Users and possessors of this source code are     *|
7 |*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
8 |*     use this code in individual and commercial software.                  *|
9 |*                                                                           *|
10 |*     Any use of this source code must include,  in the user documenta-     *|
11 |*     tion and  internal comments to the code,  notices to the end user     *|
12 |*     as follows:                                                           *|
13 |*                                                                           *|
14 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
15 |*                                                                           *|
16 |*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
17 |*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
18 |*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
19 |*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
20 |*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
21 |*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
22 |*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
23 |*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
24 |*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
25 |*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
26 |*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
27 |*                                                                           *|
28 |*     U.S. Government  End  Users.   This source code  is a "commercial     *|
29 |*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
30 |*     consisting  of "commercial  computer  software"  and  "commercial     *|
31 |*     computer  software  documentation,"  as such  terms  are  used in     *|
32 |*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
33 |*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
34 |*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
35 |*     all U.S. Government End Users  acquire the source code  with only     *|
36 |*     those rights set forth herein.                                        *|
37 |*                                                                           *|
38  \***************************************************************************/
39
40 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_setup.c,v 1.48 2005/09/14 02:28:03 mvojkovi Exp $ */
41
42 #include "nv_include.h"
43
44 /*
45  * Override VGA I/O routines.
46  */
47 static void NVWriteCrtc(vgaHWPtr pVga, CARD8 index, CARD8 value)
48 {
49     NVPtr pNv = (NVPtr)pVga->MMIOBase;
50     VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
51     VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET,  value);
52 }
53 static CARD8 NVReadCrtc(vgaHWPtr pVga, CARD8 index)
54 {
55     NVPtr pNv = (NVPtr)pVga->MMIOBase;
56     VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
57     return (VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET));
58 }
59 static void NVWriteGr(vgaHWPtr pVga, CARD8 index, CARD8 value)
60 {
61     NVPtr pNv = (NVPtr)pVga->MMIOBase;
62     VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
63     VGA_WR08(pNv->PVIO, VGA_GRAPH_DATA,  value);
64 }
65 static CARD8 NVReadGr(vgaHWPtr pVga, CARD8 index)
66 {
67     NVPtr pNv = (NVPtr)pVga->MMIOBase;
68     VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
69     return (VGA_RD08(pNv->PVIO, VGA_GRAPH_DATA));
70 }
71 static void NVWriteSeq(vgaHWPtr pVga, CARD8 index, CARD8 value)
72 {
73     NVPtr pNv = (NVPtr)pVga->MMIOBase;
74     VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
75     VGA_WR08(pNv->PVIO, VGA_SEQ_DATA,  value);
76 }
77 static CARD8 NVReadSeq(vgaHWPtr pVga, CARD8 index)
78 {
79     NVPtr pNv = (NVPtr)pVga->MMIOBase;
80     VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
81     return (VGA_RD08(pNv->PVIO, VGA_SEQ_DATA));
82 }
83 static void NVWriteAttr(vgaHWPtr pVga, CARD8 index, CARD8 value)
84 {
85     NVPtr pNv = (NVPtr)pVga->MMIOBase;
86     volatile CARD8 tmp;
87
88     tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
89     if (pVga->paletteEnabled)
90         index &= ~0x20;
91     else
92         index |= 0x20;
93     VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX,  index);
94     VGA_WR08(pNv->PCIO, VGA_ATTR_DATA_W, value);
95 }
96 static CARD8 NVReadAttr(vgaHWPtr pVga, CARD8 index)
97 {
98     NVPtr pNv = (NVPtr)pVga->MMIOBase;
99     volatile CARD8 tmp;
100
101     tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
102     if (pVga->paletteEnabled)
103         index &= ~0x20;
104     else
105         index |= 0x20;
106     VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, index);
107     return (VGA_RD08(pNv->PCIO, VGA_ATTR_DATA_R));
108 }
109 static void NVWriteMiscOut(vgaHWPtr pVga, CARD8 value)
110 {
111     NVPtr pNv = (NVPtr)pVga->MMIOBase;
112     VGA_WR08(pNv->PVIO, VGA_MISC_OUT_W, value);
113 }
114 static CARD8 NVReadMiscOut(vgaHWPtr pVga)
115 {
116     NVPtr pNv = (NVPtr)pVga->MMIOBase;
117     return (VGA_RD08(pNv->PVIO, VGA_MISC_OUT_R));
118 }
119 static void NVEnablePalette(vgaHWPtr pVga)
120 {
121     NVPtr pNv = (NVPtr)pVga->MMIOBase;
122     volatile CARD8 tmp;
123
124     tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
125     VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x00);
126     pVga->paletteEnabled = TRUE;
127 }
128 static void NVDisablePalette(vgaHWPtr pVga)
129 {
130     NVPtr pNv = (NVPtr)pVga->MMIOBase;
131     volatile CARD8 tmp;
132
133     tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
134     VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x20);
135     pVga->paletteEnabled = FALSE;
136 }
137 static void NVWriteDacMask(vgaHWPtr pVga, CARD8 value)
138 {
139     NVPtr pNv = (NVPtr)pVga->MMIOBase;
140     VGA_WR08(pNv->PDIO, VGA_DAC_MASK, value);
141 }
142 static CARD8 NVReadDacMask(vgaHWPtr pVga)
143 {
144     NVPtr pNv = (NVPtr)pVga->MMIOBase;
145     return (VGA_RD08(pNv->PDIO, VGA_DAC_MASK));
146 }
147 static void NVWriteDacReadAddr(vgaHWPtr pVga, CARD8 value)
148 {
149     NVPtr pNv = (NVPtr)pVga->MMIOBase;
150     VGA_WR08(pNv->PDIO, VGA_DAC_READ_ADDR, value);
151 }
152 static void NVWriteDacWriteAddr(vgaHWPtr pVga, CARD8 value)
153 {
154     NVPtr pNv = (NVPtr)pVga->MMIOBase;
155     VGA_WR08(pNv->PDIO, VGA_DAC_WRITE_ADDR, value);
156 }
157 static void NVWriteDacData(vgaHWPtr pVga, CARD8 value)
158 {
159     NVPtr pNv = (NVPtr)pVga->MMIOBase;
160     VGA_WR08(pNv->PDIO, VGA_DAC_DATA, value);
161 }
162 static CARD8 NVReadDacData(vgaHWPtr pVga)
163 {
164     NVPtr pNv = (NVPtr)pVga->MMIOBase;
165     return (VGA_RD08(pNv->PDIO, VGA_DAC_DATA));
166 }
167
168 static Bool 
169 NVIsConnected (ScrnInfoPtr pScrn, int output)
170 {
171     NVPtr pNv = NVPTR(pScrn);
172     volatile U032 *PRAMDAC = pNv->PRAMDAC0;
173     CARD32 reg52C, reg608;
174     Bool present;
175
176     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
177                "Probing for analog device on output %s...\n", 
178                 output ? "B" : "A");
179
180     if(output) PRAMDAC += 0x800;
181
182     reg52C = PRAMDAC[0x052C/4];
183     reg608 = PRAMDAC[0x0608/4];
184
185     PRAMDAC[0x0608/4] = reg608 & ~0x00010000;
186
187     PRAMDAC[0x052C/4] = reg52C & 0x0000FEEE;
188     usleep(1000);
189     PRAMDAC[0x052C/4] |= 1;
190
191     pNv->PRAMDAC0[0x0610/4] = 0x94050140;
192     pNv->PRAMDAC0[0x0608/4] |= 0x00001000;
193
194     usleep(1000);
195
196     present = (PRAMDAC[0x0608/4] & (1 << 28)) ? TRUE : FALSE;
197
198     if(present)
199        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "  ...found one\n");
200     else
201        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "  ...can't find one\n");
202
203     pNv->PRAMDAC0[0x0608/4] &= 0x0000EFFF;
204
205     PRAMDAC[0x052C/4] = reg52C;
206     PRAMDAC[0x0608/4] = reg608;
207
208     return present;
209 }
210
211 static void
212 NVSelectHeadRegisters(ScrnInfoPtr pScrn, int head)
213 {
214     NVPtr pNv = NVPTR(pScrn);
215
216     if(head) {
217        pNv->PCIO = pNv->PCIO0 + 0x2000;
218        pNv->PCRTC = pNv->PCRTC0 + 0x800;
219        pNv->PRAMDAC = pNv->PRAMDAC0 + 0x800;
220        pNv->PDIO = pNv->PDIO0 + 0x2000;
221     } else {
222        pNv->PCIO = pNv->PCIO0;
223        pNv->PCRTC = pNv->PCRTC0;
224        pNv->PRAMDAC = pNv->PRAMDAC0;
225        pNv->PDIO = pNv->PDIO0;
226     }
227 }
228
229 static xf86MonPtr 
230 NVProbeDDC (ScrnInfoPtr pScrn, int bus)
231 {
232     NVPtr pNv = NVPTR(pScrn);
233     xf86MonPtr MonInfo = NULL;
234
235     if(!pNv->I2C) return NULL;
236
237     pNv->DDCBase = bus ? 0x36 : 0x3e;
238
239     xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
240                "Probing for EDID on I2C bus %s...\n", bus ? "B" : "A");
241
242     if ((MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, pNv->I2C))) {
243        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
244                   "DDC detected a %s:\n", MonInfo->features.input_type ?
245                   "DFP" : "CRT");
246        xf86PrintEDID( MonInfo );
247     } else {
248        xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
249                   "  ... none found\n");
250     }
251
252     return MonInfo;
253 }
254
255 static void nv4GetConfig (NVPtr pNv)
256 {
257     if (pNv->PFB[0x0000/4] & 0x00000100) {
258         pNv->RamAmountKBytes = ((pNv->PFB[0x0000/4] >> 12) & 0x0F) * 1024 * 2
259                               + 1024 * 2;
260     } else {
261         switch (pNv->PFB[0x0000/4] & 0x00000003) {
262         case 0:
263             pNv->RamAmountKBytes = 1024 * 32;
264             break;
265         case 1:
266             pNv->RamAmountKBytes = 1024 * 4;
267             break;
268         case 2:
269             pNv->RamAmountKBytes = 1024 * 8;
270             break;
271         case 3:
272         default:
273             pNv->RamAmountKBytes = 1024 * 16;
274             break;
275         }
276     }
277     pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & 0x00000040) ? 14318 : 13500;
278     pNv->CURSOR         = &(pNv->PRAMIN[0x1E00]);
279     pNv->MinVClockFreqKHz = 12000;
280     pNv->MaxVClockFreqKHz = 350000;
281 }
282
283 static void nv10GetConfig (NVPtr pNv)
284 {
285     CARD32 implementation = pNv->Chipset & 0x0ff0;
286
287 #if X_BYTE_ORDER == X_BIG_ENDIAN
288     /* turn on big endian register access */
289     if(!(pNv->PMC[0x0004/4] & 0x01000001)) {
290        pNv->PMC[0x0004/4] = 0x01000001;
291        mem_barrier();
292     }
293 #endif
294
295     if(implementation == CHIPSET_NFORCE) {
296         int amt = pciReadLong(pciTag(0, 0, 1), 0x7C);
297         pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
298     } else if(implementation == CHIPSET_NFORCE2) {
299         int amt = pciReadLong(pciTag(0, 0, 1), 0x84);
300         pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
301     } else {
302         pNv->RamAmountKBytes = (pNv->PFB[0x020C/4] & 0xFFF00000) >> 10;
303     }
304
305     if(pNv->RamAmountKBytes > 256*1024)
306         pNv->RamAmountKBytes = 256*1024;
307
308     pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & (1 << 6)) ? 14318 : 13500;
309     
310     if(pNv->twoHeads && (implementation != CHIPSET_NV11))
311     {
312        if(pNv->PEXTDEV[0x0000/4] & (1 << 22))
313            pNv->CrystalFreqKHz = 27000;
314     }
315
316     pNv->CURSOR           = NULL;  /* can't set this here */
317     pNv->MinVClockFreqKHz = 12000;
318     pNv->MaxVClockFreqKHz = pNv->twoStagePLL ? 400000 : 350000;
319 }
320
321
322 void
323 NVCommonSetup(ScrnInfoPtr pScrn)
324 {
325     NVPtr pNv = NVPTR(pScrn);
326     vgaHWPtr pVga = VGAHWPTR(pScrn);
327     CARD16 implementation = pNv->Chipset & 0x0ff0;
328     xf86MonPtr monitorA, monitorB;
329     Bool mobile = FALSE;
330     Bool tvA = FALSE;
331     Bool tvB = FALSE;
332     int FlatPanel = -1;   /* really means the CRTC is slaved */
333     Bool Television = FALSE;
334     
335     /*
336      * Override VGA I/O routines.
337      */
338     pVga->writeCrtc         = NVWriteCrtc;
339     pVga->readCrtc          = NVReadCrtc;
340     pVga->writeGr           = NVWriteGr;
341     pVga->readGr            = NVReadGr;
342     pVga->writeAttr         = NVWriteAttr;
343     pVga->readAttr          = NVReadAttr;
344     pVga->writeSeq          = NVWriteSeq;
345     pVga->readSeq           = NVReadSeq;
346     pVga->writeMiscOut      = NVWriteMiscOut;
347     pVga->readMiscOut       = NVReadMiscOut;
348     pVga->enablePalette     = NVEnablePalette;
349     pVga->disablePalette    = NVDisablePalette;
350     pVga->writeDacMask      = NVWriteDacMask;
351     pVga->readDacMask       = NVReadDacMask;
352     pVga->writeDacWriteAddr = NVWriteDacWriteAddr;
353     pVga->writeDacReadAddr  = NVWriteDacReadAddr;
354     pVga->writeDacData      = NVWriteDacData;
355     pVga->readDacData       = NVReadDacData;
356     /*
357      * Note: There are different pointers to the CRTC/AR and GR/SEQ registers.
358      * Bastardize the intended uses of these to make it work.
359      */
360     pVga->MMIOBase   = (CARD8 *)pNv;
361     pVga->MMIOOffset = 0;
362     
363     pNv->REGS = xf86MapPciMem(pScrn->scrnIndex, 
364                               VIDMEM_MMIO | VIDMEM_READSIDEEFFECT, 
365                               pNv->PciTag, pNv->IOAddress, 0x01000000);
366
367     pNv->PRAMIN   = pNv->REGS + (0x00710000/4);
368     pNv->PCRTC0   = pNv->REGS + (0x00600000/4);
369     pNv->PRAMDAC0 = pNv->REGS + (0x00680000/4);
370     pNv->PFB      = pNv->REGS + (0x00100000/4);
371     pNv->PFIFO    = pNv->REGS + (0x00002000/4);
372     pNv->PGRAPH   = pNv->REGS + (0x00400000/4);
373     pNv->PEXTDEV  = pNv->REGS + (0x00101000/4);
374     pNv->PTIMER   = pNv->REGS + (0x00009000/4);
375     pNv->PMC      = pNv->REGS + (0x00000000/4);
376     pNv->FIFO     = pNv->REGS + (0x00800000/4);
377
378     /* 8 bit registers */
379     pNv->PCIO0    = (U008*)pNv->REGS + 0x00601000;
380     pNv->PDIO0    = (U008*)pNv->REGS + 0x00681000;
381     pNv->PVIO     = (U008*)pNv->REGS + 0x000C0000;
382
383     pNv->twoHeads =  (pNv->Architecture >= NV_ARCH_10) &&
384                      (implementation != CHIPSET_NV10) &&
385                      (implementation != CHIPSET_NV15) &&
386                      (implementation != CHIPSET_NFORCE) &&
387                      (implementation != CHIPSET_NV20);
388
389     pNv->fpScaler = (pNv->FpScale && pNv->twoHeads && (implementation!=CHIPSET_NV11));
390
391     pNv->twoStagePLL = (implementation == CHIPSET_NV31) ||
392                        (implementation == CHIPSET_NV36) ||
393                        (pNv->Architecture >= NV_ARCH_40);
394
395     pNv->WaitVSyncPossible = (pNv->Architecture >= NV_ARCH_10) &&
396                              (implementation != CHIPSET_NV10);
397
398     pNv->BlendingPossible = ((pNv->Chipset & 0xffff) != CHIPSET_NV04);
399
400     /* look for known laptop chips */
401     /* FIXME we could add some ids here (0x0167) */
402     switch(pNv->Chipset & 0xffff) {
403     case 0x0112:
404     case 0x0174:
405     case 0x0175:
406     case 0x0176:
407     case 0x0177:
408     case 0x0179:
409     case 0x017C:
410     case 0x017D:
411     case 0x0186:
412     case 0x0187:
413     case 0x018D:
414     case 0x0228:
415     case 0x0286:
416     case 0x028C:
417     case 0x0316:
418     case 0x0317:
419     case 0x031A:
420     case 0x031B:
421     case 0x031C:
422     case 0x031D:
423     case 0x031E:
424     case 0x031F:
425     case 0x0324:
426     case 0x0325:
427     case 0x0328:
428     case 0x0329:
429     case 0x032C:
430     case 0x032D:
431     case 0x0347:
432     case 0x0348:
433     case 0x0349:
434     case 0x034B:
435     case 0x034C:
436     case 0x0160:
437     case 0x0166:
438     case 0x0169:
439     case 0x016B:
440     case 0x016C:
441     case 0x016D:
442     case 0x00C8:
443     case 0x00CC:
444     case 0x0144:
445     case 0x0146:
446     case 0x0148:
447     case 0x0098:
448     case 0x0099:
449         mobile = TRUE;
450         break;
451     default:
452         break;
453     }
454
455     if(pNv->Architecture == NV_ARCH_04)
456         nv4GetConfig(pNv);
457     else
458         nv10GetConfig(pNv);
459
460     NVSelectHeadRegisters(pScrn, 0);
461
462     NVLockUnlock(pNv, 0);
463
464     NVI2CInit(pScrn);
465
466     pNv->Television = FALSE;
467
468     if(!pNv->twoHeads) {
469        pNv->CRTCnumber = 0;
470        if((monitorA = NVProbeDDC(pScrn, 0))) {
471            FlatPanel = monitorA->features.input_type ? 1 : 0;
472
473            /* NV4 doesn't support FlatPanels */
474            if((pNv->Chipset & 0x0fff) <= CHIPSET_NV04)
475               FlatPanel = 0;
476        } else {
477            VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
478            if(VGA_RD08(pNv->PCIO, 0x03D5) & 0x80) {
479               VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
480               if(!(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01)) 
481                  Television = TRUE;
482               FlatPanel = 1;
483            } else {
484               FlatPanel = 0;
485            }
486            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
487                          "HW is currently programmed for %s\n",
488                           FlatPanel ? (Television ? "TV" : "DFP") : "CRT");
489        } 
490
491        if(pNv->FlatPanel == -1) {
492            pNv->FlatPanel = FlatPanel;
493            pNv->Television = Television;
494        } else {
495            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
496                       "Forcing display type to %s as specified\n", 
497                        pNv->FlatPanel ? "DFP" : "CRT");
498        }
499     } else {
500        CARD8 outputAfromCRTC, outputBfromCRTC;
501        int CRTCnumber = -1;
502        CARD8 slaved_on_A, slaved_on_B;
503        Bool analog_on_A, analog_on_B;
504        CARD32 oldhead;
505        CARD8 cr44;
506       
507        if(implementation != CHIPSET_NV11) {
508            if(pNv->PRAMDAC0[0x0000052C/4] & 0x100)
509                outputAfromCRTC = 1;
510            else            
511                outputAfromCRTC = 0;
512            if(pNv->PRAMDAC0[0x0000252C/4] & 0x100)
513                outputBfromCRTC = 1;
514            else
515                outputBfromCRTC = 0;
516           analog_on_A = NVIsConnected(pScrn, 0);
517           analog_on_B = NVIsConnected(pScrn, 1);
518        } else {
519           outputAfromCRTC = 0;
520           outputBfromCRTC = 1;
521           analog_on_A = FALSE;
522           analog_on_B = FALSE;
523        }
524
525        VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
526        cr44 = VGA_RD08(pNv->PCIO, 0x03D5);
527
528        VGA_WR08(pNv->PCIO, 0x03D5, 3);
529        NVSelectHeadRegisters(pScrn, 1);
530        NVLockUnlock(pNv, 0);
531
532        VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
533        slaved_on_B = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80;
534        if(slaved_on_B) {
535            VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
536            tvB = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01);
537        }
538
539        VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
540        VGA_WR08(pNv->PCIO, 0x03D5, 0);
541        NVSelectHeadRegisters(pScrn, 0);
542        NVLockUnlock(pNv, 0);
543
544        VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
545        slaved_on_A = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80; 
546        if(slaved_on_A) {
547            VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
548            tvA = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01);
549        }
550
551        oldhead = pNv->PCRTC0[0x00000860/4];
552        pNv->PCRTC0[0x00000860/4] = oldhead | 0x00000010;
553
554        monitorA = NVProbeDDC(pScrn, 0);
555        monitorB = NVProbeDDC(pScrn, 1);
556
557        if(slaved_on_A && !tvA) {
558           CRTCnumber = 0;
559           FlatPanel = 1;
560           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
561                     "CRTC 0 is currently programmed for DFP\n");
562        } else 
563        if(slaved_on_B && !tvB) {
564           CRTCnumber = 1;
565           FlatPanel = 1;
566           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
567                     "CRTC 1 is currently programmed for DFP\n");
568        } else
569        if(analog_on_A) {
570           CRTCnumber = outputAfromCRTC;
571           FlatPanel = 0;
572           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
573                     "CRTC %i appears to have a CRT attached\n", CRTCnumber);
574        } else
575        if(analog_on_B) {
576            CRTCnumber = outputBfromCRTC;
577            FlatPanel = 0;
578            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
579                     "CRTC %i appears to have a CRT attached\n", CRTCnumber);
580        } else
581        if(slaved_on_A) {
582           CRTCnumber = 0;
583           FlatPanel = 1;
584           Television = 1;
585           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
586                     "CRTC 0 is currently programmed for TV\n");
587        } else
588        if(slaved_on_B) {
589           CRTCnumber = 1;
590           FlatPanel = 1;
591           Television = 1;
592           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
593                     "CRTC 1 is currently programmed for TV\n");
594        } else
595        if(monitorA) {
596            FlatPanel = monitorA->features.input_type ? 1 : 0;
597        } else 
598        if(monitorB) {
599            FlatPanel = monitorB->features.input_type ? 1 : 0;
600        }
601
602        if(pNv->FlatPanel == -1) {
603           if(FlatPanel != -1) {
604              pNv->FlatPanel = FlatPanel;
605              pNv->Television = Television;
606           } else {
607              xf86DrvMsg(pScrn->scrnIndex, X_INFO,
608                         "Unable to detect display type...\n");
609              if(mobile) {
610                  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
611                             "...On a laptop, assuming DFP\n");
612                  pNv->FlatPanel = 1;
613              } else {
614                  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
615                             "...Using default of CRT\n");
616                  pNv->FlatPanel = 0;
617              }
618           }
619        } else {
620            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
621                       "Forcing display type to %s as specified\n", 
622                        pNv->FlatPanel ? "DFP" : "CRT");
623        }
624
625        if(pNv->CRTCnumber == -1) {
626           if(CRTCnumber != -1) pNv->CRTCnumber = CRTCnumber;
627           else {
628              xf86DrvMsg(pScrn->scrnIndex, X_INFO,
629                         "Unable to detect which CRTCNumber...\n");
630              if(pNv->FlatPanel) pNv->CRTCnumber = 1;
631              else pNv->CRTCnumber = 0;
632              xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
633                         "...Defaulting to CRTCNumber %i\n", pNv->CRTCnumber);
634           }
635        } else {
636            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
637                       "Forcing CRTCNumber %i as specified\n", pNv->CRTCnumber);
638        }
639      
640        if(monitorA) {
641            if((monitorA->features.input_type && pNv->FlatPanel) ||
642               (!monitorA->features.input_type && !pNv->FlatPanel))
643            {
644                if(monitorB) { 
645                   xfree(monitorB);
646                   monitorB = NULL;
647                }
648            } else {
649               xfree(monitorA);
650               monitorA = NULL;
651            }
652        }
653
654        if(monitorB) {
655            if((monitorB->features.input_type && !pNv->FlatPanel) ||
656               (!monitorB->features.input_type && pNv->FlatPanel)) 
657            {
658               xfree(monitorB);
659            } else {
660               monitorA = monitorB;
661            }
662            monitorB = NULL;
663        }
664
665        if(implementation == CHIPSET_NV11)
666            cr44 = pNv->CRTCnumber * 0x3;
667
668        pNv->PCRTC0[0x00000860/4] = oldhead;
669
670        VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
671        VGA_WR08(pNv->PCIO, 0x03D5, cr44);
672        NVSelectHeadRegisters(pScrn, pNv->CRTCnumber);
673     }
674
675     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
676               "Using %s on CRTC %i\n",
677               pNv->FlatPanel ? (pNv->Television ? "TV" : "DFP") : "CRT", 
678               pNv->CRTCnumber);
679
680     if(pNv->FlatPanel && !pNv->Television) {
681        pNv->fpWidth = pNv->PRAMDAC[0x0820/4] + 1;
682        pNv->fpHeight = pNv->PRAMDAC[0x0800/4] + 1;
683        pNv->fpSyncs = pNv->PRAMDAC[0x0848/4] & 0x30000033;
684        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x %i\n",
685                   pNv->fpWidth, pNv->fpHeight);
686     }
687
688     if(monitorA)
689       xf86SetDDCproperties(pScrn, monitorA);
690
691     if(!pNv->FlatPanel || (pScrn->depth != 24) || !pNv->twoHeads)
692         pNv->FPDither = FALSE;
693
694     pNv->LVDS = FALSE;
695     if(pNv->FlatPanel && pNv->twoHeads) {
696         pNv->PRAMDAC0[0x08B0/4] = 0x00010004;
697         if(pNv->PRAMDAC0[0x08B4/4] & 1)
698            pNv->LVDS = TRUE;
699         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel is %s\n", 
700                    pNv->LVDS ? "LVDS" : "TMDS");
701     }
702 }
703