LockUnlock CRTC's when going back to X (EnterVT), patch by Bernhard Kaindl <bk@suse...
[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_OUTPUT);
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_OUTPUT, (reg52C & 0x0000FEEE));
198     usleep(1000);
199     
200     temp = nvReadRAMDAC(pNv, output, NV_RAMDAC_OUTPUT);
201     nvWriteRAMDAC(pNv, output, NV_RAMDAC_OUTPUT, 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_OUTPUT, 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                 uint32_t amt;
325 #ifdef XSERVER_LIBPCIACCESS
326                 const struct pci_slot_match match[] = { {0, 0, 0, 1, 0} };
327                 struct pci_device_iterator *iterator = pci_slot_match_iterator_create(&match);
328                 /* assume one device to exist */
329                 struct pci_device *device = pci_device_next(iterator);
330                 PCI_DEV_READ_LONG(device, 0x7c, &amt);
331 #else
332                 amt = pciReadLong(pciTag(0, 0, 1), 0x7C);
333 #endif /* XSERVER_LIBPCIACCESS */
334                 pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
335         } else if (implementation == CHIPSET_NFORCE2) {
336                 uint32_t amt; 
337 #ifdef XSERVER_LIBPCIACCESS
338                 const struct pci_slot_match match[] = { {0, 0, 0, 1, 0} };
339                 struct pci_device_iterator *iterator = pci_slot_match_iterator_create(&match);
340                 /* assume one device to exist */
341                 struct pci_device *device = pci_device_next(iterator);
342                 PCI_DEV_READ_LONG(device, 0x84, &amt);
343 #else
344                 amt = pciReadLong(pciTag(0, 0, 1), 0x84);
345 #endif /* XSERVER_LIBPCIACCESS */
346                 pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
347         } else {
348                 pNv->RamAmountKBytes = (nvReadFB(pNv, 0x020C) & 0xFFF00000) >> 10;
349         }
350
351     if(pNv->RamAmountKBytes > 256*1024)
352         pNv->RamAmountKBytes = 256*1024;
353
354     pNv->CrystalFreqKHz = (nvReadEXTDEV(pNv, 0x0000) & (1 << 6)) ? 14318 : 13500;
355     
356     if(pNv->twoHeads && (implementation != CHIPSET_NV11))
357     {
358        if(nvReadEXTDEV(pNv, 0x0000) & (1 << 22))
359            pNv->CrystalFreqKHz = 27000;
360     }
361
362     pNv->CURSOR           = NULL;  /* can't set this here */
363     pNv->MinVClockFreqKHz = 12000;
364     pNv->MaxVClockFreqKHz = pNv->twoStagePLL ? 400000 : 350000;
365 }
366
367 void
368 NVCommonSetup(ScrnInfoPtr pScrn)
369 {
370     NVPtr pNv = NVPTR(pScrn);
371     vgaHWPtr pVga = VGAHWPTR(pScrn);
372     CARD16 implementation = pNv->Chipset & 0x0ff0;
373     xf86MonPtr monitorA, monitorB;
374     Bool tvA = FALSE;
375     Bool tvB = FALSE;
376     int FlatPanel = -1;   /* really means the CRTC is slaved */
377     Bool Television = FALSE;
378     
379     /*
380      * Override VGA I/O routines.
381      */
382     pVga->writeCrtc         = NVWriteCrtc;
383     pVga->readCrtc          = NVReadCrtc;
384     pVga->writeGr           = NVWriteGr;
385     pVga->readGr            = NVReadGr;
386     pVga->writeAttr         = NVWriteAttr;
387     pVga->readAttr          = NVReadAttr;
388     pVga->writeSeq          = NVWriteSeq;
389     pVga->readSeq           = NVReadSeq;
390     pVga->writeMiscOut      = NVWriteMiscOut;
391     pVga->readMiscOut       = NVReadMiscOut;
392     pVga->enablePalette     = NVEnablePalette;
393     pVga->disablePalette    = NVDisablePalette;
394     pVga->writeDacMask      = NVWriteDacMask;
395     pVga->readDacMask       = NVReadDacMask;
396     pVga->writeDacWriteAddr = NVWriteDacWriteAddr;
397     pVga->writeDacReadAddr  = NVWriteDacReadAddr;
398     pVga->writeDacData      = NVWriteDacData;
399     pVga->readDacData       = NVReadDacData;
400     /*
401      * Note: There are different pointers to the CRTC/AR and GR/SEQ registers.
402      * Bastardize the intended uses of these to make it work.
403      */
404     pVga->MMIOBase   = (CARD8 *)pNv;
405     pVga->MMIOOffset = 0;
406
407 #ifndef XSERVER_LIBPCIACCESS
408         pNv->REGS = xf86MapPciMem(pScrn->scrnIndex, 
409                         VIDMEM_MMIO | VIDMEM_READSIDEEFFECT, 
410                         pNv->PciTag, pNv->IOAddress, 0x01000000);
411 #else
412         /* 0x01000000 is the size */
413         pci_device_map_memory_range(pNv->PciInfo, pNv->IOAddress, 0x01000000, TRUE, &(pNv->REGS));
414 #endif /* XSERVER_LIBPCIACCESS */
415
416     pNv->PRAMIN   = pNv->REGS + (NV_PRAMIN_OFFSET/4);
417     pNv->PCRTC0   = pNv->REGS + (NV_PCRTC0_OFFSET/4);
418     pNv->PRAMDAC0 = pNv->REGS + (NV_PRAMDAC0_OFFSET/4);
419     pNv->PFB      = pNv->REGS + (NV_PFB_OFFSET/4);
420     pNv->PFIFO    = pNv->REGS + (NV_PFIFO_OFFSET/4);
421     pNv->PGRAPH   = pNv->REGS + (NV_PGRAPH_OFFSET/4);
422     pNv->PEXTDEV  = pNv->REGS + (NV_PEXTDEV_OFFSET/4);
423     pNv->PTIMER   = pNv->REGS + (NV_PTIMER_OFFSET/4);
424     pNv->PVIDEO   = pNv->REGS + (NV_PVIDEO_OFFSET/4);
425     pNv->PMC      = pNv->REGS + (NV_PMC_OFFSET/4);
426
427     /* 8 bit registers */
428     pNv->PCIO0    = (CARD8*)pNv->REGS + NV_PCIO0_OFFSET;
429     pNv->PDIO0    = (CARD8*)pNv->REGS + NV_PDIO0_OFFSET;
430     pNv->PVIO     = (CARD8*)pNv->REGS + NV_PVIO_OFFSET;
431     pNv->PROM     = (CARD8*)pNv->REGS + NV_PROM_OFFSET;
432
433     pNv->PCRTC1   = pNv->PCRTC0 + 0x800;
434     pNv->PRAMDAC1 = pNv->PRAMDAC0 + 0x800;
435     pNv->PCIO1    = pNv->PCIO0 + 0x2000;
436     pNv->PDIO1    = pNv->PDIO0 + 0x2000;
437
438     pNv->twoHeads =  (pNv->Architecture >= NV_ARCH_10) &&
439                      (implementation != CHIPSET_NV10) &&
440                      (implementation != CHIPSET_NV15) &&
441                      (implementation != CHIPSET_NFORCE) &&
442                      (implementation != CHIPSET_NV20);
443
444     pNv->fpScaler = (pNv->FpScale && pNv->twoHeads && (implementation!=CHIPSET_NV11));
445
446     pNv->twoStagePLL = (implementation == CHIPSET_NV31) ||
447                        (implementation == CHIPSET_NV36) ||
448                        (pNv->Architecture >= NV_ARCH_40);
449
450     pNv->WaitVSyncPossible = (pNv->Architecture >= NV_ARCH_10) &&
451                              (implementation != CHIPSET_NV10);
452
453     pNv->BlendingPossible = ((pNv->Chipset & 0xffff) > CHIPSET_NV04);
454
455     /* look for known laptop chips */
456     /* FIXME we could add some ids here (0x0164,0x0167,0x0168,0x01D6,0x01D7,0x01D8,0x0298,0x0299,0x0398) */
457     switch(pNv->Chipset & 0xffff) {
458     case 0x0112:
459     case 0x0174:
460     case 0x0175:
461     case 0x0176:
462     case 0x0177:
463     case 0x0179:
464     case 0x017C:
465     case 0x017D:
466     case 0x0186:
467     case 0x0187:
468     case 0x018D:
469     case 0x0228:
470     case 0x0286:
471     case 0x028C:
472     case 0x0316:
473     case 0x0317:
474     case 0x031A:
475     case 0x031B:
476     case 0x031C:
477     case 0x031D:
478     case 0x031E:
479     case 0x031F:
480     case 0x0324:
481     case 0x0325:
482     case 0x0328:
483     case 0x0329:
484     case 0x032C:
485     case 0x032D:
486     case 0x0347:
487     case 0x0348:
488     case 0x0349:
489     case 0x034B:
490     case 0x034C:
491     case 0x0160:
492     case 0x0166:
493     case 0x0169:
494     case 0x016B:
495     case 0x016C:
496     case 0x016D:
497     case 0x00C8:
498     case 0x00CC:
499     case 0x0144:
500     case 0x0146:
501     case 0x0148:
502     case 0x0098:
503     case 0x0099:
504         pNv->Mobile = TRUE;
505         break;
506     default:
507         break;
508     }
509
510     pNv->Television = FALSE;
511
512     /* Parse the bios to initialize the card */
513     NVSelectHeadRegisters(pScrn, 0);
514     NVParseBios(pScrn);
515
516     if(pNv->Architecture == NV_ARCH_03)
517         nv3GetConfig(pNv);
518     else if(pNv->Architecture == NV_ARCH_04)
519         nv4GetConfig(pNv);
520     else
521         nv10GetConfig(pNv);
522
523     if (!pNv->randr12_enable) {
524       
525         NVSelectHeadRegisters(pScrn, 0);
526         
527         NVLockUnlock(pNv, 0);
528         
529         NVI2CInit(pScrn);
530         
531         
532         if(!pNv->twoHeads) {
533             pNv->CRTCnumber = 0;
534             if((monitorA = NVProbeDDC(pScrn, 0))) {
535                 FlatPanel = monitorA->features.input_type ? 1 : 0;
536                 
537                 /* NV4 doesn't support FlatPanels */
538                 if((pNv->Chipset & 0x0fff) <= CHIPSET_NV04)
539                     FlatPanel = 0;
540             } else {
541                 if(nvReadVGA(pNv, NV_VGA_CRTCX_PIXEL) & 0x80) {
542                     if(!(nvReadVGA(pNv, NV_VGA_CRTCX_LCD) & 0x01)) 
543                         Television = TRUE;
544                     FlatPanel = 1;
545                 } else {
546                     FlatPanel = 0;
547                 }
548                 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
549                            "HW is currently programmed for %s\n",
550                            FlatPanel ? (Television ? "TV" : "DFP") : "CRT");
551             } 
552             
553             if(pNv->FlatPanel == -1) {
554                 pNv->FlatPanel = FlatPanel;
555                 pNv->Television = Television;
556             } else {
557                 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
558                            "Forcing display type to %s as specified\n", 
559                            pNv->FlatPanel ? "DFP" : "CRT");
560             }
561         } else {
562             CARD8 outputAfromCRTC, outputBfromCRTC;
563             int CRTCnumber = -1;
564             CARD8 slaved_on_A, slaved_on_B;
565             Bool analog_on_A, analog_on_B;
566             CARD32 oldhead;
567             CARD8 cr44;
568             
569             if(implementation != CHIPSET_NV11) {
570                 if(nvReadRAMDAC0(pNv, NV_RAMDAC_OUTPUT) & 0x100)
571                     outputAfromCRTC = 1;
572                 else            
573                     outputAfromCRTC = 0;
574                 if(nvReadRAMDAC(pNv, 1, NV_RAMDAC_OUTPUT) & 0x100)
575                     outputBfromCRTC = 1;
576                 else
577                     outputBfromCRTC = 0;
578                 analog_on_A = NVIsConnected(pScrn, 0);
579                 analog_on_B = NVIsConnected(pScrn, 1);
580             } else {
581                 outputAfromCRTC = 0;
582                 outputBfromCRTC = 1;
583                 analog_on_A = FALSE;
584                 analog_on_B = FALSE;
585             }
586             
587             cr44 = nvReadVGA(pNv, NV_VGA_CRTCX_OWNER);
588             pNv->vtOWNER = cr44;
589             
590             nvWriteVGA(pNv, NV_VGA_CRTCX_OWNER, 3);
591             NVSelectHeadRegisters(pScrn, 1);
592             NVLockUnlock(pNv, 0);
593             
594             slaved_on_B = nvReadVGA(pNv, NV_VGA_CRTCX_PIXEL) & 0x80;
595             if(slaved_on_B) {
596                 tvB = !(nvReadVGA(pNv, NV_VGA_CRTCX_LCD) & 0x01);
597             }
598             
599             nvWriteVGA(pNv, NV_VGA_CRTCX_OWNER, 0);
600             NVSelectHeadRegisters(pScrn, 0);
601             NVLockUnlock(pNv, 0);
602             
603             slaved_on_A = nvReadVGA(pNv, NV_VGA_CRTCX_PIXEL) & 0x80; 
604             if(slaved_on_A) {
605                 tvA = !(nvReadVGA(pNv, NV_VGA_CRTCX_LCD) & 0x01);
606             }
607             
608             oldhead = nvReadCRTC0(pNv, NV_CRTC_FSEL);
609             nvWriteCRTC0(pNv, NV_CRTC_FSEL, oldhead | 0x00000010);
610             
611             monitorA = NVProbeDDC(pScrn, 0);
612             monitorB = NVProbeDDC(pScrn, 1);
613             
614             if(slaved_on_A && !tvA) {
615                 CRTCnumber = 0;
616                 FlatPanel = 1;
617                 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
618                            "CRTC 0 is currently programmed for DFP\n");
619             } else 
620                 if(slaved_on_B && !tvB) {
621                     CRTCnumber = 1;
622                     FlatPanel = 1;
623                     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
624                                "CRTC 1 is currently programmed for DFP\n");
625                 } else
626                     if(analog_on_A) {
627                         CRTCnumber = outputAfromCRTC;
628                         FlatPanel = 0;
629                         xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
630                                    "CRTC %i appears to have a CRT attached\n", CRTCnumber);
631                     } else
632                         if(analog_on_B) {
633                             CRTCnumber = outputBfromCRTC;
634                             FlatPanel = 0;
635                             xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
636                                        "CRTC %i appears to have a CRT attached\n", CRTCnumber);
637                         } else
638                             if(slaved_on_A) {
639                                 CRTCnumber = 0;
640                                 FlatPanel = 1;
641                                 Television = 1;
642                                 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
643                                            "CRTC 0 is currently programmed for TV\n");
644                             } else
645                                 if(slaved_on_B) {
646                                     CRTCnumber = 1;
647                                     FlatPanel = 1;
648                                     Television = 1;
649                                     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
650                                                "CRTC 1 is currently programmed for TV\n");
651                                 } else
652                                     if(monitorA) {
653                                         FlatPanel = monitorA->features.input_type ? 1 : 0;
654                                     } else 
655                                         if(monitorB) {
656                                             FlatPanel = monitorB->features.input_type ? 1 : 0;
657                                         }
658             
659             if(pNv->FlatPanel == -1) {
660                 if(FlatPanel != -1) {
661                     pNv->FlatPanel = FlatPanel;
662                     pNv->Television = Television;
663                 } else {
664                     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
665                                "Unable to detect display type...\n");
666                     if(pNv->Mobile) {
667                         xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
668                                    "...On a laptop, assuming DFP\n");
669                         pNv->FlatPanel = 1;
670                     } else {
671                         xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
672                                    "...Using default of CRT\n");
673                         pNv->FlatPanel = 0;
674                     }
675                 }
676             } else {
677                 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
678                            "Forcing display type to %s as specified\n", 
679                            pNv->FlatPanel ? "DFP" : "CRT");
680             }
681             
682             if(pNv->CRTCnumber == -1) {
683                 if(CRTCnumber != -1) pNv->CRTCnumber = CRTCnumber;
684                 else {
685                     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
686                                "Unable to detect which CRTCNumber...\n");
687                     if(pNv->FlatPanel) pNv->CRTCnumber = 1;
688                     else pNv->CRTCnumber = 0;
689                     xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
690                                "...Defaulting to CRTCNumber %i\n", pNv->CRTCnumber);
691                 }
692             } else {
693                 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
694                            "Forcing CRTCNumber %i as specified\n", pNv->CRTCnumber);
695             }
696             
697             if(monitorA) {
698                 if((monitorA->features.input_type && pNv->FlatPanel) ||
699                    (!monitorA->features.input_type && !pNv->FlatPanel))
700                 {
701                     if(monitorB) { 
702                         xfree(monitorB);
703                         monitorB = NULL;
704                     }
705                 } else {
706                     xfree(monitorA);
707                     monitorA = NULL;
708                 }
709             }
710             
711             if(monitorB) {
712                 if((monitorB->features.input_type && !pNv->FlatPanel) ||
713                    (!monitorB->features.input_type && pNv->FlatPanel)) 
714                 {
715                     xfree(monitorB);
716                 } else {
717                     monitorA = monitorB;
718                 }
719                 monitorB = NULL;
720             }
721             
722             if(implementation == CHIPSET_NV11)
723                 cr44 = pNv->CRTCnumber * 0x3;
724             
725             nvWriteCRTC0(pNv, NV_CRTC_FSEL,  oldhead);
726
727             nvWriteVGA(pNv, NV_VGA_CRTCX_OWNER, cr44);
728             NVSelectHeadRegisters(pScrn, pNv->CRTCnumber);
729         }
730         
731         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
732                    "Using %s on CRTC %i\n",
733                    pNv->FlatPanel ? (pNv->Television ? "TV" : "DFP") : "CRT", 
734                    pNv->CRTCnumber);
735         
736         if(pNv->FlatPanel && !pNv->Television) {
737             pNv->fpWidth = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_HDISP_END) + 1;
738             pNv->fpHeight = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_VDISP_END) + 1;
739             pNv->fpSyncs = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_CONTROL) & 0x30000033;
740             xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x %i\n",
741                        pNv->fpWidth, pNv->fpHeight);
742         }
743         
744         if(monitorA)
745             xf86SetDDCproperties(pScrn, monitorA);
746
747         if(!pNv->FlatPanel || (pScrn->depth != 24) || !pNv->twoHeads)
748             pNv->FPDither = FALSE;
749         
750         pNv->LVDS = FALSE;
751         if(pNv->FlatPanel && pNv->twoHeads) {
752             nvWriteRAMDAC0(pNv, NV_RAMDAC_FP_TMDS_CONTROL, 0x00010004);
753             if(nvReadRAMDAC0(pNv, NV_RAMDAC_FP_TMDS_DATA) & 1)
754                 pNv->LVDS = TRUE;
755             xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel is %s\n", 
756                        pNv->LVDS ? "LVDS" : "TMDS");
757         }
758     }
759 }
760