Comment out NVDmaKickoff() in NVResetGraphics(). NVResetGraphics is called twice...
[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 #include "nvreg.h"
44
45 /*
46  * Override VGA I/O routines.
47  */
48 static void NVWriteCrtc(vgaHWPtr pVga, CARD8 index, CARD8 value)
49 {
50     NVPtr pNv = (NVPtr)pVga->MMIOBase;
51     VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
52     VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET,  value);
53 }
54 static CARD8 NVReadCrtc(vgaHWPtr pVga, CARD8 index)
55 {
56     NVPtr pNv = (NVPtr)pVga->MMIOBase;
57     VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
58     return (VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET));
59 }
60 static void NVWriteGr(vgaHWPtr pVga, CARD8 index, CARD8 value)
61 {
62     NVPtr pNv = (NVPtr)pVga->MMIOBase;
63     VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
64     VGA_WR08(pNv->PVIO, VGA_GRAPH_DATA,  value);
65 }
66 static CARD8 NVReadGr(vgaHWPtr pVga, CARD8 index)
67 {
68     NVPtr pNv = (NVPtr)pVga->MMIOBase;
69     VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
70     return (VGA_RD08(pNv->PVIO, VGA_GRAPH_DATA));
71 }
72 static void NVWriteSeq(vgaHWPtr pVga, CARD8 index, CARD8 value)
73 {
74     NVPtr pNv = (NVPtr)pVga->MMIOBase;
75     VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
76     VGA_WR08(pNv->PVIO, VGA_SEQ_DATA,  value);
77 }
78 static CARD8 NVReadSeq(vgaHWPtr pVga, CARD8 index)
79 {
80     NVPtr pNv = (NVPtr)pVga->MMIOBase;
81     VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
82     return (VGA_RD08(pNv->PVIO, VGA_SEQ_DATA));
83 }
84 static void NVWriteAttr(vgaHWPtr pVga, CARD8 index, CARD8 value)
85 {
86     NVPtr pNv = (NVPtr)pVga->MMIOBase;
87     volatile CARD8 tmp;
88
89     tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
90     if (pVga->paletteEnabled)
91         index &= ~0x20;
92     else
93         index |= 0x20;
94     VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX,  index);
95     VGA_WR08(pNv->PCIO, VGA_ATTR_DATA_W, value);
96 }
97 static CARD8 NVReadAttr(vgaHWPtr pVga, CARD8 index)
98 {
99     NVPtr pNv = (NVPtr)pVga->MMIOBase;
100     volatile CARD8 tmp;
101
102     tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
103     if (pVga->paletteEnabled)
104         index &= ~0x20;
105     else
106         index |= 0x20;
107     VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, index);
108     return (VGA_RD08(pNv->PCIO, VGA_ATTR_DATA_R));
109 }
110 static void NVWriteMiscOut(vgaHWPtr pVga, CARD8 value)
111 {
112     NVPtr pNv = (NVPtr)pVga->MMIOBase;
113     VGA_WR08(pNv->PVIO, VGA_MISC_OUT_W, value);
114 }
115 static CARD8 NVReadMiscOut(vgaHWPtr pVga)
116 {
117     NVPtr pNv = (NVPtr)pVga->MMIOBase;
118     return (VGA_RD08(pNv->PVIO, VGA_MISC_OUT_R));
119 }
120 static void NVEnablePalette(vgaHWPtr pVga)
121 {
122     NVPtr pNv = (NVPtr)pVga->MMIOBase;
123     volatile CARD8 tmp;
124
125     tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
126     VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x00);
127     pVga->paletteEnabled = TRUE;
128 }
129 static void NVDisablePalette(vgaHWPtr pVga)
130 {
131     NVPtr pNv = (NVPtr)pVga->MMIOBase;
132     volatile CARD8 tmp;
133
134     tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
135     VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x20);
136     pVga->paletteEnabled = FALSE;
137 }
138 static void NVWriteDacMask(vgaHWPtr pVga, CARD8 value)
139 {
140     NVPtr pNv = (NVPtr)pVga->MMIOBase;
141     VGA_WR08(pNv->PDIO, VGA_DAC_MASK, value);
142 }
143 static CARD8 NVReadDacMask(vgaHWPtr pVga)
144 {
145     NVPtr pNv = (NVPtr)pVga->MMIOBase;
146     return (VGA_RD08(pNv->PDIO, VGA_DAC_MASK));
147 }
148 static void NVWriteDacReadAddr(vgaHWPtr pVga, CARD8 value)
149 {
150     NVPtr pNv = (NVPtr)pVga->MMIOBase;
151     VGA_WR08(pNv->PDIO, VGA_DAC_READ_ADDR, value);
152 }
153 static void NVWriteDacWriteAddr(vgaHWPtr pVga, CARD8 value)
154 {
155     NVPtr pNv = (NVPtr)pVga->MMIOBase;
156     VGA_WR08(pNv->PDIO, VGA_DAC_WRITE_ADDR, value);
157 }
158 static void NVWriteDacData(vgaHWPtr pVga, CARD8 value)
159 {
160     NVPtr pNv = (NVPtr)pVga->MMIOBase;
161     VGA_WR08(pNv->PDIO, VGA_DAC_DATA, value);
162 }
163 static CARD8 NVReadDacData(vgaHWPtr pVga)
164 {
165     NVPtr pNv = (NVPtr)pVga->MMIOBase;
166     return (VGA_RD08(pNv->PDIO, VGA_DAC_DATA));
167 }
168
169 static Bool 
170 NVIsConnected (ScrnInfoPtr pScrn, int output)
171 {
172     NVPtr pNv = NVPTR(pScrn);
173     volatile U032 *PRAMDAC = pNv->PRAMDAC0;
174     CARD32 reg52C, reg608;
175     Bool present;
176
177     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
178                "Probing for analog device on output %s...\n", 
179                 output ? "B" : "A");
180
181     if(output) PRAMDAC += 0x800;
182
183     reg52C = PRAMDAC[0x052C/4];
184     reg608 = PRAMDAC[0x0608/4];
185
186     PRAMDAC[0x0608/4] = reg608 & ~0x00010000;
187
188     PRAMDAC[0x052C/4] = reg52C & 0x0000FEEE;
189     usleep(1000);
190     PRAMDAC[0x052C/4] |= 1;
191
192     pNv->PRAMDAC0[0x0610/4] = 0x94050140;
193     pNv->PRAMDAC0[0x0608/4] |= 0x00001000;
194
195     usleep(1000);
196
197     present = (PRAMDAC[0x0608/4] & (1 << 28)) ? TRUE : FALSE;
198
199     if(present)
200        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "  ...found one\n");
201     else
202        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "  ...can't find one\n");
203
204     pNv->PRAMDAC0[0x0608/4] &= 0x0000EFFF;
205
206     PRAMDAC[0x052C/4] = reg52C;
207     PRAMDAC[0x0608/4] = reg608;
208
209     return present;
210 }
211
212 static void
213 NVSelectHeadRegisters(ScrnInfoPtr pScrn, int head)
214 {
215     NVPtr pNv = NVPTR(pScrn);
216
217     if(head) {
218        pNv->PCIO = pNv->PCIO0 + 0x2000;
219        pNv->PCRTC = pNv->PCRTC0 + 0x800;
220        pNv->PRAMDAC = pNv->PRAMDAC0 + 0x800;
221        pNv->PDIO = pNv->PDIO0 + 0x2000;
222     } else {
223        pNv->PCIO = pNv->PCIO0;
224        pNv->PCRTC = pNv->PCRTC0;
225        pNv->PRAMDAC = pNv->PRAMDAC0;
226        pNv->PDIO = pNv->PDIO0;
227     }
228 }
229
230 static xf86MonPtr 
231 NVProbeDDC (ScrnInfoPtr pScrn, int bus)
232 {
233     NVPtr pNv = NVPTR(pScrn);
234     xf86MonPtr MonInfo = NULL;
235
236     if(!pNv->I2C) return NULL;
237
238     pNv->DDCBase = bus ? 0x36 : 0x3e;
239
240     xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
241                "Probing for EDID on I2C bus %s...\n", bus ? "B" : "A");
242
243     if ((MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, pNv->I2C))) {
244        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
245                   "DDC detected a %s:\n", MonInfo->features.input_type ?
246                   "DFP" : "CRT");
247        xf86PrintEDID( MonInfo );
248     } else {
249        xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
250                   "  ... none found\n");
251     }
252
253     return MonInfo;
254 }
255
256 static void nv4GetConfig (NVPtr pNv)
257 {
258     if (pNv->PFB[0x0000/4] & 0x00000100) {
259         pNv->RamAmountKBytes = ((pNv->PFB[0x0000/4] >> 12) & 0x0F) * 1024 * 2
260                               + 1024 * 2;
261     } else {
262         switch (pNv->PFB[0x0000/4] & 0x00000003) {
263         case 0:
264             pNv->RamAmountKBytes = 1024 * 32;
265             break;
266         case 1:
267             pNv->RamAmountKBytes = 1024 * 4;
268             break;
269         case 2:
270             pNv->RamAmountKBytes = 1024 * 8;
271             break;
272         case 3:
273         default:
274             pNv->RamAmountKBytes = 1024 * 16;
275             break;
276         }
277     }
278     pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & 0x00000040) ? 14318 : 13500;
279     pNv->CURSOR         = &(pNv->PRAMIN[0x1E00]);
280     pNv->MinVClockFreqKHz = 12000;
281     pNv->MaxVClockFreqKHz = 350000;
282 }
283
284 static void nv10GetConfig (NVPtr pNv)
285 {
286     CARD32 implementation = pNv->Chipset & 0x0ff0;
287
288 #if X_BYTE_ORDER == X_BIG_ENDIAN
289     /* turn on big endian register access */
290     if(!(pNv->PMC[0x0004/4] & 0x01000001)) {
291        pNv->PMC[0x0004/4] = 0x01000001;
292        mem_barrier();
293     }
294 #endif
295
296     if(implementation == CHIPSET_NFORCE) {
297         int amt = pciReadLong(pciTag(0, 0, 1), 0x7C);
298         pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
299     } else if(implementation == CHIPSET_NFORCE2) {
300         int amt = pciReadLong(pciTag(0, 0, 1), 0x84);
301         pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
302     } else {
303         pNv->RamAmountKBytes = (pNv->PFB[0x020C/4] & 0xFFF00000) >> 10;
304     }
305
306     if(pNv->RamAmountKBytes > 256*1024)
307         pNv->RamAmountKBytes = 256*1024;
308
309     pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & (1 << 6)) ? 14318 : 13500;
310     
311     if(pNv->twoHeads && (implementation != CHIPSET_NV11))
312     {
313        if(pNv->PEXTDEV[0x0000/4] & (1 << 22))
314            pNv->CrystalFreqKHz = 27000;
315     }
316
317     pNv->CURSOR           = NULL;  /* can't set this here */
318     pNv->MinVClockFreqKHz = 12000;
319     pNv->MaxVClockFreqKHz = pNv->twoStagePLL ? 400000 : 350000;
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 + (NV_PRAMIN_OFFSET/4);
368     pNv->PCRTC0   = pNv->REGS + (NV_PCRTC0_OFFSET/4);
369     pNv->PRAMDAC0 = pNv->REGS + (NV_PRAMDAC0_OFFSET/4);
370     pNv->PFB      = pNv->REGS + (NV_PFB_OFFSET/4);
371     pNv->PFIFO    = pNv->REGS + (NV_PFIFO_OFFSET/4);
372     pNv->PGRAPH   = pNv->REGS + (NV_PGRAPH_OFFSET/4);
373     pNv->PEXTDEV  = pNv->REGS + (NV_PEXTDEV_OFFSET/4);
374     pNv->PTIMER   = pNv->REGS + (NV_PTIMER_OFFSET/4);
375     pNv->PMC      = pNv->REGS + (NV_PMC_OFFSET/4);
376
377     /* 8 bit registers */
378     pNv->PCIO0    = (U008*)pNv->REGS + NV_PCIO0_OFFSET;
379     pNv->PDIO0    = (U008*)pNv->REGS + NV_PDIO0_OFFSET;
380     pNv->PVIO     = (U008*)pNv->REGS + NV_PVIO_OFFSET;
381     pNv->PROM     = (U008*)pNv->REGS + NV_PROM_OFFSET;
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     /* Parse the bios to initialize the card */
456     NVSelectHeadRegisters(pScrn, 0);
457     NVParseBios(pScrn);
458     /* reset PFIFO and PGRAPH, then power up all the card units */
459 /*    pNv->PMC[0x200]=0x17110013;
460     usleep(1000);*/
461     pNv->PMC[0x200]=0x17111113;
462
463     if(pNv->Architecture == NV_ARCH_04)
464         nv4GetConfig(pNv);
465     else
466         nv10GetConfig(pNv);
467
468     NVSelectHeadRegisters(pScrn, 0);
469
470     NVLockUnlock(pNv, 0);
471
472     NVI2CInit(pScrn);
473
474     pNv->Television = FALSE;
475
476     if(!pNv->twoHeads) {
477        pNv->CRTCnumber = 0;
478        if((monitorA = NVProbeDDC(pScrn, 0))) {
479            FlatPanel = monitorA->features.input_type ? 1 : 0;
480
481            /* NV4 doesn't support FlatPanels */
482            if((pNv->Chipset & 0x0fff) <= CHIPSET_NV04)
483               FlatPanel = 0;
484        } else {
485            VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
486            if(VGA_RD08(pNv->PCIO, 0x03D5) & 0x80) {
487               VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
488               if(!(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01)) 
489                  Television = TRUE;
490               FlatPanel = 1;
491            } else {
492               FlatPanel = 0;
493            }
494            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
495                          "HW is currently programmed for %s\n",
496                           FlatPanel ? (Television ? "TV" : "DFP") : "CRT");
497        } 
498
499        if(pNv->FlatPanel == -1) {
500            pNv->FlatPanel = FlatPanel;
501            pNv->Television = Television;
502        } else {
503            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
504                       "Forcing display type to %s as specified\n", 
505                        pNv->FlatPanel ? "DFP" : "CRT");
506        }
507     } else {
508        CARD8 outputAfromCRTC, outputBfromCRTC;
509        int CRTCnumber = -1;
510        CARD8 slaved_on_A, slaved_on_B;
511        Bool analog_on_A, analog_on_B;
512        CARD32 oldhead;
513        CARD8 cr44;
514       
515        if(implementation != CHIPSET_NV11) {
516            if(pNv->PRAMDAC0[0x0000052C/4] & 0x100)
517                outputAfromCRTC = 1;
518            else            
519                outputAfromCRTC = 0;
520            if(pNv->PRAMDAC0[0x0000252C/4] & 0x100)
521                outputBfromCRTC = 1;
522            else
523                outputBfromCRTC = 0;
524           analog_on_A = NVIsConnected(pScrn, 0);
525           analog_on_B = NVIsConnected(pScrn, 1);
526        } else {
527           outputAfromCRTC = 0;
528           outputBfromCRTC = 1;
529           analog_on_A = FALSE;
530           analog_on_B = FALSE;
531        }
532
533        VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
534        cr44 = VGA_RD08(pNv->PCIO, 0x03D5);
535            pNv->vtOWNER = cr44;
536
537        VGA_WR08(pNv->PCIO, 0x03D5, 3);
538        NVSelectHeadRegisters(pScrn, 1);
539        NVLockUnlock(pNv, 0);
540
541        VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
542        slaved_on_B = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80;
543        if(slaved_on_B) {
544            VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
545            tvB = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01);
546        }
547
548        VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
549        VGA_WR08(pNv->PCIO, 0x03D5, 0);
550        NVSelectHeadRegisters(pScrn, 0);
551        NVLockUnlock(pNv, 0);
552
553        VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
554        slaved_on_A = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80; 
555        if(slaved_on_A) {
556            VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
557            tvA = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01);
558        }
559
560        oldhead = pNv->PCRTC0[0x00000860/4];
561        pNv->PCRTC0[0x00000860/4] = oldhead | 0x00000010;
562
563        monitorA = NVProbeDDC(pScrn, 0);
564        monitorB = NVProbeDDC(pScrn, 1);
565
566        if(slaved_on_A && !tvA) {
567           CRTCnumber = 0;
568           FlatPanel = 1;
569           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
570                     "CRTC 0 is currently programmed for DFP\n");
571        } else 
572        if(slaved_on_B && !tvB) {
573           CRTCnumber = 1;
574           FlatPanel = 1;
575           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
576                     "CRTC 1 is currently programmed for DFP\n");
577        } else
578        if(analog_on_A) {
579           CRTCnumber = outputAfromCRTC;
580           FlatPanel = 0;
581           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
582                     "CRTC %i appears to have a CRT attached\n", CRTCnumber);
583        } else
584        if(analog_on_B) {
585            CRTCnumber = outputBfromCRTC;
586            FlatPanel = 0;
587            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
588                     "CRTC %i appears to have a CRT attached\n", CRTCnumber);
589        } else
590        if(slaved_on_A) {
591           CRTCnumber = 0;
592           FlatPanel = 1;
593           Television = 1;
594           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
595                     "CRTC 0 is currently programmed for TV\n");
596        } else
597        if(slaved_on_B) {
598           CRTCnumber = 1;
599           FlatPanel = 1;
600           Television = 1;
601           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
602                     "CRTC 1 is currently programmed for TV\n");
603        } else
604        if(monitorA) {
605            FlatPanel = monitorA->features.input_type ? 1 : 0;
606        } else 
607        if(monitorB) {
608            FlatPanel = monitorB->features.input_type ? 1 : 0;
609        }
610
611        if(pNv->FlatPanel == -1) {
612           if(FlatPanel != -1) {
613              pNv->FlatPanel = FlatPanel;
614              pNv->Television = Television;
615           } else {
616              xf86DrvMsg(pScrn->scrnIndex, X_INFO,
617                         "Unable to detect display type...\n");
618              if(mobile) {
619                  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
620                             "...On a laptop, assuming DFP\n");
621                  pNv->FlatPanel = 1;
622              } else {
623                  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
624                             "...Using default of CRT\n");
625                  pNv->FlatPanel = 0;
626              }
627           }
628        } else {
629            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
630                       "Forcing display type to %s as specified\n", 
631                        pNv->FlatPanel ? "DFP" : "CRT");
632        }
633
634        if(pNv->CRTCnumber == -1) {
635           if(CRTCnumber != -1) pNv->CRTCnumber = CRTCnumber;
636           else {
637              xf86DrvMsg(pScrn->scrnIndex, X_INFO,
638                         "Unable to detect which CRTCNumber...\n");
639              if(pNv->FlatPanel) pNv->CRTCnumber = 1;
640              else pNv->CRTCnumber = 0;
641              xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
642                         "...Defaulting to CRTCNumber %i\n", pNv->CRTCnumber);
643           }
644        } else {
645            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
646                       "Forcing CRTCNumber %i as specified\n", pNv->CRTCnumber);
647        }
648      
649        if(monitorA) {
650            if((monitorA->features.input_type && pNv->FlatPanel) ||
651               (!monitorA->features.input_type && !pNv->FlatPanel))
652            {
653                if(monitorB) { 
654                   xfree(monitorB);
655                   monitorB = NULL;
656                }
657            } else {
658               xfree(monitorA);
659               monitorA = NULL;
660            }
661        }
662
663        if(monitorB) {
664            if((monitorB->features.input_type && !pNv->FlatPanel) ||
665               (!monitorB->features.input_type && pNv->FlatPanel)) 
666            {
667               xfree(monitorB);
668            } else {
669               monitorA = monitorB;
670            }
671            monitorB = NULL;
672        }
673
674        if(implementation == CHIPSET_NV11)
675            cr44 = pNv->CRTCnumber * 0x3;
676
677        pNv->PCRTC0[0x00000860/4] = oldhead;
678
679        VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
680        VGA_WR08(pNv->PCIO, 0x03D5, cr44);
681        NVSelectHeadRegisters(pScrn, pNv->CRTCnumber);
682     }
683
684     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
685               "Using %s on CRTC %i\n",
686               pNv->FlatPanel ? (pNv->Television ? "TV" : "DFP") : "CRT", 
687               pNv->CRTCnumber);
688
689     if(pNv->FlatPanel && !pNv->Television) {
690        pNv->fpWidth = pNv->PRAMDAC[0x0820/4] + 1;
691        pNv->fpHeight = pNv->PRAMDAC[0x0800/4] + 1;
692        pNv->fpSyncs = pNv->PRAMDAC[0x0848/4] & 0x30000033;
693        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x %i\n",
694                   pNv->fpWidth, pNv->fpHeight);
695     }
696
697     if(monitorA)
698       xf86SetDDCproperties(pScrn, monitorA);
699
700     if(!pNv->FlatPanel || (pScrn->depth != 24) || !pNv->twoHeads)
701         pNv->FPDither = FALSE;
702
703     pNv->LVDS = FALSE;
704     if(pNv->FlatPanel && pNv->twoHeads) {
705         pNv->PRAMDAC0[0x08B0/4] = 0x00010004;
706         if(pNv->PRAMDAC0[0x08B4/4] & 1)
707            pNv->LVDS = TRUE;
708         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel is %s\n", 
709                    pNv->LVDS ? "LVDS" : "TMDS");
710     }
711 }
712