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