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