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