nv_setup.c revision 6257f37d
1/*
2 * Copyright (c) 2003 NVIDIA, Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "nv_include.h"
29
30/*
31 * Override VGA I/O routines.
32 */
33static void NVWriteCrtc(vgaHWPtr pVga, CARD8 index, CARD8 value)
34{
35    NVPtr pNv = (NVPtr)pVga->MMIOBase;
36    VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
37    VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET,  value);
38}
39static CARD8 NVReadCrtc(vgaHWPtr pVga, CARD8 index)
40{
41    NVPtr pNv = (NVPtr)pVga->MMIOBase;
42    VGA_WR08(pNv->PCIO, pVga->IOBase + VGA_CRTC_INDEX_OFFSET, index);
43    return (VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_CRTC_DATA_OFFSET));
44}
45static void NVWriteGr(vgaHWPtr pVga, CARD8 index, CARD8 value)
46{
47    NVPtr pNv = (NVPtr)pVga->MMIOBase;
48    VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
49    VGA_WR08(pNv->PVIO, VGA_GRAPH_DATA,  value);
50}
51static CARD8 NVReadGr(vgaHWPtr pVga, CARD8 index)
52{
53    NVPtr pNv = (NVPtr)pVga->MMIOBase;
54    VGA_WR08(pNv->PVIO, VGA_GRAPH_INDEX, index);
55    return (VGA_RD08(pNv->PVIO, VGA_GRAPH_DATA));
56}
57static void NVWriteSeq(vgaHWPtr pVga, CARD8 index, CARD8 value)
58{
59    NVPtr pNv = (NVPtr)pVga->MMIOBase;
60    VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
61    VGA_WR08(pNv->PVIO, VGA_SEQ_DATA,  value);
62}
63static CARD8 NVReadSeq(vgaHWPtr pVga, CARD8 index)
64{
65    NVPtr pNv = (NVPtr)pVga->MMIOBase;
66    VGA_WR08(pNv->PVIO, VGA_SEQ_INDEX, index);
67    return (VGA_RD08(pNv->PVIO, VGA_SEQ_DATA));
68}
69static void NVWriteAttr(vgaHWPtr pVga, CARD8 index, CARD8 value)
70{
71    NVPtr pNv = (NVPtr)pVga->MMIOBase;
72    volatile CARD8 tmp;
73
74    tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
75    if (pVga->paletteEnabled)
76        index &= ~0x20;
77    else
78        index |= 0x20;
79    VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX,  index);
80    VGA_WR08(pNv->PCIO, VGA_ATTR_DATA_W, value);
81}
82static CARD8 NVReadAttr(vgaHWPtr pVga, CARD8 index)
83{
84    NVPtr pNv = (NVPtr)pVga->MMIOBase;
85    volatile CARD8 tmp;
86
87    tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
88    if (pVga->paletteEnabled)
89        index &= ~0x20;
90    else
91        index |= 0x20;
92    VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, index);
93    return (VGA_RD08(pNv->PCIO, VGA_ATTR_DATA_R));
94}
95static void NVWriteMiscOut(vgaHWPtr pVga, CARD8 value)
96{
97    NVPtr pNv = (NVPtr)pVga->MMIOBase;
98    VGA_WR08(pNv->PVIO, VGA_MISC_OUT_W, value);
99}
100static CARD8 NVReadMiscOut(vgaHWPtr pVga)
101{
102    NVPtr pNv = (NVPtr)pVga->MMIOBase;
103    return (VGA_RD08(pNv->PVIO, VGA_MISC_OUT_R));
104}
105static void NVEnablePalette(vgaHWPtr pVga)
106{
107    NVPtr pNv = (NVPtr)pVga->MMIOBase;
108    volatile CARD8 tmp;
109
110    tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
111    VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x00);
112    pVga->paletteEnabled = TRUE;
113}
114static void NVDisablePalette(vgaHWPtr pVga)
115{
116    NVPtr pNv = (NVPtr)pVga->MMIOBase;
117    volatile CARD8 tmp;
118
119    tmp = VGA_RD08(pNv->PCIO, pVga->IOBase + VGA_IN_STAT_1_OFFSET);
120    VGA_WR08(pNv->PCIO, VGA_ATTR_INDEX, 0x20);
121    pVga->paletteEnabled = FALSE;
122}
123static void NVWriteDacMask(vgaHWPtr pVga, CARD8 value)
124{
125    NVPtr pNv = (NVPtr)pVga->MMIOBase;
126    VGA_WR08(pNv->PDIO, VGA_DAC_MASK, value);
127}
128static CARD8 NVReadDacMask(vgaHWPtr pVga)
129{
130    NVPtr pNv = (NVPtr)pVga->MMIOBase;
131    return (VGA_RD08(pNv->PDIO, VGA_DAC_MASK));
132}
133static void NVWriteDacReadAddr(vgaHWPtr pVga, CARD8 value)
134{
135    NVPtr pNv = (NVPtr)pVga->MMIOBase;
136    VGA_WR08(pNv->PDIO, VGA_DAC_READ_ADDR, value);
137}
138static void NVWriteDacWriteAddr(vgaHWPtr pVga, CARD8 value)
139{
140    NVPtr pNv = (NVPtr)pVga->MMIOBase;
141    VGA_WR08(pNv->PDIO, VGA_DAC_WRITE_ADDR, value);
142}
143static void NVWriteDacData(vgaHWPtr pVga, CARD8 value)
144{
145    NVPtr pNv = (NVPtr)pVga->MMIOBase;
146    VGA_WR08(pNv->PDIO, VGA_DAC_DATA, value);
147}
148static CARD8 NVReadDacData(vgaHWPtr pVga)
149{
150    NVPtr pNv = (NVPtr)pVga->MMIOBase;
151    return (VGA_RD08(pNv->PDIO, VGA_DAC_DATA));
152}
153
154static Bool
155NVIsConnected (ScrnInfoPtr pScrn, int output)
156{
157    NVPtr pNv = NVPTR(pScrn);
158    volatile U032 *PRAMDAC = pNv->PRAMDAC0;
159    CARD32 reg52C, reg608, dac0_reg608 = 0;
160    Bool present;
161
162    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
163               "Probing for analog device on output %s...\n",
164                output ? "B" : "A");
165
166    if(output) {
167        dac0_reg608 = PRAMDAC[0x0608/4];
168        PRAMDAC += 0x800;
169    }
170
171    reg52C = PRAMDAC[0x052C/4];
172    reg608 = PRAMDAC[0x0608/4];
173
174    PRAMDAC[0x0608/4] = reg608 & ~0x00010000;
175
176    PRAMDAC[0x052C/4] = reg52C & 0x0000FEEE;
177    usleep(1000);
178    PRAMDAC[0x052C/4] |= 1;
179
180    pNv->PRAMDAC0[0x0610/4] = 0x94050140;
181    pNv->PRAMDAC0[0x0608/4] |= 0x00001000;
182
183    usleep(1000);
184
185    present = (PRAMDAC[0x0608/4] & (1 << 28)) ? TRUE : FALSE;
186
187    if(present)
188       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "  ...found one\n");
189    else
190       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "  ...can't find one\n");
191
192    if(output)
193        pNv->PRAMDAC0[0x0608/4] = dac0_reg608;
194
195    PRAMDAC[0x052C/4] = reg52C;
196    PRAMDAC[0x0608/4] = reg608;
197
198    return present;
199}
200
201static void
202NVSelectHeadRegisters(ScrnInfoPtr pScrn, int head)
203{
204    NVPtr pNv = NVPTR(pScrn);
205
206    if(head) {
207       pNv->PCIO = pNv->PCIO0 + 0x2000;
208       pNv->PCRTC = pNv->PCRTC0 + 0x800;
209       pNv->PRAMDAC = pNv->PRAMDAC0 + 0x800;
210       pNv->PDIO = pNv->PDIO0 + 0x2000;
211    } else {
212       pNv->PCIO = pNv->PCIO0;
213       pNv->PCRTC = pNv->PCRTC0;
214       pNv->PRAMDAC = pNv->PRAMDAC0;
215       pNv->PDIO = pNv->PDIO0;
216    }
217}
218
219static xf86MonPtr
220NVProbeDDC (ScrnInfoPtr pScrn, int bus)
221{
222    NVPtr pNv = NVPTR(pScrn);
223    xf86MonPtr MonInfo = NULL;
224
225    if(!pNv->I2C) return NULL;
226
227    pNv->DDCBase = bus ? 0x36 : 0x3e;
228
229    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
230               "Probing for EDID on I2C bus %s...\n", bus ? "B" : "A");
231
232#ifdef EDID_COMPLETE_RAWDATA
233    MonInfo = xf86DoEEDID(XF86_SCRN_ARG(pScrn), pNv->I2C, TRUE);
234#else
235    MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), pNv->I2C);
236#endif
237    if (MonInfo) {
238       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
239                  "DDC detected a %s:\n", MonInfo->features.input_type ?
240                  "DFP" : "CRT");
241       xf86PrintEDID( MonInfo );
242    } else {
243       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
244                  "  ... none found\n");
245    }
246
247    return MonInfo;
248}
249
250static void nv4GetConfig (NVPtr pNv)
251{
252    if (pNv->PFB[0x0000/4] & 0x00000100) {
253        pNv->RamAmountKBytes = ((pNv->PFB[0x0000/4] >> 12) & 0x0F) * 1024 * 2
254                              + 1024 * 2;
255    } else {
256        switch (pNv->PFB[0x0000/4] & 0x00000003) {
257        case 0:
258            pNv->RamAmountKBytes = 1024 * 32;
259            break;
260        case 1:
261            pNv->RamAmountKBytes = 1024 * 4;
262            break;
263        case 2:
264            pNv->RamAmountKBytes = 1024 * 8;
265            break;
266        case 3:
267        default:
268            pNv->RamAmountKBytes = 1024 * 16;
269            break;
270        }
271    }
272    pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & 0x00000040) ? 14318 : 13500;
273    pNv->CURSOR         = &(pNv->PRAMIN[0x1E00]);
274    pNv->MinVClockFreqKHz = 12000;
275    pNv->MaxVClockFreqKHz = 350000;
276}
277
278static void nv10GetConfig (NVPtr pNv)
279{
280    CARD32 implementation = pNv->Chipset & 0x0ff0;
281
282#if X_BYTE_ORDER == X_BIG_ENDIAN
283    /* turn on big endian register access */
284    if(!(pNv->PMC[0x0004/4] & 0x01000001)) {
285       pNv->PMC[0x0004/4] = 0x01000001;
286       mem_barrier();
287    }
288#endif
289
290#if XSERVER_LIBPCIACCESS
291    {
292    /* [AGP]: I don't know if this is correct */
293    struct pci_device *dev = pci_device_find_by_slot(0, 0, 0, 1);
294
295    if(implementation == 0x01a0) {
296        uint32_t amt;
297        pci_device_cfg_read_u32(dev, &amt, 0x7C);
298        pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
299    } else if(implementation == 0x01f0) {
300        uint32_t amt;
301        pci_device_cfg_read_u32(dev, &amt, 0x84);
302        pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
303    } else {
304        pNv->RamAmountKBytes = (pNv->PFB[0x020C/4] & 0xFFF00000) >> 10;
305    }
306    }
307#else
308    if(implementation == 0x01a0) {
309        int amt = pciReadLong(pciTag(0, 0, 1), 0x7C);
310        pNv->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
311    } else if(implementation == 0x01f0) {
312        int amt = pciReadLong(pciTag(0, 0, 1), 0x84);
313        pNv->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
314    } else {
315        pNv->RamAmountKBytes = (pNv->PFB[0x020C/4] & 0xFFF00000) >> 10;
316    }
317#endif
318
319    if(pNv->RamAmountKBytes > 256*1024)
320        pNv->RamAmountKBytes = 256*1024;
321
322    pNv->CrystalFreqKHz = (pNv->PEXTDEV[0x0000/4] & (1 << 6)) ? 14318 : 13500;
323
324    if(pNv->twoHeads && (implementation != 0x0110))
325    {
326       if(pNv->PEXTDEV[0x0000/4] & (1 << 22))
327           pNv->CrystalFreqKHz = 27000;
328    }
329
330    pNv->CURSOR           = NULL;  /* can't set this here */
331    pNv->MinVClockFreqKHz = 12000;
332    pNv->MaxVClockFreqKHz = pNv->twoStagePLL ? 400000 : 350000;
333}
334
335
336void
337NVCommonSetup(ScrnInfoPtr pScrn)
338{
339    NVPtr pNv = NVPTR(pScrn);
340    vgaHWPtr pVga = VGAHWPTR(pScrn);
341    CARD16 implementation = pNv->Chipset & 0x0ff0;
342    xf86MonPtr monitorA, monitorB;
343    Bool mobile = FALSE;
344    Bool tvA = FALSE;
345    Bool tvB = FALSE;
346    int FlatPanel = -1;   /* really means the CRTC is slaved */
347    Bool Television = FALSE;
348    void *tmp;
349#if XSERVER_LIBPCIACCESS
350    int err;
351#endif
352
353    /*
354     * Override VGA I/O routines.
355     */
356    pVga->writeCrtc         = NVWriteCrtc;
357    pVga->readCrtc          = NVReadCrtc;
358    pVga->writeGr           = NVWriteGr;
359    pVga->readGr            = NVReadGr;
360    pVga->writeAttr         = NVWriteAttr;
361    pVga->readAttr          = NVReadAttr;
362    pVga->writeSeq          = NVWriteSeq;
363    pVga->readSeq           = NVReadSeq;
364    pVga->writeMiscOut      = NVWriteMiscOut;
365    pVga->readMiscOut       = NVReadMiscOut;
366    pVga->enablePalette     = NVEnablePalette;
367    pVga->disablePalette    = NVDisablePalette;
368    pVga->writeDacMask      = NVWriteDacMask;
369    pVga->readDacMask       = NVReadDacMask;
370    pVga->writeDacWriteAddr = NVWriteDacWriteAddr;
371    pVga->writeDacReadAddr  = NVWriteDacReadAddr;
372    pVga->writeDacData      = NVWriteDacData;
373    pVga->readDacData       = NVReadDacData;
374    /*
375     * Note: There are different pointers to the CRTC/AR and GR/SEQ registers.
376     * Bastardize the intended uses of these to make it work.
377     */
378    pVga->MMIOBase   = (CARD8 *)pNv;
379    pVga->MMIOOffset = 0;
380
381#if XSERVER_LIBPCIACCESS
382    err = pci_device_map_range(pNv->PciInfo, pNv->IOAddress, 0x01000000,
383			       PCI_DEV_MAP_FLAG_WRITABLE, &tmp);
384    if (err != 0) {
385	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
386		   "pci_device_map_range failed: %s\n", strerror(err));
387    }
388#else
389    tmp = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
390                        pNv->PciTag, pNv->IOAddress, 0x01000000);
391#endif
392    pNv->REGS = tmp;
393
394    pNv->PRAMIN   = pNv->REGS + (0x00710000/4);
395    pNv->PCRTC0   = pNv->REGS + (0x00600000/4);
396    pNv->PRAMDAC0 = pNv->REGS + (0x00680000/4);
397    pNv->PFB      = pNv->REGS + (0x00100000/4);
398    pNv->PFIFO    = pNv->REGS + (0x00002000/4);
399    pNv->PGRAPH   = pNv->REGS + (0x00400000/4);
400    pNv->PEXTDEV  = pNv->REGS + (0x00101000/4);
401    pNv->PTIMER   = pNv->REGS + (0x00009000/4);
402    pNv->PMC      = pNv->REGS + (0x00000000/4);
403    pNv->FIFO     = pNv->REGS + (0x00800000/4);
404
405    /* 8 bit registers */
406    pNv->PCIO0    = (U008*)pNv->REGS + 0x00601000;
407    pNv->PDIO0    = (U008*)pNv->REGS + 0x00681000;
408    pNv->PVIO     = (U008*)pNv->REGS + 0x000C0000;
409
410    pNv->twoHeads =  (pNv->Architecture >= NV_ARCH_10) &&
411                     (implementation != 0x0100) &&
412                     (implementation != 0x0150) &&
413                     (implementation != 0x01A0) &&
414                     (implementation != 0x0200);
415
416    pNv->fpScaler = (pNv->FpScale && pNv->twoHeads && (implementation!=0x0110));
417
418    pNv->twoStagePLL = (implementation == 0x0310) ||
419                       (implementation == 0x0340) ||
420                       (pNv->Architecture >= NV_ARCH_40);
421
422    pNv->WaitVSyncPossible = (pNv->Architecture >= NV_ARCH_10) &&
423                             (implementation != 0x0100);
424
425    pNv->BlendingPossible = ((pNv->Chipset & 0xffff) != 0x0020);
426
427    /* look for known laptop chips */
428    switch(pNv->Chipset & 0xffff) {
429    case 0x0112:
430    case 0x0174:
431    case 0x0175:
432    case 0x0176:
433    case 0x0177:
434    case 0x0179:
435    case 0x017C:
436    case 0x017D:
437    case 0x0186:
438    case 0x0187:
439    case 0x018D:
440    case 0x0228:
441    case 0x0286:
442    case 0x028C:
443    case 0x0316:
444    case 0x0317:
445    case 0x031A:
446    case 0x031B:
447    case 0x031C:
448    case 0x031D:
449    case 0x031E:
450    case 0x031F:
451    case 0x0324:
452    case 0x0325:
453    case 0x0328:
454    case 0x0329:
455    case 0x032C:
456    case 0x032D:
457    case 0x0347:
458    case 0x0348:
459    case 0x0349:
460    case 0x034B:
461    case 0x034C:
462    case 0x0160:
463    case 0x0166:
464    case 0x0169:
465    case 0x016B:
466    case 0x016C:
467    case 0x016D:
468    case 0x00C8:
469    case 0x00CC:
470    case 0x0144:
471    case 0x0146:
472    case 0x0148:
473    case 0x0098:
474    case 0x0099:
475        mobile = TRUE;
476        break;
477    default:
478        break;
479    }
480
481    if(pNv->Architecture == NV_ARCH_04)
482        nv4GetConfig(pNv);
483    else
484        nv10GetConfig(pNv);
485
486    NVSelectHeadRegisters(pScrn, 0);
487
488    NVLockUnlock(pNv, 0);
489
490    NVI2CInit(pScrn);
491
492    pNv->Television = FALSE;
493
494    vgaHWGetIOBase(pVga);
495
496    if(!pNv->twoHeads) {
497       pNv->CRTCnumber = 0;
498       if((monitorA = NVProbeDDC(pScrn, 0))) {
499           FlatPanel = monitorA->features.input_type ? 1 : 0;
500
501           /* NV4 doesn't support FlatPanels */
502           if((pNv->Chipset & 0x0fff) <= 0x0020)
503              FlatPanel = 0;
504       } else {
505           VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
506           if(VGA_RD08(pNv->PCIO, 0x03D5) & 0x80) {
507              VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
508              if(!(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01))
509                 Television = TRUE;
510              FlatPanel = 1;
511           } else {
512              FlatPanel = 0;
513           }
514           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
515                         "HW is currently programmed for %s\n",
516                          FlatPanel ? (Television ? "TV" : "DFP") : "CRT");
517       }
518
519       if(pNv->FlatPanel == -1) {
520           pNv->FlatPanel = FlatPanel;
521           pNv->Television = Television;
522       } else {
523           xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
524                      "Forcing display type to %s as specified\n",
525                       pNv->FlatPanel ? "DFP" : "CRT");
526       }
527    } else {
528       CARD8 outputAfromCRTC, outputBfromCRTC;
529       int CRTCnumber = -1;
530       CARD8 slaved_on_A, slaved_on_B;
531       Bool analog_on_A, analog_on_B;
532       CARD32 oldhead;
533       CARD8 cr44;
534
535       if(implementation != 0x0110) {
536           if(pNv->PRAMDAC0[0x0000052C/4] & 0x100)
537               outputAfromCRTC = 1;
538           else
539               outputAfromCRTC = 0;
540           if(pNv->PRAMDAC0[0x0000252C/4] & 0x100)
541               outputBfromCRTC = 1;
542           else
543               outputBfromCRTC = 0;
544          analog_on_A = NVIsConnected(pScrn, 0);
545          analog_on_B = NVIsConnected(pScrn, 1);
546       } else {
547          outputAfromCRTC = 0;
548          outputBfromCRTC = 1;
549          analog_on_A = FALSE;
550          analog_on_B = FALSE;
551       }
552
553       VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
554       cr44 = VGA_RD08(pNv->PCIO, 0x03D5);
555
556       VGA_WR08(pNv->PCIO, 0x03D5, 3);
557       NVSelectHeadRegisters(pScrn, 1);
558       NVLockUnlock(pNv, 0);
559
560       VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
561       slaved_on_B = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80;
562       if(slaved_on_B) {
563           VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
564           tvB = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01);
565       }
566
567       VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
568       VGA_WR08(pNv->PCIO, 0x03D5, 0);
569       NVSelectHeadRegisters(pScrn, 0);
570       NVLockUnlock(pNv, 0);
571
572       VGA_WR08(pNv->PCIO, 0x03D4, 0x28);
573       slaved_on_A = VGA_RD08(pNv->PCIO, 0x03D5) & 0x80;
574       if(slaved_on_A) {
575           VGA_WR08(pNv->PCIO, 0x03D4, 0x33);
576           tvA = !(VGA_RD08(pNv->PCIO, 0x03D5) & 0x01);
577       }
578
579       oldhead = pNv->PCRTC0[0x00000860/4];
580       pNv->PCRTC0[0x00000860/4] = oldhead | 0x00000010;
581
582       monitorA = NVProbeDDC(pScrn, 0);
583       monitorB = NVProbeDDC(pScrn, 1);
584
585       if(slaved_on_A && !tvA) {
586          CRTCnumber = 0;
587          FlatPanel = 1;
588          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
589                    "CRTC 0 is currently programmed for DFP\n");
590       } else
591       if(slaved_on_B && !tvB) {
592          CRTCnumber = 1;
593          FlatPanel = 1;
594          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
595                    "CRTC 1 is currently programmed for DFP\n");
596       } else
597       if(analog_on_A) {
598          CRTCnumber = outputAfromCRTC;
599          FlatPanel = 0;
600          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
601                    "CRTC %i appears to have a CRT attached\n", CRTCnumber);
602       } else
603       if(analog_on_B) {
604           CRTCnumber = outputBfromCRTC;
605           FlatPanel = 0;
606           xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
607                    "CRTC %i appears to have a CRT attached\n", CRTCnumber);
608       } else
609       if(slaved_on_A) {
610          CRTCnumber = 0;
611          FlatPanel = 1;
612          Television = 1;
613          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
614                    "CRTC 0 is currently programmed for TV\n");
615       } else
616       if(slaved_on_B) {
617          CRTCnumber = 1;
618          FlatPanel = 1;
619          Television = 1;
620          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
621                    "CRTC 1 is currently programmed for TV\n");
622       } else
623       if(monitorA) {
624           FlatPanel = monitorA->features.input_type ? 1 : 0;
625       } else
626       if(monitorB) {
627           FlatPanel = monitorB->features.input_type ? 1 : 0;
628       }
629
630       if(pNv->FlatPanel == -1) {
631          if(FlatPanel != -1) {
632             pNv->FlatPanel = FlatPanel;
633             pNv->Television = Television;
634          } else {
635             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
636                        "Unable to detect display type...\n");
637             if(mobile) {
638                 xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
639                            "...On a laptop, assuming DFP\n");
640                 pNv->FlatPanel = 1;
641             } else {
642                 xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
643                            "...Using default of CRT\n");
644                 pNv->FlatPanel = 0;
645             }
646          }
647       } else {
648           xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
649                      "Forcing display type to %s as specified\n",
650                       pNv->FlatPanel ? "DFP" : "CRT");
651       }
652
653       if(pNv->CRTCnumber == -1) {
654          if(CRTCnumber != -1) pNv->CRTCnumber = CRTCnumber;
655          else {
656             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
657                        "Unable to detect which CRTCNumber...\n");
658             if(pNv->FlatPanel) pNv->CRTCnumber = 1;
659             else pNv->CRTCnumber = 0;
660             xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
661                        "...Defaulting to CRTCNumber %i\n", pNv->CRTCnumber);
662          }
663       } else {
664           xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
665                      "Forcing CRTCNumber %i as specified\n", pNv->CRTCnumber);
666       }
667
668       if(monitorA) {
669           if((monitorA->features.input_type && pNv->FlatPanel) ||
670              (!monitorA->features.input_type && !pNv->FlatPanel))
671           {
672               if(monitorB) {
673                  free(monitorB);
674                  monitorB = NULL;
675               }
676           } else {
677              free(monitorA);
678              monitorA = NULL;
679           }
680       }
681
682       if(monitorB) {
683           if((monitorB->features.input_type && !pNv->FlatPanel) ||
684              (!monitorB->features.input_type && pNv->FlatPanel))
685           {
686              free(monitorB);
687           } else {
688              monitorA = monitorB;
689           }
690           monitorB = NULL;
691       }
692
693       if(implementation == 0x0110)
694           cr44 = pNv->CRTCnumber * 0x3;
695
696       pNv->PCRTC0[0x00000860/4] = oldhead;
697
698       VGA_WR08(pNv->PCIO, 0x03D4, 0x44);
699       VGA_WR08(pNv->PCIO, 0x03D5, cr44);
700       NVSelectHeadRegisters(pScrn, pNv->CRTCnumber);
701    }
702
703    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
704              "Using %s on CRTC %i\n",
705              pNv->FlatPanel ? (pNv->Television ? "TV" : "DFP") : "CRT",
706              pNv->CRTCnumber);
707
708    if(pNv->FlatPanel && !pNv->Television) {
709       pNv->fpWidth = pNv->PRAMDAC[0x0820/4] + 1;
710       pNv->fpHeight = pNv->PRAMDAC[0x0800/4] + 1;
711       pNv->fpVTotal = pNv->PRAMDAC[0x804/4] + 1;
712       pNv->fpSyncs = pNv->PRAMDAC[0x0848/4] & 0x30000033;
713       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x %i\n",
714                  pNv->fpWidth, pNv->fpHeight);
715       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NOTE: This driver cannot "
716                  "reconfigure the BIOS-programmed size.\n");
717       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "These dimensions will be used as "
718                  "the panel size for mode validation.\n");
719    }
720
721    if(monitorA)
722      xf86SetDDCproperties(pScrn, monitorA);
723
724    if(!pNv->FlatPanel || (pScrn->depth != 24) || !pNv->twoHeads)
725        pNv->FPDither = FALSE;
726
727    pNv->LVDS = FALSE;
728    if(pNv->FlatPanel && pNv->twoHeads) {
729        pNv->PRAMDAC0[0x08B0/4] = 0x00010004;
730        if(pNv->PRAMDAC0[0x08B4/4] & 1)
731           pNv->LVDS = TRUE;
732        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel is %s\n",
733                   pNv->LVDS ? "LVDS" : "TMDS");
734    }
735}
736