1f7018c21STomi Valkeinen /***************************************************************************\
2f7018c21STomi Valkeinen |* *|
3f7018c21STomi Valkeinen |* Copyright 2003 NVIDIA, Corporation. All rights reserved. *|
4f7018c21STomi Valkeinen |* *|
5f7018c21STomi Valkeinen |* NOTICE TO USER: The source code is copyrighted under U.S. and *|
6f7018c21STomi Valkeinen |* international laws. Users and possessors of this source code are *|
7f7018c21STomi Valkeinen |* hereby granted a nonexclusive, royalty-free copyright license to *|
8f7018c21STomi Valkeinen |* use this code in individual and commercial software. *|
9f7018c21STomi Valkeinen |* *|
10f7018c21STomi Valkeinen |* Any use of this source code must include, in the user documenta- *|
11f7018c21STomi Valkeinen |* tion and internal comments to the code, notices to the end user *|
12f7018c21STomi Valkeinen |* as follows: *|
13f7018c21STomi Valkeinen |* *|
14f7018c21STomi Valkeinen |* Copyright 2003 NVIDIA, Corporation. All rights reserved. *|
15f7018c21STomi Valkeinen |* *|
16f7018c21STomi Valkeinen |* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *|
17f7018c21STomi Valkeinen |* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *|
18f7018c21STomi Valkeinen |* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *|
19f7018c21STomi Valkeinen |* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *|
20f7018c21STomi Valkeinen |* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *|
21f7018c21STomi Valkeinen |* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *|
22f7018c21STomi Valkeinen |* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *|
23f7018c21STomi Valkeinen |* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *|
24f7018c21STomi Valkeinen |* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *|
25f7018c21STomi Valkeinen |* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *|
26f7018c21STomi Valkeinen |* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *|
27f7018c21STomi Valkeinen |* *|
28f7018c21STomi Valkeinen |* U.S. Government End Users. This source code is a "commercial *|
29f7018c21STomi Valkeinen |* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *|
30f7018c21STomi Valkeinen |* consisting of "commercial computer software" and "commercial *|
31f7018c21STomi Valkeinen |* computer software documentation," as such terms are used in *|
32f7018c21STomi Valkeinen |* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *|
33f7018c21STomi Valkeinen |* ment only as a commercial end item. Consistent with 48 C.F.R. *|
34f7018c21STomi Valkeinen |* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *|
35f7018c21STomi Valkeinen |* all U.S. Government End Users acquire the source code with only *|
36f7018c21STomi Valkeinen |* those rights set forth herein. *|
37f7018c21STomi Valkeinen |* *|
38f7018c21STomi Valkeinen \***************************************************************************/
39f7018c21STomi Valkeinen
40f7018c21STomi Valkeinen /*
41f7018c21STomi Valkeinen * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
42f7018c21STomi Valkeinen * XFree86 'nv' driver, this source code is provided under MIT-style licensing
43f7018c21STomi Valkeinen * where the source code is provided "as is" without warranty of any kind.
44f7018c21STomi Valkeinen * The only usage restriction is for the copyright notices to be retained
45f7018c21STomi Valkeinen * whenever code is used.
46f7018c21STomi Valkeinen *
47f7018c21STomi Valkeinen * Antonino Daplas <[email protected]> 2005-03-11
48f7018c21STomi Valkeinen */
49f7018c21STomi Valkeinen
50f7018c21STomi Valkeinen #include <video/vga.h>
51f7018c21STomi Valkeinen #include <linux/delay.h>
52f7018c21STomi Valkeinen #include <linux/pci.h>
53f7018c21STomi Valkeinen #include <linux/slab.h>
54f7018c21STomi Valkeinen #include "nv_type.h"
55f7018c21STomi Valkeinen #include "nv_local.h"
56f7018c21STomi Valkeinen #include "nv_proto.h"
57f7018c21STomi Valkeinen /*
58f7018c21STomi Valkeinen * Override VGA I/O routines.
59f7018c21STomi Valkeinen */
NVWriteCrtc(struct nvidia_par * par,u8 index,u8 value)60f7018c21STomi Valkeinen void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value)
61f7018c21STomi Valkeinen {
62f7018c21STomi Valkeinen VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
63f7018c21STomi Valkeinen VGA_WR08(par->PCIO, par->IOBase + 0x05, value);
64f7018c21STomi Valkeinen }
NVReadCrtc(struct nvidia_par * par,u8 index)65f7018c21STomi Valkeinen u8 NVReadCrtc(struct nvidia_par *par, u8 index)
66f7018c21STomi Valkeinen {
67f7018c21STomi Valkeinen VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
68f7018c21STomi Valkeinen return (VGA_RD08(par->PCIO, par->IOBase + 0x05));
69f7018c21STomi Valkeinen }
NVWriteGr(struct nvidia_par * par,u8 index,u8 value)70f7018c21STomi Valkeinen void NVWriteGr(struct nvidia_par *par, u8 index, u8 value)
71f7018c21STomi Valkeinen {
72f7018c21STomi Valkeinen VGA_WR08(par->PVIO, VGA_GFX_I, index);
73f7018c21STomi Valkeinen VGA_WR08(par->PVIO, VGA_GFX_D, value);
74f7018c21STomi Valkeinen }
NVReadGr(struct nvidia_par * par,u8 index)75f7018c21STomi Valkeinen u8 NVReadGr(struct nvidia_par *par, u8 index)
76f7018c21STomi Valkeinen {
77f7018c21STomi Valkeinen VGA_WR08(par->PVIO, VGA_GFX_I, index);
78f7018c21STomi Valkeinen return (VGA_RD08(par->PVIO, VGA_GFX_D));
79f7018c21STomi Valkeinen }
NVWriteSeq(struct nvidia_par * par,u8 index,u8 value)80f7018c21STomi Valkeinen void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value)
81f7018c21STomi Valkeinen {
82f7018c21STomi Valkeinen VGA_WR08(par->PVIO, VGA_SEQ_I, index);
83f7018c21STomi Valkeinen VGA_WR08(par->PVIO, VGA_SEQ_D, value);
84f7018c21STomi Valkeinen }
NVReadSeq(struct nvidia_par * par,u8 index)85f7018c21STomi Valkeinen u8 NVReadSeq(struct nvidia_par *par, u8 index)
86f7018c21STomi Valkeinen {
87f7018c21STomi Valkeinen VGA_WR08(par->PVIO, VGA_SEQ_I, index);
88f7018c21STomi Valkeinen return (VGA_RD08(par->PVIO, VGA_SEQ_D));
89f7018c21STomi Valkeinen }
NVWriteAttr(struct nvidia_par * par,u8 index,u8 value)90f7018c21STomi Valkeinen void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value)
91f7018c21STomi Valkeinen {
92f7018c21STomi Valkeinen
93*025ae825SSam Ravnborg VGA_RD08(par->PCIO, par->IOBase + 0x0a);
94f7018c21STomi Valkeinen if (par->paletteEnabled)
95f7018c21STomi Valkeinen index &= ~0x20;
96f7018c21STomi Valkeinen else
97f7018c21STomi Valkeinen index |= 0x20;
98f7018c21STomi Valkeinen VGA_WR08(par->PCIO, VGA_ATT_IW, index);
99f7018c21STomi Valkeinen VGA_WR08(par->PCIO, VGA_ATT_W, value);
100f7018c21STomi Valkeinen }
NVReadAttr(struct nvidia_par * par,u8 index)101f7018c21STomi Valkeinen u8 NVReadAttr(struct nvidia_par *par, u8 index)
102f7018c21STomi Valkeinen {
103*025ae825SSam Ravnborg VGA_RD08(par->PCIO, par->IOBase + 0x0a);
104f7018c21STomi Valkeinen if (par->paletteEnabled)
105f7018c21STomi Valkeinen index &= ~0x20;
106f7018c21STomi Valkeinen else
107f7018c21STomi Valkeinen index |= 0x20;
108f7018c21STomi Valkeinen VGA_WR08(par->PCIO, VGA_ATT_IW, index);
109f7018c21STomi Valkeinen return (VGA_RD08(par->PCIO, VGA_ATT_R));
110f7018c21STomi Valkeinen }
NVWriteMiscOut(struct nvidia_par * par,u8 value)111f7018c21STomi Valkeinen void NVWriteMiscOut(struct nvidia_par *par, u8 value)
112f7018c21STomi Valkeinen {
113f7018c21STomi Valkeinen VGA_WR08(par->PVIO, VGA_MIS_W, value);
114f7018c21STomi Valkeinen }
NVReadMiscOut(struct nvidia_par * par)115f7018c21STomi Valkeinen u8 NVReadMiscOut(struct nvidia_par *par)
116f7018c21STomi Valkeinen {
117f7018c21STomi Valkeinen return (VGA_RD08(par->PVIO, VGA_MIS_R));
118f7018c21STomi Valkeinen }
NVWriteDacMask(struct nvidia_par * par,u8 value)119f7018c21STomi Valkeinen void NVWriteDacMask(struct nvidia_par *par, u8 value)
120f7018c21STomi Valkeinen {
121f7018c21STomi Valkeinen VGA_WR08(par->PDIO, VGA_PEL_MSK, value);
122f7018c21STomi Valkeinen }
NVWriteDacReadAddr(struct nvidia_par * par,u8 value)123f7018c21STomi Valkeinen void NVWriteDacReadAddr(struct nvidia_par *par, u8 value)
124f7018c21STomi Valkeinen {
125f7018c21STomi Valkeinen VGA_WR08(par->PDIO, VGA_PEL_IR, value);
126f7018c21STomi Valkeinen }
NVWriteDacWriteAddr(struct nvidia_par * par,u8 value)127f7018c21STomi Valkeinen void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value)
128f7018c21STomi Valkeinen {
129f7018c21STomi Valkeinen VGA_WR08(par->PDIO, VGA_PEL_IW, value);
130f7018c21STomi Valkeinen }
NVWriteDacData(struct nvidia_par * par,u8 value)131f7018c21STomi Valkeinen void NVWriteDacData(struct nvidia_par *par, u8 value)
132f7018c21STomi Valkeinen {
133f7018c21STomi Valkeinen VGA_WR08(par->PDIO, VGA_PEL_D, value);
134f7018c21STomi Valkeinen }
NVReadDacData(struct nvidia_par * par)135f7018c21STomi Valkeinen u8 NVReadDacData(struct nvidia_par *par)
136f7018c21STomi Valkeinen {
137f7018c21STomi Valkeinen return (VGA_RD08(par->PDIO, VGA_PEL_D));
138f7018c21STomi Valkeinen }
139f7018c21STomi Valkeinen
NVIsConnected(struct nvidia_par * par,int output)140f7018c21STomi Valkeinen static int NVIsConnected(struct nvidia_par *par, int output)
141f7018c21STomi Valkeinen {
142f7018c21STomi Valkeinen volatile u32 __iomem *PRAMDAC = par->PRAMDAC0;
143f7018c21STomi Valkeinen u32 reg52C, reg608, dac0_reg608 = 0;
144f7018c21STomi Valkeinen int present;
145f7018c21STomi Valkeinen
146f7018c21STomi Valkeinen if (output) {
147f7018c21STomi Valkeinen dac0_reg608 = NV_RD32(PRAMDAC, 0x0608);
148f7018c21STomi Valkeinen PRAMDAC += 0x800;
149f7018c21STomi Valkeinen }
150f7018c21STomi Valkeinen
151f7018c21STomi Valkeinen reg52C = NV_RD32(PRAMDAC, 0x052C);
152f7018c21STomi Valkeinen reg608 = NV_RD32(PRAMDAC, 0x0608);
153f7018c21STomi Valkeinen
154f7018c21STomi Valkeinen NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000);
155f7018c21STomi Valkeinen
156f7018c21STomi Valkeinen NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE);
157f7018c21STomi Valkeinen msleep(1);
158f7018c21STomi Valkeinen NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1);
159f7018c21STomi Valkeinen
160f7018c21STomi Valkeinen NV_WR32(par->PRAMDAC0, 0x0610, 0x94050140);
161f7018c21STomi Valkeinen NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) |
162f7018c21STomi Valkeinen 0x00001000);
163f7018c21STomi Valkeinen
164f7018c21STomi Valkeinen msleep(1);
165f7018c21STomi Valkeinen
166f7018c21STomi Valkeinen present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0;
167f7018c21STomi Valkeinen
168f7018c21STomi Valkeinen if (present)
169f7018c21STomi Valkeinen printk("nvidiafb: CRTC%i analog found\n", output);
170f7018c21STomi Valkeinen else
171f7018c21STomi Valkeinen printk("nvidiafb: CRTC%i analog not found\n", output);
172f7018c21STomi Valkeinen
173f7018c21STomi Valkeinen if (output)
174f7018c21STomi Valkeinen NV_WR32(par->PRAMDAC0, 0x0608, dac0_reg608);
175f7018c21STomi Valkeinen
176f7018c21STomi Valkeinen NV_WR32(PRAMDAC, 0x052C, reg52C);
177f7018c21STomi Valkeinen NV_WR32(PRAMDAC, 0x0608, reg608);
178f7018c21STomi Valkeinen
179f7018c21STomi Valkeinen return present;
180f7018c21STomi Valkeinen }
181f7018c21STomi Valkeinen
NVSelectHeadRegisters(struct nvidia_par * par,int head)182f7018c21STomi Valkeinen static void NVSelectHeadRegisters(struct nvidia_par *par, int head)
183f7018c21STomi Valkeinen {
184f7018c21STomi Valkeinen if (head) {
185f7018c21STomi Valkeinen par->PCIO = par->PCIO0 + 0x2000;
186f7018c21STomi Valkeinen par->PCRTC = par->PCRTC0 + 0x800;
187f7018c21STomi Valkeinen par->PRAMDAC = par->PRAMDAC0 + 0x800;
188f7018c21STomi Valkeinen par->PDIO = par->PDIO0 + 0x2000;
189f7018c21STomi Valkeinen } else {
190f7018c21STomi Valkeinen par->PCIO = par->PCIO0;
191f7018c21STomi Valkeinen par->PCRTC = par->PCRTC0;
192f7018c21STomi Valkeinen par->PRAMDAC = par->PRAMDAC0;
193f7018c21STomi Valkeinen par->PDIO = par->PDIO0;
194f7018c21STomi Valkeinen }
195f7018c21STomi Valkeinen }
196f7018c21STomi Valkeinen
nv4GetConfig(struct nvidia_par * par)197f7018c21STomi Valkeinen static void nv4GetConfig(struct nvidia_par *par)
198f7018c21STomi Valkeinen {
199f7018c21STomi Valkeinen if (NV_RD32(par->PFB, 0x0000) & 0x00000100) {
200f7018c21STomi Valkeinen par->RamAmountKBytes =
201f7018c21STomi Valkeinen ((NV_RD32(par->PFB, 0x0000) >> 12) & 0x0F) * 1024 * 2 +
202f7018c21STomi Valkeinen 1024 * 2;
203f7018c21STomi Valkeinen } else {
204f7018c21STomi Valkeinen switch (NV_RD32(par->PFB, 0x0000) & 0x00000003) {
205f7018c21STomi Valkeinen case 0:
206f7018c21STomi Valkeinen par->RamAmountKBytes = 1024 * 32;
207f7018c21STomi Valkeinen break;
208f7018c21STomi Valkeinen case 1:
209f7018c21STomi Valkeinen par->RamAmountKBytes = 1024 * 4;
210f7018c21STomi Valkeinen break;
211f7018c21STomi Valkeinen case 2:
212f7018c21STomi Valkeinen par->RamAmountKBytes = 1024 * 8;
213f7018c21STomi Valkeinen break;
214f7018c21STomi Valkeinen case 3:
215f7018c21STomi Valkeinen default:
216f7018c21STomi Valkeinen par->RamAmountKBytes = 1024 * 16;
217f7018c21STomi Valkeinen break;
218f7018c21STomi Valkeinen }
219f7018c21STomi Valkeinen }
220f7018c21STomi Valkeinen par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & 0x00000040) ?
221f7018c21STomi Valkeinen 14318 : 13500;
222f7018c21STomi Valkeinen par->CURSOR = &par->PRAMIN[0x1E00];
223f7018c21STomi Valkeinen par->MinVClockFreqKHz = 12000;
224f7018c21STomi Valkeinen par->MaxVClockFreqKHz = 350000;
225f7018c21STomi Valkeinen }
226f7018c21STomi Valkeinen
nv10GetConfig(struct nvidia_par * par)227f7018c21STomi Valkeinen static void nv10GetConfig(struct nvidia_par *par)
228f7018c21STomi Valkeinen {
229f7018c21STomi Valkeinen struct pci_dev *dev;
230f7018c21STomi Valkeinen u32 implementation = par->Chipset & 0x0ff0;
231f7018c21STomi Valkeinen
232f7018c21STomi Valkeinen #ifdef __BIG_ENDIAN
233f7018c21STomi Valkeinen /* turn on big endian register access */
234f7018c21STomi Valkeinen if (!(NV_RD32(par->PMC, 0x0004) & 0x01000001)) {
235f7018c21STomi Valkeinen NV_WR32(par->PMC, 0x0004, 0x01000001);
236f7018c21STomi Valkeinen mb();
237f7018c21STomi Valkeinen }
238f7018c21STomi Valkeinen #endif
239f7018c21STomi Valkeinen
2405ceae169SSinan Kaya dev = pci_get_domain_bus_and_slot(pci_domain_nr(par->pci_dev->bus),
2415ceae169SSinan Kaya 0, 1);
242f7018c21STomi Valkeinen if ((par->Chipset & 0xffff) == 0x01a0) {
243f7018c21STomi Valkeinen u32 amt;
244f7018c21STomi Valkeinen
245f7018c21STomi Valkeinen pci_read_config_dword(dev, 0x7c, &amt);
246f7018c21STomi Valkeinen par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
247f7018c21STomi Valkeinen } else if ((par->Chipset & 0xffff) == 0x01f0) {
248f7018c21STomi Valkeinen u32 amt;
249f7018c21STomi Valkeinen
250f7018c21STomi Valkeinen pci_read_config_dword(dev, 0x84, &amt);
251f7018c21STomi Valkeinen par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
252f7018c21STomi Valkeinen } else {
253f7018c21STomi Valkeinen par->RamAmountKBytes =
254f7018c21STomi Valkeinen (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10;
255f7018c21STomi Valkeinen }
256f7018c21STomi Valkeinen pci_dev_put(dev);
257f7018c21STomi Valkeinen
258f7018c21STomi Valkeinen par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ?
259f7018c21STomi Valkeinen 14318 : 13500;
260f7018c21STomi Valkeinen
261f7018c21STomi Valkeinen if (par->twoHeads && (implementation != 0x0110)) {
262f7018c21STomi Valkeinen if (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 22))
263f7018c21STomi Valkeinen par->CrystalFreqKHz = 27000;
264f7018c21STomi Valkeinen }
265f7018c21STomi Valkeinen
266f7018c21STomi Valkeinen par->CURSOR = NULL; /* can't set this here */
267f7018c21STomi Valkeinen par->MinVClockFreqKHz = 12000;
268f7018c21STomi Valkeinen par->MaxVClockFreqKHz = par->twoStagePLL ? 400000 : 350000;
269f7018c21STomi Valkeinen }
270f7018c21STomi Valkeinen
NVCommonSetup(struct fb_info * info)271f7018c21STomi Valkeinen int NVCommonSetup(struct fb_info *info)
272f7018c21STomi Valkeinen {
273f7018c21STomi Valkeinen struct nvidia_par *par = info->par;
274f7018c21STomi Valkeinen struct fb_var_screeninfo *var;
275f7018c21STomi Valkeinen u16 implementation = par->Chipset & 0x0ff0;
276f7018c21STomi Valkeinen u8 *edidA = NULL, *edidB = NULL;
277f7018c21STomi Valkeinen struct fb_monspecs *monitorA, *monitorB;
278f7018c21STomi Valkeinen struct fb_monspecs *monA = NULL, *monB = NULL;
279f7018c21STomi Valkeinen int mobile = 0;
280f7018c21STomi Valkeinen int tvA = 0;
281f7018c21STomi Valkeinen int tvB = 0;
282f7018c21STomi Valkeinen int FlatPanel = -1; /* really means the CRTC is slaved */
283f7018c21STomi Valkeinen int Television = 0;
284f7018c21STomi Valkeinen int err = 0;
285f7018c21STomi Valkeinen
286f7018c21STomi Valkeinen var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
287f7018c21STomi Valkeinen monitorA = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
288f7018c21STomi Valkeinen monitorB = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
289f7018c21STomi Valkeinen
290f7018c21STomi Valkeinen if (!var || !monitorA || !monitorB) {
291f7018c21STomi Valkeinen err = -ENOMEM;
292f7018c21STomi Valkeinen goto done;
293f7018c21STomi Valkeinen }
294f7018c21STomi Valkeinen
295f7018c21STomi Valkeinen par->PRAMIN = par->REGS + (0x00710000 / 4);
296f7018c21STomi Valkeinen par->PCRTC0 = par->REGS + (0x00600000 / 4);
297f7018c21STomi Valkeinen par->PRAMDAC0 = par->REGS + (0x00680000 / 4);
298f7018c21STomi Valkeinen par->PFB = par->REGS + (0x00100000 / 4);
299f7018c21STomi Valkeinen par->PFIFO = par->REGS + (0x00002000 / 4);
300f7018c21STomi Valkeinen par->PGRAPH = par->REGS + (0x00400000 / 4);
301f7018c21STomi Valkeinen par->PEXTDEV = par->REGS + (0x00101000 / 4);
302f7018c21STomi Valkeinen par->PTIMER = par->REGS + (0x00009000 / 4);
303f7018c21STomi Valkeinen par->PMC = par->REGS + (0x00000000 / 4);
304f7018c21STomi Valkeinen par->FIFO = par->REGS + (0x00800000 / 4);
305f7018c21STomi Valkeinen
306f7018c21STomi Valkeinen /* 8 bit registers */
307f7018c21STomi Valkeinen par->PCIO0 = (u8 __iomem *) par->REGS + 0x00601000;
308f7018c21STomi Valkeinen par->PDIO0 = (u8 __iomem *) par->REGS + 0x00681000;
309f7018c21STomi Valkeinen par->PVIO = (u8 __iomem *) par->REGS + 0x000C0000;
310f7018c21STomi Valkeinen
311f7018c21STomi Valkeinen par->twoHeads = (par->Architecture >= NV_ARCH_10) &&
312f7018c21STomi Valkeinen (implementation != 0x0100) &&
313f7018c21STomi Valkeinen (implementation != 0x0150) &&
314f7018c21STomi Valkeinen (implementation != 0x01A0) && (implementation != 0x0200);
315f7018c21STomi Valkeinen
316f7018c21STomi Valkeinen par->fpScaler = (par->FpScale && par->twoHeads &&
317f7018c21STomi Valkeinen (implementation != 0x0110));
318f7018c21STomi Valkeinen
319f7018c21STomi Valkeinen par->twoStagePLL = (implementation == 0x0310) ||
320f7018c21STomi Valkeinen (implementation == 0x0340) || (par->Architecture >= NV_ARCH_40);
321f7018c21STomi Valkeinen
322f7018c21STomi Valkeinen par->WaitVSyncPossible = (par->Architecture >= NV_ARCH_10) &&
323f7018c21STomi Valkeinen (implementation != 0x0100);
324f7018c21STomi Valkeinen
325f7018c21STomi Valkeinen par->BlendingPossible = ((par->Chipset & 0xffff) != 0x0020);
326f7018c21STomi Valkeinen
327f7018c21STomi Valkeinen /* look for known laptop chips */
328f7018c21STomi Valkeinen switch (par->Chipset & 0xffff) {
329f7018c21STomi Valkeinen case 0x0112:
330f7018c21STomi Valkeinen case 0x0174:
331f7018c21STomi Valkeinen case 0x0175:
332f7018c21STomi Valkeinen case 0x0176:
333f7018c21STomi Valkeinen case 0x0177:
334f7018c21STomi Valkeinen case 0x0179:
335f7018c21STomi Valkeinen case 0x017C:
336f7018c21STomi Valkeinen case 0x017D:
337f7018c21STomi Valkeinen case 0x0186:
338f7018c21STomi Valkeinen case 0x0187:
339f7018c21STomi Valkeinen case 0x018D:
340f7018c21STomi Valkeinen case 0x01D7:
341f7018c21STomi Valkeinen case 0x0228:
342f7018c21STomi Valkeinen case 0x0286:
343f7018c21STomi Valkeinen case 0x028C:
344f7018c21STomi Valkeinen case 0x0316:
345f7018c21STomi Valkeinen case 0x0317:
346f7018c21STomi Valkeinen case 0x031A:
347f7018c21STomi Valkeinen case 0x031B:
348f7018c21STomi Valkeinen case 0x031C:
349f7018c21STomi Valkeinen case 0x031D:
350f7018c21STomi Valkeinen case 0x031E:
351f7018c21STomi Valkeinen case 0x031F:
352f7018c21STomi Valkeinen case 0x0324:
353f7018c21STomi Valkeinen case 0x0325:
354f7018c21STomi Valkeinen case 0x0328:
355f7018c21STomi Valkeinen case 0x0329:
356f7018c21STomi Valkeinen case 0x032C:
357f7018c21STomi Valkeinen case 0x032D:
358f7018c21STomi Valkeinen case 0x0347:
359f7018c21STomi Valkeinen case 0x0348:
360f7018c21STomi Valkeinen case 0x0349:
361f7018c21STomi Valkeinen case 0x034B:
362f7018c21STomi Valkeinen case 0x034C:
363f7018c21STomi Valkeinen case 0x0160:
364f7018c21STomi Valkeinen case 0x0166:
365f7018c21STomi Valkeinen case 0x0169:
366f7018c21STomi Valkeinen case 0x016B:
367f7018c21STomi Valkeinen case 0x016C:
368f7018c21STomi Valkeinen case 0x016D:
369f7018c21STomi Valkeinen case 0x00C8:
370f7018c21STomi Valkeinen case 0x00CC:
371f7018c21STomi Valkeinen case 0x0144:
372f7018c21STomi Valkeinen case 0x0146:
373f7018c21STomi Valkeinen case 0x0147:
374f7018c21STomi Valkeinen case 0x0148:
375f7018c21STomi Valkeinen case 0x0098:
376f7018c21STomi Valkeinen case 0x0099:
377f7018c21STomi Valkeinen mobile = 1;
378f7018c21STomi Valkeinen break;
379f7018c21STomi Valkeinen default:
380f7018c21STomi Valkeinen break;
381f7018c21STomi Valkeinen }
382f7018c21STomi Valkeinen
383f7018c21STomi Valkeinen if (par->Architecture == NV_ARCH_04)
384f7018c21STomi Valkeinen nv4GetConfig(par);
385f7018c21STomi Valkeinen else
386f7018c21STomi Valkeinen nv10GetConfig(par);
387f7018c21STomi Valkeinen
388f7018c21STomi Valkeinen NVSelectHeadRegisters(par, 0);
389f7018c21STomi Valkeinen
390f7018c21STomi Valkeinen NVLockUnlock(par, 0);
391f7018c21STomi Valkeinen
392f7018c21STomi Valkeinen par->IOBase = (NVReadMiscOut(par) & 0x01) ? 0x3d0 : 0x3b0;
393f7018c21STomi Valkeinen
394f7018c21STomi Valkeinen par->Television = 0;
395f7018c21STomi Valkeinen
396f7018c21STomi Valkeinen nvidia_create_i2c_busses(par);
397f7018c21STomi Valkeinen if (!par->twoHeads) {
398f7018c21STomi Valkeinen par->CRTCnumber = 0;
399f7018c21STomi Valkeinen if (nvidia_probe_i2c_connector(info, 1, &edidA))
400f7018c21STomi Valkeinen nvidia_probe_of_connector(info, 1, &edidA);
401f7018c21STomi Valkeinen if (edidA && !fb_parse_edid(edidA, var)) {
402f7018c21STomi Valkeinen printk("nvidiafb: EDID found from BUS1\n");
403f7018c21STomi Valkeinen monA = monitorA;
404f7018c21STomi Valkeinen fb_edid_to_monspecs(edidA, monA);
405f7018c21STomi Valkeinen FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
406f7018c21STomi Valkeinen
407f7018c21STomi Valkeinen /* NV4 doesn't support FlatPanels */
408f7018c21STomi Valkeinen if ((par->Chipset & 0x0fff) <= 0x0020)
409f7018c21STomi Valkeinen FlatPanel = 0;
410f7018c21STomi Valkeinen } else {
411f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D4, 0x28);
412f7018c21STomi Valkeinen if (VGA_RD08(par->PCIO, 0x03D5) & 0x80) {
413f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D4, 0x33);
414f7018c21STomi Valkeinen if (!(VGA_RD08(par->PCIO, 0x03D5) & 0x01))
415f7018c21STomi Valkeinen Television = 1;
416f7018c21STomi Valkeinen FlatPanel = 1;
417f7018c21STomi Valkeinen } else {
418f7018c21STomi Valkeinen FlatPanel = 0;
419f7018c21STomi Valkeinen }
420f7018c21STomi Valkeinen printk("nvidiafb: HW is currently programmed for %s\n",
421f7018c21STomi Valkeinen FlatPanel ? (Television ? "TV" : "DFP") :
422f7018c21STomi Valkeinen "CRT");
423f7018c21STomi Valkeinen }
424f7018c21STomi Valkeinen
425f7018c21STomi Valkeinen if (par->FlatPanel == -1) {
426f7018c21STomi Valkeinen par->FlatPanel = FlatPanel;
427f7018c21STomi Valkeinen par->Television = Television;
428f7018c21STomi Valkeinen } else {
429f7018c21STomi Valkeinen printk("nvidiafb: Forcing display type to %s as "
430f7018c21STomi Valkeinen "specified\n", par->FlatPanel ? "DFP" : "CRT");
431f7018c21STomi Valkeinen }
432f7018c21STomi Valkeinen } else {
433f7018c21STomi Valkeinen u8 outputAfromCRTC, outputBfromCRTC;
434f7018c21STomi Valkeinen int CRTCnumber = -1;
435f7018c21STomi Valkeinen u8 slaved_on_A, slaved_on_B;
436f7018c21STomi Valkeinen int analog_on_A, analog_on_B;
437f7018c21STomi Valkeinen u32 oldhead;
438f7018c21STomi Valkeinen u8 cr44;
439f7018c21STomi Valkeinen
440f7018c21STomi Valkeinen if (implementation != 0x0110) {
441f7018c21STomi Valkeinen if (NV_RD32(par->PRAMDAC0, 0x0000052C) & 0x100)
442f7018c21STomi Valkeinen outputAfromCRTC = 1;
443f7018c21STomi Valkeinen else
444f7018c21STomi Valkeinen outputAfromCRTC = 0;
445f7018c21STomi Valkeinen if (NV_RD32(par->PRAMDAC0, 0x0000252C) & 0x100)
446f7018c21STomi Valkeinen outputBfromCRTC = 1;
447f7018c21STomi Valkeinen else
448f7018c21STomi Valkeinen outputBfromCRTC = 0;
449f7018c21STomi Valkeinen analog_on_A = NVIsConnected(par, 0);
450f7018c21STomi Valkeinen analog_on_B = NVIsConnected(par, 1);
451f7018c21STomi Valkeinen } else {
452f7018c21STomi Valkeinen outputAfromCRTC = 0;
453f7018c21STomi Valkeinen outputBfromCRTC = 1;
454f7018c21STomi Valkeinen analog_on_A = 0;
455f7018c21STomi Valkeinen analog_on_B = 0;
456f7018c21STomi Valkeinen }
457f7018c21STomi Valkeinen
458f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D4, 0x44);
459f7018c21STomi Valkeinen cr44 = VGA_RD08(par->PCIO, 0x03D5);
460f7018c21STomi Valkeinen
461f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D5, 3);
462f7018c21STomi Valkeinen NVSelectHeadRegisters(par, 1);
463f7018c21STomi Valkeinen NVLockUnlock(par, 0);
464f7018c21STomi Valkeinen
465f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D4, 0x28);
466f7018c21STomi Valkeinen slaved_on_B = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
467f7018c21STomi Valkeinen if (slaved_on_B) {
468f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D4, 0x33);
469f7018c21STomi Valkeinen tvB = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
470f7018c21STomi Valkeinen }
471f7018c21STomi Valkeinen
472f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D4, 0x44);
473f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D5, 0);
474f7018c21STomi Valkeinen NVSelectHeadRegisters(par, 0);
475f7018c21STomi Valkeinen NVLockUnlock(par, 0);
476f7018c21STomi Valkeinen
477f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D4, 0x28);
478f7018c21STomi Valkeinen slaved_on_A = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
479f7018c21STomi Valkeinen if (slaved_on_A) {
480f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D4, 0x33);
481f7018c21STomi Valkeinen tvA = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
482f7018c21STomi Valkeinen }
483f7018c21STomi Valkeinen
484f7018c21STomi Valkeinen oldhead = NV_RD32(par->PCRTC0, 0x00000860);
485f7018c21STomi Valkeinen NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010);
486f7018c21STomi Valkeinen
487f7018c21STomi Valkeinen if (nvidia_probe_i2c_connector(info, 1, &edidA))
488f7018c21STomi Valkeinen nvidia_probe_of_connector(info, 1, &edidA);
489f7018c21STomi Valkeinen if (edidA && !fb_parse_edid(edidA, var)) {
490f7018c21STomi Valkeinen printk("nvidiafb: EDID found from BUS1\n");
491f7018c21STomi Valkeinen monA = monitorA;
492f7018c21STomi Valkeinen fb_edid_to_monspecs(edidA, monA);
493f7018c21STomi Valkeinen }
494f7018c21STomi Valkeinen
495f7018c21STomi Valkeinen if (nvidia_probe_i2c_connector(info, 2, &edidB))
496f7018c21STomi Valkeinen nvidia_probe_of_connector(info, 2, &edidB);
497f7018c21STomi Valkeinen if (edidB && !fb_parse_edid(edidB, var)) {
498f7018c21STomi Valkeinen printk("nvidiafb: EDID found from BUS2\n");
499f7018c21STomi Valkeinen monB = monitorB;
500f7018c21STomi Valkeinen fb_edid_to_monspecs(edidB, monB);
501f7018c21STomi Valkeinen }
502f7018c21STomi Valkeinen
503f7018c21STomi Valkeinen if (slaved_on_A && !tvA) {
504f7018c21STomi Valkeinen CRTCnumber = 0;
505f7018c21STomi Valkeinen FlatPanel = 1;
506f7018c21STomi Valkeinen printk("nvidiafb: CRTC 0 is currently programmed for "
507f7018c21STomi Valkeinen "DFP\n");
508f7018c21STomi Valkeinen } else if (slaved_on_B && !tvB) {
509f7018c21STomi Valkeinen CRTCnumber = 1;
510f7018c21STomi Valkeinen FlatPanel = 1;
511f7018c21STomi Valkeinen printk("nvidiafb: CRTC 1 is currently programmed "
512f7018c21STomi Valkeinen "for DFP\n");
513f7018c21STomi Valkeinen } else if (analog_on_A) {
514f7018c21STomi Valkeinen CRTCnumber = outputAfromCRTC;
515f7018c21STomi Valkeinen FlatPanel = 0;
516f7018c21STomi Valkeinen printk("nvidiafb: CRTC %i appears to have a "
517f7018c21STomi Valkeinen "CRT attached\n", CRTCnumber);
518f7018c21STomi Valkeinen } else if (analog_on_B) {
519f7018c21STomi Valkeinen CRTCnumber = outputBfromCRTC;
520f7018c21STomi Valkeinen FlatPanel = 0;
521f7018c21STomi Valkeinen printk("nvidiafb: CRTC %i appears to have a "
522f7018c21STomi Valkeinen "CRT attached\n", CRTCnumber);
523f7018c21STomi Valkeinen } else if (slaved_on_A) {
524f7018c21STomi Valkeinen CRTCnumber = 0;
525f7018c21STomi Valkeinen FlatPanel = 1;
526f7018c21STomi Valkeinen Television = 1;
527f7018c21STomi Valkeinen printk("nvidiafb: CRTC 0 is currently programmed "
528f7018c21STomi Valkeinen "for TV\n");
529f7018c21STomi Valkeinen } else if (slaved_on_B) {
530f7018c21STomi Valkeinen CRTCnumber = 1;
531f7018c21STomi Valkeinen FlatPanel = 1;
532f7018c21STomi Valkeinen Television = 1;
533f7018c21STomi Valkeinen printk("nvidiafb: CRTC 1 is currently programmed for "
534f7018c21STomi Valkeinen "TV\n");
535f7018c21STomi Valkeinen } else if (monA) {
536f7018c21STomi Valkeinen FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
537f7018c21STomi Valkeinen } else if (monB) {
538f7018c21STomi Valkeinen FlatPanel = (monB->input & FB_DISP_DDI) ? 1 : 0;
539f7018c21STomi Valkeinen }
540f7018c21STomi Valkeinen
541f7018c21STomi Valkeinen if (par->FlatPanel == -1) {
542f7018c21STomi Valkeinen if (FlatPanel != -1) {
543f7018c21STomi Valkeinen par->FlatPanel = FlatPanel;
544f7018c21STomi Valkeinen par->Television = Television;
545f7018c21STomi Valkeinen } else {
546f7018c21STomi Valkeinen printk("nvidiafb: Unable to detect display "
547f7018c21STomi Valkeinen "type...\n");
548f7018c21STomi Valkeinen if (mobile) {
549f7018c21STomi Valkeinen printk("...On a laptop, assuming "
550f7018c21STomi Valkeinen "DFP\n");
551f7018c21STomi Valkeinen par->FlatPanel = 1;
552f7018c21STomi Valkeinen } else {
553f7018c21STomi Valkeinen printk("...Using default of CRT\n");
554f7018c21STomi Valkeinen par->FlatPanel = 0;
555f7018c21STomi Valkeinen }
556f7018c21STomi Valkeinen }
557f7018c21STomi Valkeinen } else {
558f7018c21STomi Valkeinen printk("nvidiafb: Forcing display type to %s as "
559f7018c21STomi Valkeinen "specified\n", par->FlatPanel ? "DFP" : "CRT");
560f7018c21STomi Valkeinen }
561f7018c21STomi Valkeinen
562f7018c21STomi Valkeinen if (par->CRTCnumber == -1) {
563f7018c21STomi Valkeinen if (CRTCnumber != -1)
564f7018c21STomi Valkeinen par->CRTCnumber = CRTCnumber;
565f7018c21STomi Valkeinen else {
566f7018c21STomi Valkeinen printk("nvidiafb: Unable to detect which "
567f7018c21STomi Valkeinen "CRTCNumber...\n");
568f7018c21STomi Valkeinen if (par->FlatPanel)
569f7018c21STomi Valkeinen par->CRTCnumber = 1;
570f7018c21STomi Valkeinen else
571f7018c21STomi Valkeinen par->CRTCnumber = 0;
572f7018c21STomi Valkeinen printk("...Defaulting to CRTCNumber %i\n",
573f7018c21STomi Valkeinen par->CRTCnumber);
574f7018c21STomi Valkeinen }
575f7018c21STomi Valkeinen } else {
576f7018c21STomi Valkeinen printk("nvidiafb: Forcing CRTCNumber %i as "
577f7018c21STomi Valkeinen "specified\n", par->CRTCnumber);
578f7018c21STomi Valkeinen }
579f7018c21STomi Valkeinen
580f7018c21STomi Valkeinen if (monA) {
581f7018c21STomi Valkeinen if (((monA->input & FB_DISP_DDI) &&
582f7018c21STomi Valkeinen par->FlatPanel) ||
583f7018c21STomi Valkeinen ((!(monA->input & FB_DISP_DDI)) &&
584f7018c21STomi Valkeinen !par->FlatPanel)) {
585f7018c21STomi Valkeinen if (monB) {
586f7018c21STomi Valkeinen fb_destroy_modedb(monB->modedb);
587f7018c21STomi Valkeinen monB = NULL;
588f7018c21STomi Valkeinen }
589f7018c21STomi Valkeinen } else {
590f7018c21STomi Valkeinen fb_destroy_modedb(monA->modedb);
591f7018c21STomi Valkeinen monA = NULL;
592f7018c21STomi Valkeinen }
593f7018c21STomi Valkeinen }
594f7018c21STomi Valkeinen
595f7018c21STomi Valkeinen if (monB) {
596f7018c21STomi Valkeinen if (((monB->input & FB_DISP_DDI) &&
597f7018c21STomi Valkeinen !par->FlatPanel) ||
598f7018c21STomi Valkeinen ((!(monB->input & FB_DISP_DDI)) &&
599f7018c21STomi Valkeinen par->FlatPanel)) {
600f7018c21STomi Valkeinen fb_destroy_modedb(monB->modedb);
601f7018c21STomi Valkeinen monB = NULL;
602f7018c21STomi Valkeinen } else
603f7018c21STomi Valkeinen monA = monB;
604f7018c21STomi Valkeinen }
605f7018c21STomi Valkeinen
606f7018c21STomi Valkeinen if (implementation == 0x0110)
607f7018c21STomi Valkeinen cr44 = par->CRTCnumber * 0x3;
608f7018c21STomi Valkeinen
609f7018c21STomi Valkeinen NV_WR32(par->PCRTC0, 0x00000860, oldhead);
610f7018c21STomi Valkeinen
611f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D4, 0x44);
612f7018c21STomi Valkeinen VGA_WR08(par->PCIO, 0x03D5, cr44);
613f7018c21STomi Valkeinen NVSelectHeadRegisters(par, par->CRTCnumber);
614f7018c21STomi Valkeinen }
615f7018c21STomi Valkeinen
616f7018c21STomi Valkeinen printk("nvidiafb: Using %s on CRTC %i\n",
617f7018c21STomi Valkeinen par->FlatPanel ? (par->Television ? "TV" : "DFP") : "CRT",
618f7018c21STomi Valkeinen par->CRTCnumber);
619f7018c21STomi Valkeinen
620f7018c21STomi Valkeinen if (par->FlatPanel && !par->Television) {
621f7018c21STomi Valkeinen par->fpWidth = NV_RD32(par->PRAMDAC, 0x0820) + 1;
622f7018c21STomi Valkeinen par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1;
623f7018c21STomi Valkeinen par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033;
624f7018c21STomi Valkeinen
625f7018c21STomi Valkeinen printk("nvidiafb: Panel size is %i x %i\n", par->fpWidth, par->fpHeight);
626f7018c21STomi Valkeinen }
627f7018c21STomi Valkeinen
628f7018c21STomi Valkeinen if (monA)
629f7018c21STomi Valkeinen info->monspecs = *monA;
630f7018c21STomi Valkeinen
631f7018c21STomi Valkeinen if (!par->FlatPanel || !par->twoHeads)
632f7018c21STomi Valkeinen par->FPDither = 0;
633f7018c21STomi Valkeinen
634f7018c21STomi Valkeinen par->LVDS = 0;
635f7018c21STomi Valkeinen if (par->FlatPanel && par->twoHeads) {
636f7018c21STomi Valkeinen NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004);
637f7018c21STomi Valkeinen if (NV_RD32(par->PRAMDAC0, 0x08b4) & 1)
638f7018c21STomi Valkeinen par->LVDS = 1;
639f7018c21STomi Valkeinen printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS");
640f7018c21STomi Valkeinen }
641f7018c21STomi Valkeinen
642f7018c21STomi Valkeinen kfree(edidA);
643f7018c21STomi Valkeinen kfree(edidB);
644f7018c21STomi Valkeinen done:
645f7018c21STomi Valkeinen kfree(var);
646f7018c21STomi Valkeinen kfree(monitorA);
647f7018c21STomi Valkeinen kfree(monitorB);
648f7018c21STomi Valkeinen return err;
649f7018c21STomi Valkeinen }
650