Merge branch 'randr-1.2' into nv50-branch
[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 CARD32 debug_offset;
46
47 /*
48  * Override VGA I/O routines.
49  */
50 static void NVWriteCrtc(vgaHWPtr pVga, CARD8 index, CARD8 value)
51 {
52     NVPtr pNv = (NVPtr)pVga->MMIOBase;
53     volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
54     VGA_WR08(ptr, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
55     VGA_WR08(ptr, pVga->IOBase + VGA_CRTC_DATA_OFFSET,  value);
56 }
57 static CARD8 NVReadCrtc(vgaHWPtr pVga, CARD8 index)
58 {
59     NVPtr pNv = (NVPtr)pVga->MMIOBase;
60     volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
61     VGA_WR08(ptr, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
62     return (VGA_RD08(ptr, pVga->IOBase + VGA_CRTC_DATA_OFFSET));
63 }
64 static void NVWriteGr(vgaHWPtr pVga, CARD8 index, CARD8 value)
65 {
66     NVPtr pNv = (NVPtr)pVga->MMIOBase;
67     VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
68     VGA_WR08(pNv->PVIO, VGA_GRAPH_DATA,  value);
69 }
70 static CARD8 NVReadGr(vgaHWPtr pVga, CARD8 index)
71 {
72     NVPtr pNv = (NVPtr)pVga->MMIOBase;
73     VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
74     return (VGA_RD08(pNv->PVIO, VGA_GRAPH_DATA));
75 }
76 static void NVWriteSeq(vgaHWPtr pVga, CARD8 index, CARD8 value)
77 {
78     NVPtr pNv = (NVPtr)pVga->MMIOBase;
79     VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
80     VGA_WR08(pNv->PVIO, VGA_SEQ_DATA,  value);
81 }
82 static CARD8 NVReadSeq(vgaHWPtr pVga, CARD8 index)
83 {
84     NVPtr pNv = (NVPtr)pVga->MMIOBase;
85     VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
86     return (VGA_RD08(pNv->PVIO, VGA_SEQ_DATA));
87 }
88 static void NVWriteAttr(vgaHWPtr pVga, CARD8 index, CARD8 value)
89 {
90     NVPtr pNv = (NVPtr)pVga->MMIOBase;
91     volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
92     volatile CARD8 tmp;
93
94     tmp = VGA_RD08(ptr, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
95     if (pVga->paletteEnabled)
96         index &= ~0x20;
97     else
98         index |= 0x20;
99     VGA_WR08(ptr, VGA_ATTR_INDEX,  index);
100     VGA_WR08(ptr, VGA_ATTR_DATA_W, value);
101 }
102 static CARD8 NVReadAttr(vgaHWPtr pVga, CARD8 index)
103 {
104     NVPtr pNv = (NVPtr)pVga->MMIOBase;
105     volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
106     volatile CARD8 tmp;
107
108     tmp = VGA_RD08(ptr, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
109     if (pVga->paletteEnabled)
110         index &= ~0x20;
111     else
112         index |= 0x20;
113     VGA_WR08(ptr, VGA_ATTR_INDEX, index);
114     return (VGA_RD08(ptr, VGA_ATTR_DATA_R));
115 }
116 static void NVWriteMiscOut(vgaHWPtr pVga, CARD8 value)
117 {
118     NVPtr pNv = (NVPtr)pVga->MMIOBase;
119     VGA_WR08(pNv->PVIO, VGA_MISC_OUT_W, value);
120 }
121 static CARD8 NVReadMiscOut(vgaHWPtr pVga)
122 {
123     NVPtr pNv = (NVPtr)pVga->MMIOBase;
124     return (VGA_RD08(pNv->PVIO, VGA_MISC_OUT_R));
125 }
126 static void NVEnablePalette(vgaHWPtr pVga)
127 {
128     NVPtr pNv = (NVPtr)pVga->MMIOBase;
129     volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
130     volatile CARD8 tmp;
131
132     tmp = VGA_RD08(ptr, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
133     VGA_WR08(ptr, VGA_ATTR_INDEX, 0x00);
134     pVga->paletteEnabled = TRUE;
135 }
136 static void NVDisablePalette(vgaHWPtr pVga)
137 {
138     NVPtr pNv = (NVPtr)pVga->MMIOBase;
139     volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
140     volatile CARD8 tmp;
141
142     tmp = VGA_RD08(ptr, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
143     VGA_WR08(ptr, VGA_ATTR_INDEX, 0x20);
144     pVga->paletteEnabled = FALSE;
145 }
146 static void NVWriteDacMask(vgaHWPtr pVga, CARD8 value)
147 {
148     NVPtr pNv = (NVPtr)pVga->MMIOBase;
149     volatile CARD8 *ptr = pNv->cur_head ? pNv->PDIO1 : pNv->PDIO0;
150     VGA_WR08(ptr, VGA_DAC_MASK, value);
151 }
152 static CARD8 NVReadDacMask(vgaHWPtr pVga)
153 {
154     NVPtr pNv = (NVPtr)pVga->MMIOBase;
155     volatile CARD8 *ptr = pNv->cur_head ? pNv->PDIO1 : pNv->PDIO0;
156     return (VGA_RD08(ptr, VGA_DAC_MASK));
157 }
158 static void NVWriteDacReadAddr(vgaHWPtr pVga, CARD8 value)
159 {
160     NVPtr pNv = (NVPtr)pVga->MMIOBase;
161     volatile CARD8 *ptr = pNv->cur_head ? pNv->PDIO1 : pNv->PDIO0;
162     VGA_WR08(ptr, VGA_DAC_READ_ADDR, value);
163 }
164 static void NVWriteDacWriteAddr(vgaHWPtr pVga, CARD8 value)
165 {
166     NVPtr pNv = (NVPtr)pVga->MMIOBase;
167     volatile CARD8 *ptr = pNv->cur_head ? pNv->PDIO1 : pNv->PDIO0;
168     VGA_WR08(ptr, VGA_DAC_WRITE_ADDR, value);
169 }
170 static void NVWriteDacData(vgaHWPtr pVga, CARD8 value)
171 {
172     NVPtr pNv = (NVPtr)pVga->MMIOBase;
173     volatile CARD8 *ptr = pNv->cur_head ? pNv->PDIO1 : pNv->PDIO0;
174     VGA_WR08(ptr, VGA_DAC_DATA, value);
175 }
176 static CARD8 NVReadDacData(vgaHWPtr pVga)
177 {
178     NVPtr pNv = (NVPtr)pVga->MMIOBase;
179     volatile CARD8 *ptr = pNv->cur_head ? pNv->PDIO1 : pNv->PDIO0;
180     return (VGA_RD08(ptr, VGA_DAC_DATA));
181 }
182
183 static void
184 NVSelectHeadRegisters(ScrnInfoPtr pScrn, int head)
185 {
186     NVPtr pNv = NVPTR(pScrn);
187
188     pNv->cur_head = head;
189 }
190
191 static void nv3GetConfig (NVPtr pNv)
192 {
193     CARD32 reg_FB0 = nvReadFB(pNv, 0x0);
194     switch (reg_FB0 & 0x00000003) {
195     case 0:
196         pNv->RamAmountKBytes = 1024 * 8;
197         break;
198     case 1:
199         pNv->RamAmountKBytes = 1024 * 2;
200         break;
201     case 2:
202         pNv->RamAmountKBytes = 1024 * 4;
203         break;
204     default:
205         pNv->RamAmountKBytes = 1024 * 8;
206         break;
207     }
208     pNv->CrystalFreqKHz   = (nvReadEXTDEV(pNv, 0x0000) & 0x00000040) ? 14318 : 13500;
209     pNv->CURSOR           = &(pNv->PRAMIN[0x00008000/4 - 0x0800/4]);
210     pNv->MinVClockFreqKHz = 12000;
211     pNv->MaxVClockFreqKHz = 256000;
212 }
213
214 static void nv4GetConfig (NVPtr pNv)
215 {
216     CARD32 reg_FB0 = nvReadFB(pNv, 0x0);
217     if (reg_FB0 & 0x00000100) {
218         pNv->RamAmountKBytes = ((reg_FB0 >> 12) & 0x0F) * 1024 * 2
219                               + 1024 * 2;
220     } else {
221         switch (reg_FB0 & 0x00000003) {
222         case 0:
223             pNv->RamAmountKBytes = 1024 * 32;
224             break;
225         case 1:
226             pNv->RamAmountKBytes = 1024 * 4;
227             break;
228         case 2:
229             pNv->RamAmountKBytes = 1024 * 8;
230             break;
231         case 3:
232         default:
233             pNv->RamAmountKBytes = 1024 * 16;
234             break;
235         }
236     }
237     pNv->CrystalFreqKHz = (nvReadEXTDEV(pNv, 0x0000) & 0x00000040) ? 14318 : 13500;
238     pNv->CURSOR         = &(pNv->PRAMIN[0x1E00]);
239     pNv->MinVClockFreqKHz = 12000;
240     pNv->MaxVClockFreqKHz = 350000;
241 }
242
243 static void nv10GetConfig (NVPtr pNv)
244 {
245     CARD32 implementation = pNv->Chipset & 0x0ff0;
246
247 #if X_BYTE_ORDER == X_BIG_ENDIAN
248     /* turn on big endian register access */
249     if(!(nvReadMC(pNv, 0x0004) & 0x01000001)) {
250        nvWriteMC(pNv, 0x0004, 0x01000001);
251        mem_barrier();
252     }
253 #endif
254
255     if(implementation == CHIPSET_NFORCE) {
256         int amt = pciReadLong(pciTag(0, 0, 1), 0x7C);
257         pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
258     } else if(implementation == CHIPSET_NFORCE2) {
259         int amt = pciReadLong(pciTag(0, 0, 1), 0x84);
260         pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
261     } else {
262         pNv->RamAmountKBytes = (nvReadFB(pNv, 0x020C) & 0xFFF00000) >> 10;
263     }
264
265     if(pNv->RamAmountKBytes > 256*1024)
266         pNv->RamAmountKBytes = 256*1024;
267
268     pNv->CrystalFreqKHz = (nvReadEXTDEV(pNv, 0x0000) & (1 << 6)) ? 14318 : 13500;
269     
270     if(pNv->twoHeads && (implementation != CHIPSET_NV11))
271     {
272        if(nvReadEXTDEV(pNv, 0x0000) & (1 << 22))
273            pNv->CrystalFreqKHz = 27000;
274     }
275
276     pNv->CURSOR           = NULL;  /* can't set this here */
277     pNv->MinVClockFreqKHz = 12000;
278     pNv->MaxVClockFreqKHz = pNv->twoStagePLL ? 400000 : 350000;
279 }
280
281 void
282 NVCommonSetup(ScrnInfoPtr pScrn)
283 {
284     NVPtr pNv = NVPTR(pScrn);
285     vgaHWPtr pVga = VGAHWPTR(pScrn);
286     CARD16 implementation = pNv->Chipset & 0x0ff0;
287     
288     /*
289      * Override VGA I/O routines.
290      */
291     pVga->writeCrtc         = NVWriteCrtc;
292     pVga->readCrtc          = NVReadCrtc;
293     pVga->writeGr           = NVWriteGr;
294     pVga->readGr            = NVReadGr;
295     pVga->writeAttr         = NVWriteAttr;
296     pVga->readAttr          = NVReadAttr;
297     pVga->writeSeq          = NVWriteSeq;
298     pVga->readSeq           = NVReadSeq;
299     pVga->writeMiscOut      = NVWriteMiscOut;
300     pVga->readMiscOut       = NVReadMiscOut;
301     pVga->enablePalette     = NVEnablePalette;
302     pVga->disablePalette    = NVDisablePalette;
303     pVga->writeDacMask      = NVWriteDacMask;
304     pVga->readDacMask       = NVReadDacMask;
305     pVga->writeDacWriteAddr = NVWriteDacWriteAddr;
306     pVga->writeDacReadAddr  = NVWriteDacReadAddr;
307     pVga->writeDacData      = NVWriteDacData;
308     pVga->readDacData       = NVReadDacData;
309     /*
310      * Note: There are different pointers to the CRTC/AR and GR/SEQ registers.
311      * Bastardize the intended uses of these to make it work.
312      */
313     pVga->MMIOBase   = (CARD8 *)pNv;
314     pVga->MMIOOffset = 0;
315     
316     pNv->REGS = xf86MapPciMem(pScrn->scrnIndex, 
317                               VIDMEM_MMIO | VIDMEM_READSIDEEFFECT, 
318                               pNv->PciTag, pNv->IOAddress, 0x01000000);
319     
320     debug_offset = pNv->REGS;
321     pNv->PRAMIN   = pNv->REGS + (NV_PRAMIN_OFFSET/4);
322     pNv->PCRTC0   = pNv->REGS + (NV_PCRTC0_OFFSET/4);
323     pNv->PRAMDAC0 = pNv->REGS + (NV_PRAMDAC0_OFFSET/4);
324     pNv->PFB      = pNv->REGS + (NV_PFB_OFFSET/4);
325     pNv->PFIFO    = pNv->REGS + (NV_PFIFO_OFFSET/4);
326     pNv->PGRAPH   = pNv->REGS + (NV_PGRAPH_OFFSET/4);
327     pNv->PEXTDEV  = pNv->REGS + (NV_PEXTDEV_OFFSET/4);
328     pNv->PTIMER   = pNv->REGS + (NV_PTIMER_OFFSET/4);
329     pNv->PVIDEO   = pNv->REGS + (NV_PVIDEO_OFFSET/4);
330     pNv->PMC      = pNv->REGS + (NV_PMC_OFFSET/4);
331
332     /* 8 bit registers */
333     pNv->PCIO0    = (CARD8*)pNv->REGS + NV_PCIO0_OFFSET;
334     pNv->PDIO0    = (CARD8*)pNv->REGS + NV_PDIO0_OFFSET;
335     pNv->PVIO     = (CARD8*)pNv->REGS + NV_PVIO_OFFSET;
336     pNv->PROM     = (CARD8*)pNv->REGS + NV_PROM_OFFSET;
337
338     pNv->PCRTC1   = pNv->PCRTC0 + 0x800;
339     pNv->PRAMDAC1 = pNv->PRAMDAC0 + 0x800;
340     pNv->PCIO1    = pNv->PCIO0 + 0x2000;
341     pNv->PDIO1    = pNv->PDIO0 + 0x2000;
342
343     pNv->twoHeads =  (pNv->Architecture >= NV_ARCH_10) &&
344                      (implementation != CHIPSET_NV10) &&
345                      (implementation != CHIPSET_NV15) &&
346                      (implementation != CHIPSET_NFORCE) &&
347                      (implementation != CHIPSET_NV20);
348
349     pNv->fpScaler = (pNv->FpScale && pNv->twoHeads && (implementation!=CHIPSET_NV11));
350
351     pNv->twoStagePLL = (implementation == CHIPSET_NV31) ||
352                        (implementation == CHIPSET_NV36) ||
353                        (pNv->Architecture >= NV_ARCH_40);
354
355     pNv->WaitVSyncPossible = (pNv->Architecture >= NV_ARCH_10) &&
356                              (implementation != CHIPSET_NV10);
357
358     pNv->BlendingPossible = ((pNv->Chipset & 0xffff) > CHIPSET_NV04);
359
360     /* Chipset from PMC_BOOT_0 register */
361     if (pNv->Architecture == NV_ARCH_04) {
362             pNv->_Chipset = 0x04;
363     } else {
364             pNv->_Chipset = (nvReadMC(pNv, 0) >> 20) & 0xff;
365     }
366
367     /* Parse the bios to initialize the card */
368     NVSelectHeadRegisters(pScrn, 0);
369     NVParseBios(pScrn);
370 #if 0
371     /* reset PFIFO and PGRAPH, then power up all the card units */
372     nvWriteMC(pNv, 0x200, 0x17110013);
373     usleep(1000);
374     nvWriteMC(pNv, 0x200, 0x17111113);
375 #endif
376
377     if(pNv->Architecture == NV_ARCH_03)
378         nv3GetConfig(pNv);
379     else if(pNv->Architecture == NV_ARCH_04)
380         nv4GetConfig(pNv);
381     else
382         nv10GetConfig(pNv);
383
384     NVSelectHeadRegisters(pScrn, 0);
385
386     pNv->vtOWNER = nvReadVGA(pNv, NV_VGA_CRTCX_OWNER);
387
388     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "vtowner is %d\n", pNv->vtOWNER);
389     /* look for known laptop chips */
390     /* FIXME we could add some ids here (0x0164,0x0167,0x0168,0x01D6,0x01D7,0x01D8,0x0298,0x0299,0x0398) */
391     switch(pNv->Chipset & 0xffff) {
392     case 0x0112:
393     case 0x0174:
394     case 0x0175:
395     case 0x0176:
396     case 0x0177:
397     case 0x0179:
398     case 0x017C:
399     case 0x017D:
400     case 0x0186:
401     case 0x0187:
402     case 0x018D:
403     case 0x0228:
404     case 0x0286:
405     case 0x028C:
406     case 0x0316:
407     case 0x0317:
408     case 0x031A:
409     case 0x031B:
410     case 0x031C:
411     case 0x031D:
412     case 0x031E:
413     case 0x031F:
414     case 0x0324:
415     case 0x0325:
416     case 0x0328:
417     case 0x0329:
418     case 0x032C:
419     case 0x032D:
420     case 0x0347:
421     case 0x0348:
422     case 0x0349:
423     case 0x034B:
424     case 0x034C:
425     case 0x0160:
426     case 0x0166:
427     case 0x0169:
428     case 0x016B:
429     case 0x016C:
430     case 0x016D:
431     case 0x00C8:
432     case 0x00CC:
433     case 0x0144:
434     case 0x0146:
435     case 0x0148:
436     case 0x0098:
437     case 0x0099:
438         pNv->Mobile = TRUE;
439         break;
440     default:
441         break;
442     }
443
444     pNv->Television = FALSE;
445
446 }
447
448 #if 0
449 void NVPreInitOldCode(ScrnInfoPtr pScrn)
450 {
451   NVPtr pNv = NVPTR(pScrn);
452     xf86MonPtr monitorA, monitorB;
453     Bool mobile = pNv->Mobile;
454     Bool tvA = FALSE;
455     Bool tvB = FALSE;
456     int FlatPanel = -1;   /* really means the CRTC is slaved */
457     Bool Television = FALSE;
458     CARD16 implementation = pNv->Chipset & 0x0ff0;
459
460     if(!pNv->twoHeads) {
461        pNv->CRTCnumber = 0;
462        if((monitorA = NVProbeDDC(pScrn, 0))) {
463            FlatPanel = monitorA->features.input_type ? 1 : 0;
464
465            /* NV4 doesn't support FlatPanels */
466            if((pNv->Chipset & 0x0fff) <= CHIPSET_NV04)
467               FlatPanel = 0;
468        } else {
469            if(nvReadVGA(pNv, NV_VGA_CRTCX_PIXEL) & 0x80) {
470               if(!(nvReadVGA(pNv, NV_VGA_CRTCX_LCD) & 0x01)) 
471                  Television = TRUE;
472               FlatPanel = 1;
473            } else {
474               FlatPanel = 0;
475            }
476            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
477                          "HW is currently programmed for %s\n",
478                           FlatPanel ? (Television ? "TV" : "DFP") : "CRT");
479        } 
480
481        if(pNv->FlatPanel == -1) {
482            pNv->FlatPanel = FlatPanel;
483            pNv->Television = Television;
484        } else {
485            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
486                       "Forcing display type to %s as specified\n", 
487                        pNv->FlatPanel ? "DFP" : "CRT");
488        }
489     } else {
490        CARD8 outputAfromCRTC, outputBfromCRTC;
491        int CRTCnumber = -1;
492        CARD8 slaved_on_A, slaved_on_B;
493        Bool analog_on_A, analog_on_B;
494        CARD32 oldhead;
495        CARD8 cr44;
496       
497        if(implementation != CHIPSET_NV11) {
498            if(nvReadRAMDAC0(pNv, NV_RAMDAC_052C) & 0x100)
499                outputAfromCRTC = 1;
500            else            
501                outputAfromCRTC = 0;
502            if(nvReadRAMDAC(pNv, 1, NV_RAMDAC_052C) & 0x100)
503                outputBfromCRTC = 1;
504            else
505                outputBfromCRTC = 0;
506           analog_on_A = NVIsConnected(pScrn, 0);
507           analog_on_B = NVIsConnected(pScrn, 1);
508        } else {
509           outputAfromCRTC = 0;
510           outputBfromCRTC = 1;
511           analog_on_A = FALSE;
512           analog_on_B = FALSE;
513        }
514
515        cr44 = nvReadVGA(pNv, NV_VGA_CRTCX_OWNER);
516        pNv->vtOWNER = cr44;
517
518        nvWriteVGA(pNv, NV_VGA_CRTCX_OWNER, 3);
519        NVSelectHeadRegisters(pScrn, 1);
520        NVLockUnlock(pNv, 0);
521
522        slaved_on_B = nvReadVGA(pNv, NV_VGA_CRTCX_PIXEL) & 0x80;
523        if(slaved_on_B) {
524            tvB = !(nvReadVGA(pNv, NV_VGA_CRTCX_LCD) & 0x01);
525        }
526
527        nvWriteVGA(pNv, NV_VGA_CRTCX_OWNER, 0);
528        NVSelectHeadRegisters(pScrn, 0);
529        NVLockUnlock(pNv, 0);
530
531        slaved_on_A = nvReadVGA(pNv, NV_VGA_CRTCX_PIXEL) & 0x80; 
532        if(slaved_on_A) {
533            tvA = !(nvReadVGA(pNv, NV_VGA_CRTCX_LCD) & 0x01);
534        }
535
536        oldhead = nvReadCRTC0(pNv, NV_CRTC_HEAD_CONFIG);
537        nvWriteCRTC0(pNv, NV_CRTC_HEAD_CONFIG, oldhead | 0x00000010);
538
539        monitorA = NVProbeDDC(pScrn, 0);
540        monitorB = NVProbeDDC(pScrn, 1);
541
542        if(slaved_on_A && !tvA) {
543           CRTCnumber = 0;
544           FlatPanel = 1;
545           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
546                     "CRTC 0 is currently programmed for DFP\n");
547        } else 
548        if(slaved_on_B && !tvB) {
549           CRTCnumber = 1;
550           FlatPanel = 1;
551           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
552                     "CRTC 1 is currently programmed for DFP\n");
553        } else
554        if(analog_on_A) {
555           CRTCnumber = outputAfromCRTC;
556           FlatPanel = 0;
557           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
558                     "CRTC %i appears to have a CRT attached\n", CRTCnumber);
559        } else
560        if(analog_on_B) {
561            CRTCnumber = outputBfromCRTC;
562            FlatPanel = 0;
563            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
564                     "CRTC %i appears to have a CRT attached\n", CRTCnumber);
565        } else
566        if(slaved_on_A) {
567           CRTCnumber = 0;
568           FlatPanel = 1;
569           Television = 1;
570           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
571                     "CRTC 0 is currently programmed for TV\n");
572        } else
573        if(slaved_on_B) {
574           CRTCnumber = 1;
575           FlatPanel = 1;
576           Television = 1;
577           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
578                     "CRTC 1 is currently programmed for TV\n");
579        } else
580        if(monitorA) {
581            FlatPanel = monitorA->features.input_type ? 1 : 0;
582        } else 
583        if(monitorB) {
584            FlatPanel = monitorB->features.input_type ? 1 : 0;
585        }
586
587        if(pNv->FlatPanel == -1) {
588           if(FlatPanel != -1) {
589              pNv->FlatPanel = FlatPanel;
590              pNv->Television = Television;
591           } else {
592              xf86DrvMsg(pScrn->scrnIndex, X_INFO,
593                         "Unable to detect display type...\n");
594              if(mobile) {
595                  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
596                             "...On a laptop, assuming DFP\n");
597                  pNv->FlatPanel = 1;
598              } else {
599                  xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
600                             "...Using default of CRT\n");
601                  pNv->FlatPanel = 0;
602              }
603           }
604        } else {
605            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
606                       "Forcing display type to %s as specified\n", 
607                        pNv->FlatPanel ? "DFP" : "CRT");
608        }
609
610        if(pNv->CRTCnumber == -1) {
611           if(CRTCnumber != -1) pNv->CRTCnumber = CRTCnumber;
612           else {
613              xf86DrvMsg(pScrn->scrnIndex, X_INFO,
614                         "Unable to detect which CRTCNumber...\n");
615              if(pNv->FlatPanel) pNv->CRTCnumber = 1;
616              else pNv->CRTCnumber = 0;
617              xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
618                         "...Defaulting to CRTCNumber %i\n", pNv->CRTCnumber);
619           }
620        } else {
621            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
622                       "Forcing CRTCNumber %i as specified\n", pNv->CRTCnumber);
623        }
624      
625        if(monitorA) {
626            if((monitorA->features.input_type && pNv->FlatPanel) ||
627               (!monitorA->features.input_type && !pNv->FlatPanel))
628            {
629                if(monitorB) { 
630                   xfree(monitorB);
631                   monitorB = NULL;
632                }
633            } else {
634               xfree(monitorA);
635               monitorA = NULL;
636            }
637        }
638
639        if(monitorB) {
640            if((monitorB->features.input_type && !pNv->FlatPanel) ||
641               (!monitorB->features.input_type && pNv->FlatPanel)) 
642            {
643               xfree(monitorB);
644            } else {
645               monitorA = monitorB;
646            }
647            monitorB = NULL;
648        }
649
650        if(implementation == CHIPSET_NV11)
651            cr44 = pNv->CRTCnumber * 0x3;
652
653        nvWriteCRTC0(pNv, NV_CRTC_HEAD_CONFIG,  oldhead);
654
655        nvWriteVGA(pNv, NV_VGA_CRTCX_OWNER, cr44);
656        NVSelectHeadRegisters(pScrn, pNv->CRTCnumber);
657     }
658
659     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
660               "Using %s on CRTC %i\n",
661               pNv->FlatPanel ? (pNv->Television ? "TV" : "DFP") : "CRT", 
662               pNv->CRTCnumber);
663
664     if(pNv->FlatPanel && !pNv->Television) {
665        pNv->fpWidth = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_HDISP_END) + 1;
666        pNv->fpHeight = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_VDISP_END) + 1;
667        pNv->fpSyncs = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_CONTROL) & 0x30000033;
668        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x %i\n",
669                   pNv->fpWidth, pNv->fpHeight);
670     }
671
672     if(monitorA)
673       xf86SetDDCproperties(pScrn, monitorA);
674
675     if(!pNv->FlatPanel || (pScrn->depth != 24) || !pNv->twoHeads)
676         pNv->FPDither = FALSE;
677
678     pNv->LVDS = FALSE;
679     if(pNv->FlatPanel && pNv->twoHeads) {
680         nvWriteRAMDAC0(pNv, NV_RAMDAC_FP_TMDS_DATA, 0x00010004);
681         if(nvReadRAMDAC0(pNv, NV_RAMDAC_FP_TMDS_LVDS) & 1)
682            pNv->LVDS = TRUE;
683         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel is %s\n", 
684                    pNv->LVDS ? "LVDS" : "TMDS");
685     }
686 }
687
688 #endif