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

source code of linux/drivers/video/fbdev/nvidia/nv_setup.c