remove PCRTC via macros
[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     CARD32 reg52C, reg608, temp;
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     reg52C = nvReadRAMDAC(pNv, output, 0x052C);
181     reg608 = nvReadRAMDAC(pNv, output, 0x0608);
182
183     nvWriteRAMDAC(pNv, output, 0x608, (reg608 & ~0x00010000));
184
185     nvWriteRAMDAC(pNv, output, 0x52C, (reg52C & 0x0000FEEE));
186     usleep(1000);
187     
188     temp = nvReadRAMDAC(pNv, output, 0x52C);
189     nvWriteRAMDAC(pNv, output, 0x52C, temp | 1);
190
191     nvWriteRAMDAC(pNv, output, 0x610, 0x94050140);
192     temp = nvReadRAMDAC(pNv, output, 0x608);
193     nvWriteRAMDAC(pNv, output, 0x608, temp | 0x1000);
194
195     usleep(1000);
196
197     present = (nvReadRAMDAC(pNv, output, 0x608) & (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     temp = nvReadRAMDAC(pNv, output, 0x608);
205     nvWriteRAMDAC(pNv, output, 0x608, temp & 0x000EFFF);
206
207     nvWriteRAMDAC(pNv, output, 0x52C, reg52C);
208     nvWriteRAMDAC(pNv, output, 0x608, reg608);
209
210     return present;
211 }
212
213 static void
214 NVSelectHeadRegisters(ScrnInfoPtr pScrn, int head)
215 {
216     NVPtr pNv = NVPTR(pScrn);
217
218     pNv->cur_head = head;
219
220     if(head) {
221        pNv->PCIO = pNv->PCIO1;
222        pNv->PCRTC = pNv->PCRTC1;
223        pNv->PRAMDAC = pNv->PRAMDAC1;
224        pNv->PDIO = pNv->PDIO1;
225     } else {
226        pNv->PCIO = pNv->PCIO0;
227        pNv->PCRTC = pNv->PCRTC0;
228        pNv->PRAMDAC = pNv->PRAMDAC0;
229        pNv->PDIO = pNv->PDIO0;
230     }
231 }
232
233 static xf86MonPtr 
234 NVProbeDDC (ScrnInfoPtr pScrn, int bus)
235 {
236     NVPtr pNv = NVPTR(pScrn);
237     xf86MonPtr MonInfo = NULL;
238
239     if(!pNv->I2C) return NULL;
240
241     pNv->DDCBase = bus ? 0x36 : 0x3e;
242
243     xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
244                "Probing for EDID on I2C bus %s...\n", bus ? "B" : "A");
245
246     if ((MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, pNv->I2C))) {
247        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
248                   "DDC detected a %s:\n", MonInfo->features.input_type ?
249                   "DFP" : "CRT");
250        xf86PrintEDID( MonInfo );
251     } else {
252        xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
253                   "  ... none found\n");
254     }
255
256     return MonInfo;
257 }
258
259 static void nv4GetConfig (NVPtr pNv)
260 {
261     CARD32 reg_FB0 = nvReadFB(pNv, 0x0);
262     if (reg_FB0 & 0x00000100) {
263         pNv->RamAmountKBytes = ((reg_FB0 >> 12) & 0x0F) * 1024 * 2
264                               + 1024 * 2;
265     } else {
266         switch (reg_FB0 & 0x00000003) {
267         case 0:
268             pNv->RamAmountKBytes = 1024 * 32;
269             break;
270         case 1:
271             pNv->RamAmountKBytes = 1024 * 4;
272             break;
273         case 2:
274             pNv->RamAmountKBytes = 1024 * 8;
275             break;
276         case 3:
277         default:
278             pNv->RamAmountKBytes = 1024 * 16;
279             break;
280         }
281     }
282     pNv->CrystalFreqKHz = (nvReadEXTDEV(pNv, 0x0000) & 0x00000040) ? 14318 : 13500;
283     pNv->CURSOR         = &(pNv->PRAMIN[0x1E00]);
284     pNv->MinVClockFreqKHz = 12000;
285     pNv->MaxVClockFreqKHz = 350000;
286 }
287
288 static void nv10GetConfig (NVPtr pNv)
289 {
290     CARD32 implementation = pNv->Chipset & 0x0ff0;
291
292 #if X_BYTE_ORDER == X_BIG_ENDIAN
293     /* turn on big endian register access */
294     if(!(nvReadMC(pNv, 0x0004) & 0x01000001)) {
295        nvWriteMC(pNv, 0x0004, 0x01000001);
296        mem_barrier();
297     }
298 #endif
299
300     if(implementation == CHIPSET_NFORCE) {
301         int amt = pciReadLong(pciTag(0, 0, 1), 0x7C);
302         pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
303     } else if(implementation == CHIPSET_NFORCE2) {
304         int amt = pciReadLong(pciTag(0, 0, 1), 0x84);
305         pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
306     } else {
307         pNv->RamAmountKBytes = (nvReadFB(pNv, 0x020C) & 0xFFF00000) >> 10;
308     }
309
310     if(pNv->RamAmountKBytes > 256*1024)
311         pNv->RamAmountKBytes = 256*1024;
312
313     pNv->CrystalFreqKHz = (nvReadEXTDEV(pNv, 0x0000) & (1 << 6)) ? 14318 : 13500;
314     
315     if(pNv->twoHeads && (implementation != CHIPSET_NV11))
316     {
317        if(nvReadEXTDEV(pNv, 0x0000) & (1 << 22))
318            pNv->CrystalFreqKHz = 27000;
319     }
320
321     pNv->CURSOR           = NULL;  /* can't set this here */
322     pNv->MinVClockFreqKHz = 12000;
323     pNv->MaxVClockFreqKHz = pNv->twoStagePLL ? 400000 : 350000;
324 }
325
326 void
327 NVCommonSetup(ScrnInfoPtr pScrn)
328 {
329     NVPtr pNv = NVPTR(pScrn);
330     vgaHWPtr pVga = VGAHWPTR(pScrn);
331     CARD16 implementation = pNv->Chipset & 0x0ff0;
332     xf86MonPtr monitorA, monitorB;
333     Bool mobile = FALSE;
334     Bool tvA = FALSE;
335     Bool tvB = FALSE;
336     int FlatPanel = -1;   /* really means the CRTC is slaved */
337     Bool Television = FALSE;
338     
339     /*
340      * Override VGA I/O routines.
341      */
342     pVga->writeCrtc         = NVWriteCrtc;
343     pVga->readCrtc          = NVReadCrtc;
344     pVga->writeGr           = NVWriteGr;
345     pVga->readGr            = NVReadGr;
346     pVga->writeAttr         = NVWriteAttr;
347     pVga->readAttr          = NVReadAttr;
348     pVga->writeSeq          = NVWriteSeq;
349     pVga->readSeq           = NVReadSeq;
350     pVga->writeMiscOut      = NVWriteMiscOut;
351     pVga->readMiscOut       = NVReadMiscOut;
352     pVga->enablePalette     = NVEnablePalette;
353     pVga->disablePalette    = NVDisablePalette;
354     pVga->writeDacMask      = NVWriteDacMask;
355     pVga->readDacMask       = NVReadDacMask;
356     pVga->writeDacWriteAddr = NVWriteDacWriteAddr;
357     pVga->writeDacReadAddr  = NVWriteDacReadAddr;
358     pVga->writeDacData      = NVWriteDacData;
359     pVga->readDacData       = NVReadDacData;
360     /*
361      * Note: There are different pointers to the CRTC/AR and GR/SEQ registers.
362      * Bastardize the intended uses of these to make it work.
363      */
364     pVga->MMIOBase   = (CARD8 *)pNv;
365     pVga->MMIOOffset = 0;
366     
367     pNv->REGS = xf86MapPciMem(pScrn->scrnIndex, 
368                               VIDMEM_MMIO | VIDMEM_READSIDEEFFECT, 
369                               pNv->PciTag, pNv->IOAddress, 0x01000000);
370
371     pNv->PRAMIN   = pNv->REGS + (NV_PRAMIN_OFFSET/4);
372     pNv->PCRTC0   = pNv->REGS + (NV_PCRTC0_OFFSET/4);
373     pNv->PRAMDAC0 = pNv->REGS + (NV_PRAMDAC0_OFFSET/4);
374     pNv->PFB      = pNv->REGS + (NV_PFB_OFFSET/4);
375     pNv->PFIFO    = pNv->REGS + (NV_PFIFO_OFFSET/4);
376     pNv->PGRAPH   = pNv->REGS + (NV_PGRAPH_OFFSET/4);
377     pNv->PEXTDEV  = pNv->REGS + (NV_PEXTDEV_OFFSET/4);
378     pNv->PTIMER   = pNv->REGS + (NV_PTIMER_OFFSET/4);
379     pNv->PMC      = pNv->REGS + (NV_PMC_OFFSET/4);
380
381     /* 8 bit registers */
382     pNv->PCIO0    = (CARD8*)pNv->REGS + NV_PCIO0_OFFSET;
383     pNv->PDIO0    = (CARD8*)pNv->REGS + NV_PDIO0_OFFSET;
384     pNv->PVIO     = (CARD8*)pNv->REGS + NV_PVIO_OFFSET;
385     pNv->PROM     = (CARD8*)pNv->REGS + NV_PROM_OFFSET;
386
387     pNv->PCRTC1   = pNv->PCRTC0 + 0x800;
388     pNv->PRAMDAC1 = pNv->PRAMDAC0 + 0x800;
389     pNv->PCIO1    = pNv->PCIO0 + 0x2000;
390     pNv->PDIO1    = pNv->PDIO0 + 0x2000;
391
392     pNv->twoHeads =  (pNv->Architecture >= NV_ARCH_10) &&
393                      (implementation != CHIPSET_NV10) &&
394                      (implementation != CHIPSET_NV15) &&
395                      (implementation != CHIPSET_NFORCE) &&
396                      (implementation != CHIPSET_NV20);
397
398     pNv->fpScaler = (pNv->FpScale && pNv->twoHeads && (implementation!=CHIPSET_NV11));
399
400     pNv->twoStagePLL = (implementation == CHIPSET_NV31) ||
401                        (implementation == CHIPSET_NV36) ||
402                        (pNv->Architecture >= NV_ARCH_40);
403
404     pNv->WaitVSyncPossible = (pNv->Architecture >= NV_ARCH_10) &&
405                              (implementation != CHIPSET_NV10);
406
407     pNv->BlendingPossible = ((pNv->Chipset & 0xffff) != CHIPSET_NV04);
408
409     /* look for known laptop chips */
410     /* FIXME we could add some ids here (0x0164,0x0167,0x0168,0x01D6,0x01D7,0x01D8,0x0298,0x0299,0x0398) */
411     switch(pNv->Chipset & 0xffff) {
412     case 0x0112:
413     case 0x0174:
414     case 0x0175:
415     case 0x0176:
416     case 0x0177:
417     case 0x0179:
418     case 0x017C:
419     case 0x017D:
420     case 0x0186:
421     case 0x0187:
422     case 0x018D:
423     case 0x0228:
424     case 0x0286:
425     case 0x028C:
426     case 0x0316:
427     case 0x0317:
428     case 0x031A:
429     case 0x031B:
430     case 0x031C:
431     case 0x031D:
432     case 0x031E:
433     case 0x031F:
434     case 0x0324:
435     case 0x0325:
436     case 0x0328:
437     case 0x0329:
438     case 0x032C:
439     case 0x032D:
440     case 0x0347:
441     case 0x0348:
442     case 0x0349:
443     case 0x034B:
444     case 0x034C:
445     case 0x0160:
446     case 0x0166:
447     case 0x0169:
448     case 0x016B:
449     case 0x016C:
450     case 0x016D:
451     case 0x00C8:
452     case 0x00CC:
453     case 0x0144:
454     case 0x0146:
455     case 0x0148:
456     case 0x0098:
457     case 0x0099:
458         mobile = TRUE;
459         break;
460     default:
461         break;
462     }
463
464     /* Parse the bios to initialize the card */
465     NVSelectHeadRegisters(pScrn, 0);
466     NVParseBios(pScrn);
467     /* reset PFIFO and PGRAPH, then power up all the card units */
468 /*    nvWriteMC(pNv, 0x800, 0x17110013);
469     usleep(1000);*/
470     nvWriteMC(pNv, 0x800, 0x17111113);
471
472     if(pNv->Architecture == NV_ARCH_04)
473         nv4GetConfig(pNv);
474     else
475         nv10GetConfig(pNv);
476
477     NVSelectHeadRegisters(pScrn, 0);
478
479     NVLockUnlock(pNv, 0);
480
481     NVI2CInit(pScrn);
482
483     pNv->Television = FALSE;
484
485     if(!pNv->twoHeads) {
486        pNv->CRTCnumber = 0;
487        if((monitorA = NVProbeDDC(pScrn, 0))) {
488            FlatPanel = monitorA->features.input_type ? 1 : 0;
489
490            /* NV4 doesn't support FlatPanels */
491            if((pNv->Chipset & 0x0fff) <= CHIPSET_NV04)
492               FlatPanel = 0;
493        } else {
494            if(nvReadVGA(pNv, 0x28) & 0x80) {
495               if(!(nvReadVGA(pNv, 0x33) & 0x01)) 
496                  Television = TRUE;
497               FlatPanel = 1;
498            } else {
499               FlatPanel = 0;
500            }
501            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
502                          "HW is currently programmed for %s\n",
503                           FlatPanel ? (Television ? "TV" : "DFP") : "CRT");
504        } 
505
506        if(pNv->FlatPanel == -1) {
507            pNv->FlatPanel = FlatPanel;
508            pNv->Television = Television;
509        } else {
510            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
511                       "Forcing display type to %s as specified\n", 
512                        pNv->FlatPanel ? "DFP" : "CRT");
513        }
514     } else {
515        CARD8 outputAfromCRTC, outputBfromCRTC;
516        int CRTCnumber = -1;
517        CARD8 slaved_on_A, slaved_on_B;
518        Bool analog_on_A, analog_on_B;
519        CARD32 oldhead;
520        CARD8 cr44;
521       
522        if(implementation != CHIPSET_NV11) {
523            if(nvReadRAMDAC0(pNv, 0x52c) & 0x100)
524                outputAfromCRTC = 1;
525            else            
526                outputAfromCRTC = 0;
527            if(nvReadRAMDAC(pNv, 1, 0x52C) & 0x100)
528                outputBfromCRTC = 1;
529            else
530                outputBfromCRTC = 0;
531           analog_on_A = NVIsConnected(pScrn, 0);
532           analog_on_B = NVIsConnected(pScrn, 1);
533        } else {
534           outputAfromCRTC = 0;
535           outputBfromCRTC = 1;
536           analog_on_A = FALSE;
537           analog_on_B = FALSE;
538        }
539
540        cr44 = nvReadVGA(pNv, 0x44);
541        pNv->vtOWNER = cr44;
542
543        nvWriteVGA(pNv, 0x44, 3);
544        NVSelectHeadRegisters(pScrn, 1);
545        NVLockUnlock(pNv, 0);
546
547        slaved_on_B = nvReadVGA(pNv, 0x28) & 0x80;
548        if(slaved_on_B) {
549            tvB = !(nvReadVGA(pNv, 0x33) & 0x01);
550        }
551
552        nvWriteVGA(pNv, 0x44, 0);
553        NVSelectHeadRegisters(pScrn, 0);
554        NVLockUnlock(pNv, 0);
555
556        slaved_on_A = nvReadVGA(pNv, 0x28) & 0x80; 
557        if(slaved_on_A) {
558            tvA = !(nvReadVGA(pNv, 0x33) & 0x01);
559        }
560
561        oldhead = nvReadCRTC0(pNv, 0x0860);
562        nvWriteCRTC0(pNv, 0x0860, oldhead | 0x00000010);
563
564        monitorA = NVProbeDDC(pScrn, 0);
565        monitorB = NVProbeDDC(pScrn, 1);
566
567        if(slaved_on_A && !tvA) {
568           CRTCnumber = 0;
569           FlatPanel = 1;
570           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
571                     "CRTC 0 is currently programmed for DFP\n");
572        } else 
573        if(slaved_on_B && !tvB) {
574           CRTCnumber = 1;
575           FlatPanel = 1;
576           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
577                     "CRTC 1 is currently programmed for DFP\n");
578        } else
579        if(analog_on_A) {
580           CRTCnumber = outputAfromCRTC;
581           FlatPanel = 0;
582           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
583                     "CRTC %i appears to have a CRT attached\n", CRTCnumber);
584        } else
585        if(analog_on_B) {
586            CRTCnumber = outputBfromCRTC;
587            FlatPanel = 0;
588            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
589                     "CRTC %i appears to have a CRT attached\n", CRTCnumber);
590        } else
591        if(slaved_on_A) {
592           CRTCnumber = 0;
593           FlatPanel = 1;
594           Television = 1;
595           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
596                     "CRTC 0 is currently programmed for TV\n");
597        } else
598        if(slaved_on_B) {
599           CRTCnumber = 1;
600           FlatPanel = 1;
601           Television = 1;
602           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
603                     "CRTC 1 is currently programmed for TV\n");
604        } else
605        if(monitorA) {
606            FlatPanel = monitorA->features.input_type ? 1 : 0;
607        } else 
608        if(monitorB) {
609            FlatPanel = monitorB->features.input_type ? 1 : 0;
610        }
611
612        if(pNv->FlatPanel == -1) {
613           if(FlatPanel != -1) {
614              pNv->FlatPanel = FlatPanel;
615              pNv->Television = Television;
616           } else {
617              xf86DrvMsg(pScrn->scrnIndex, X_INFO,
618                         "Unable to detect display type...\n");
619              if(mobile) {
620                  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
621                             "...On a laptop, assuming DFP\n");
622                  pNv->FlatPanel = 1;
623              } else {
624                  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
625                             "...Using default of CRT\n");
626                  pNv->FlatPanel = 0;
627              }
628           }
629        } else {
630            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
631                       "Forcing display type to %s as specified\n", 
632                        pNv->FlatPanel ? "DFP" : "CRT");
633        }
634
635        if(pNv->CRTCnumber == -1) {
636           if(CRTCnumber != -1) pNv->CRTCnumber = CRTCnumber;
637           else {
638              xf86DrvMsg(pScrn->scrnIndex, X_INFO,
639                         "Unable to detect which CRTCNumber...\n");
640              if(pNv->FlatPanel) pNv->CRTCnumber = 1;
641              else pNv->CRTCnumber = 0;
642              xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
643                         "...Defaulting to CRTCNumber %i\n", pNv->CRTCnumber);
644           }
645        } else {
646            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
647                       "Forcing CRTCNumber %i as specified\n", pNv->CRTCnumber);
648        }
649      
650        if(monitorA) {
651            if((monitorA->features.input_type && pNv->FlatPanel) ||
652               (!monitorA->features.input_type && !pNv->FlatPanel))
653            {
654                if(monitorB) { 
655                   xfree(monitorB);
656                   monitorB = NULL;
657                }
658            } else {
659               xfree(monitorA);
660               monitorA = NULL;
661            }
662        }
663
664        if(monitorB) {
665            if((monitorB->features.input_type && !pNv->FlatPanel) ||
666               (!monitorB->features.input_type && pNv->FlatPanel)) 
667            {
668               xfree(monitorB);
669            } else {
670               monitorA = monitorB;
671            }
672            monitorB = NULL;
673        }
674
675        if(implementation == CHIPSET_NV11)
676            cr44 = pNv->CRTCnumber * 0x3;
677
678        nvWriteCRTC0(pNv, 0x0860,  oldhead);
679
680        nvWriteVGA(pNv, 0x44, 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 = nvReadCurRAMDAC(pNv, 0x820) + 1;
691        pNv->fpHeight = nvReadCurRAMDAC(pNv, 0x800) + 1;
692        pNv->fpSyncs = nvReadCurRAMDAC(pNv, 0x0848) & 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         nvWriteRAMDAC0(pNv, 0x8b0, 0x00010004);
706         if(nvReadRAMDAC0(pNv, 0x08B4) & 1)
707            pNv->LVDS = TRUE;
708         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel is %s\n", 
709                    pNv->LVDS ? "LVDS" : "TMDS");
710     }
711 }
712