blob: 4273c6ee8cf6baf166fa5d38121c1bf6f3ca735c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/video/nvidia/nvidia.c - nVidia fb driver
3 *
4 * Copyright 2004 Antonino Daplas <adaplas@pol.net>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 *
10 */
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/errno.h>
15#include <linux/string.h>
16#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/slab.h>
18#include <linux/delay.h>
19#include <linux/fb.h>
20#include <linux/init.h>
21#include <linux/pci.h>
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -080022#include <linux/console.h>
Michael Hanselmann5474c122006-06-25 05:47:08 -070023#include <linux/backlight.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#ifdef CONFIG_MTRR
25#include <asm/mtrr.h>
26#endif
Paul Mackerras70abac62006-10-03 01:15:14 -070027#ifdef CONFIG_BOOTX_TEXT
28#include <asm/btext.h>
29#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#include "nv_local.h"
32#include "nv_type.h"
33#include "nv_proto.h"
34#include "nv_dma.h"
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#ifdef CONFIG_FB_NVIDIA_DEBUG
37#define NVTRACE printk
38#else
39#define NVTRACE if (0) printk
40#endif
41
Harvey Harrison5ae12172008-04-28 02:15:47 -070042#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__)
43#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45#ifdef CONFIG_FB_NVIDIA_DEBUG
46#define assert(expr) \
47 if (!(expr)) { \
48 printk( "Assertion failed! %s,%s,%s,line=%d\n",\
Harvey Harrison5ae12172008-04-28 02:15:47 -070049 #expr,__FILE__,__func__,__LINE__); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 BUG(); \
51 }
52#else
53#define assert(expr)
54#endif
55
56#define PFX "nvidiafb: "
57
58/* HW cursor parameters */
59#define MAX_CURS 32
60
61static struct pci_device_id nvidiafb_pci_tbl[] = {
Antonino A. Daplas8eec4982006-06-26 00:26:30 -070062 {PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
63 PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0},
64 { 0, }
Linus Torvalds1da177e2005-04-16 15:20:36 -070065};
Linus Torvalds1da177e2005-04-16 15:20:36 -070066MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl);
67
68/* command line data, set in nvidiafb_setup() */
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080069static int flatpanel = -1; /* Autodetect later */
70static int fpdither = -1;
71static int forceCRTC = -1;
72static int hwcur = 0;
73static int noaccel = 0;
74static int noscale = 0;
75static int paneltweak = 0;
76static int vram = 0;
77static int bpp = 8;
78static int reverse_i2c;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079#ifdef CONFIG_MTRR
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080080static bool nomtrr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#endif
Richard Purdie202d4e62007-03-03 17:43:52 +000082#ifdef CONFIG_PMAC_BACKLIGHT
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080083static int backlight = 1;
Richard Purdie202d4e62007-03-03 17:43:52 +000084#else
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080085static int backlight = 0;
Richard Purdie202d4e62007-03-03 17:43:52 +000086#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080088static char *mode_option = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080090static struct fb_fix_screeninfo nvidiafb_fix = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 .type = FB_TYPE_PACKED_PIXELS,
92 .xpanstep = 8,
93 .ypanstep = 1,
94};
95
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080096static struct fb_var_screeninfo nvidiafb_default_var = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 .xres = 640,
98 .yres = 480,
99 .xres_virtual = 640,
100 .yres_virtual = 480,
101 .bits_per_pixel = 8,
102 .red = {0, 8, 0},
103 .green = {0, 8, 0},
104 .blue = {0, 8, 0},
105 .transp = {0, 0, 0},
106 .activate = FB_ACTIVATE_NOW,
107 .height = -1,
108 .width = -1,
109 .pixclock = 39721,
110 .left_margin = 40,
111 .right_margin = 24,
112 .upper_margin = 32,
113 .lower_margin = 11,
114 .hsync_len = 96,
115 .vsync_len = 2,
116 .vmode = FB_VMODE_NONINTERLACED
117};
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
120 u16 bg, u16 fg, u32 w, u32 h)
121{
James Simmonsf1ab5da2005-06-21 17:17:07 -0700122 u32 *data = (u32 *) data8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 int i, j, k = 0;
124 u32 b, tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126 w = (w + 1) & ~1;
127
128 for (i = 0; i < h; i++) {
129 b = *data++;
130 reverse_order(&b);
131
132 for (j = 0; j < w / 2; j++) {
133 tmp = 0;
134#if defined (__BIG_ENDIAN)
135 tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
136 b <<= 1;
137 tmp |= (b & (1 << 31)) ? fg : bg;
138 b <<= 1;
139#else
140 tmp = (b & 1) ? fg : bg;
141 b >>= 1;
142 tmp |= (b & 1) ? fg << 16 : bg << 16;
143 b >>= 1;
144#endif
145 NV_WR32(&par->CURSOR[k++], 0, tmp);
146 }
147 k += (MAX_CURS - w) / 2;
148 }
149}
150
151static void nvidia_write_clut(struct nvidia_par *par,
152 u8 regnum, u8 red, u8 green, u8 blue)
153{
154 NVWriteDacMask(par, 0xff);
155 NVWriteDacWriteAddr(par, regnum);
156 NVWriteDacData(par, red);
157 NVWriteDacData(par, green);
158 NVWriteDacData(par, blue);
159}
160
161static void nvidia_read_clut(struct nvidia_par *par,
162 u8 regnum, u8 * red, u8 * green, u8 * blue)
163{
164 NVWriteDacMask(par, 0xff);
165 NVWriteDacReadAddr(par, regnum);
166 *red = NVReadDacData(par);
167 *green = NVReadDacData(par);
168 *blue = NVReadDacData(par);
169}
170
171static int nvidia_panel_tweak(struct nvidia_par *par,
172 struct _riva_hw_state *state)
173{
174 int tweak = 0;
175
176 if (par->paneltweak) {
177 tweak = par->paneltweak;
178 } else {
179 /* begin flat panel hacks */
180 /* This is unfortunate, but some chips need this register
181 tweaked or else you get artifacts where adjacent pixels are
182 swapped. There are no hard rules for what to set here so all
183 we can do is experiment and apply hacks. */
184
185 if(((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) {
186 /* At least one NV34 laptop needs this workaround. */
187 tweak = -1;
188 }
189
190 if((par->Chipset & 0xfff0) == 0x0310) {
191 tweak = 1;
192 }
193 /* end flat panel hacks */
194 }
195
196 return tweak;
197}
198
Antonino A. Daplasb9b26962007-05-08 00:38:23 -0700199static void nvidia_screen_off(struct nvidia_par *par, int on)
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -0800200{
201 unsigned char tmp;
202
203 if (on) {
204 /*
205 * Turn off screen and disable sequencer.
206 */
207 tmp = NVReadSeq(par, 0x01);
208
209 NVWriteSeq(par, 0x00, 0x01); /* Synchronous Reset */
210 NVWriteSeq(par, 0x01, tmp | 0x20); /* disable the display */
211 } else {
212 /*
213 * Reenable sequencer, then turn on screen.
214 */
215
216 tmp = NVReadSeq(par, 0x01);
217
218 NVWriteSeq(par, 0x01, tmp & ~0x20); /* reenable display */
219 NVWriteSeq(par, 0x00, 0x03); /* End Reset */
220 }
221}
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223static void nvidia_save_vga(struct nvidia_par *par,
224 struct _riva_hw_state *state)
225{
226 int i;
227
228 NVTRACE_ENTER();
229 NVLockUnlock(par, 0);
230
231 NVUnloadStateExt(par, state);
232
233 state->misc_output = NVReadMiscOut(par);
234
235 for (i = 0; i < NUM_CRT_REGS; i++)
236 state->crtc[i] = NVReadCrtc(par, i);
237
238 for (i = 0; i < NUM_ATC_REGS; i++)
239 state->attr[i] = NVReadAttr(par, i);
240
241 for (i = 0; i < NUM_GRC_REGS; i++)
242 state->gra[i] = NVReadGr(par, i);
243
244 for (i = 0; i < NUM_SEQ_REGS; i++)
245 state->seq[i] = NVReadSeq(par, i);
246 NVTRACE_LEAVE();
247}
248
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800249#undef DUMP_REG
250
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -0800251static void nvidia_write_regs(struct nvidia_par *par,
252 struct _riva_hw_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 int i;
255
256 NVTRACE_ENTER();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 NVLoadStateExt(par, state);
259
260 NVWriteMiscOut(par, state->misc_output);
261
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800262 for (i = 1; i < NUM_SEQ_REGS; i++) {
263#ifdef DUMP_REG
264 printk(" SEQ[%02x] = %08x\n", i, state->seq[i]);
265#endif
266 NVWriteSeq(par, i, state->seq[i]);
267 }
268
269 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17] */
270 NVWriteCrtc(par, 0x11, state->crtc[0x11] & ~0x80);
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 for (i = 0; i < NUM_CRT_REGS; i++) {
273 switch (i) {
274 case 0x19:
275 case 0x20 ... 0x40:
276 break;
277 default:
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800278#ifdef DUMP_REG
279 printk("CRTC[%02x] = %08x\n", i, state->crtc[i]);
280#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 NVWriteCrtc(par, i, state->crtc[i]);
282 }
283 }
284
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800285 for (i = 0; i < NUM_GRC_REGS; i++) {
286#ifdef DUMP_REG
287 printk(" GRA[%02x] = %08x\n", i, state->gra[i]);
288#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 NVWriteGr(par, i, state->gra[i]);
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800292 for (i = 0; i < NUM_ATC_REGS; i++) {
293#ifdef DUMP_REG
294 printk("ATTR[%02x] = %08x\n", i, state->attr[i]);
295#endif
296 NVWriteAttr(par, i, state->attr[i]);
297 }
298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 NVTRACE_LEAVE();
300}
301
302static int nvidia_calc_regs(struct fb_info *info)
303{
304 struct nvidia_par *par = info->par;
305 struct _riva_hw_state *state = &par->ModeReg;
Antonino A. Daplasb8c90942005-09-09 13:04:37 -0700306 int i, depth = fb_get_color_depth(&info->var, &info->fix);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 int h_display = info->var.xres / 8 - 1;
308 int h_start = (info->var.xres + info->var.right_margin) / 8 - 1;
309 int h_end = (info->var.xres + info->var.right_margin +
310 info->var.hsync_len) / 8 - 1;
311 int h_total = (info->var.xres + info->var.right_margin +
312 info->var.hsync_len + info->var.left_margin) / 8 - 5;
313 int h_blank_s = h_display;
314 int h_blank_e = h_total + 4;
315 int v_display = info->var.yres - 1;
316 int v_start = info->var.yres + info->var.lower_margin - 1;
317 int v_end = (info->var.yres + info->var.lower_margin +
318 info->var.vsync_len) - 1;
319 int v_total = (info->var.yres + info->var.lower_margin +
320 info->var.vsync_len + info->var.upper_margin) - 2;
321 int v_blank_s = v_display;
322 int v_blank_e = v_total + 1;
323
324 /*
325 * Set all CRTC values.
326 */
327
328 if (info->var.vmode & FB_VMODE_INTERLACED)
329 v_total |= 1;
330
331 if (par->FlatPanel == 1) {
332 v_start = v_total - 3;
333 v_end = v_total - 2;
334 v_blank_s = v_start;
335 h_start = h_total - 5;
336 h_end = h_total - 2;
337 h_blank_e = h_total + 4;
338 }
339
340 state->crtc[0x0] = Set8Bits(h_total);
341 state->crtc[0x1] = Set8Bits(h_display);
342 state->crtc[0x2] = Set8Bits(h_blank_s);
343 state->crtc[0x3] = SetBitField(h_blank_e, 4: 0, 4:0)
344 | SetBit(7);
345 state->crtc[0x4] = Set8Bits(h_start);
346 state->crtc[0x5] = SetBitField(h_blank_e, 5: 5, 7:7)
347 | SetBitField(h_end, 4: 0, 4:0);
348 state->crtc[0x6] = SetBitField(v_total, 7: 0, 7:0);
349 state->crtc[0x7] = SetBitField(v_total, 8: 8, 0:0)
350 | SetBitField(v_display, 8: 8, 1:1)
351 | SetBitField(v_start, 8: 8, 2:2)
352 | SetBitField(v_blank_s, 8: 8, 3:3)
353 | SetBit(4)
354 | SetBitField(v_total, 9: 9, 5:5)
355 | SetBitField(v_display, 9: 9, 6:6)
356 | SetBitField(v_start, 9: 9, 7:7);
357 state->crtc[0x9] = SetBitField(v_blank_s, 9: 9, 5:5)
358 | SetBit(6)
359 | ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0x00);
360 state->crtc[0x10] = Set8Bits(v_start);
361 state->crtc[0x11] = SetBitField(v_end, 3: 0, 3:0) | SetBit(5);
362 state->crtc[0x12] = Set8Bits(v_display);
363 state->crtc[0x13] = ((info->var.xres_virtual / 8) *
364 (info->var.bits_per_pixel / 8));
365 state->crtc[0x15] = Set8Bits(v_blank_s);
366 state->crtc[0x16] = Set8Bits(v_blank_e);
367
368 state->attr[0x10] = 0x01;
369
370 if (par->Television)
371 state->attr[0x11] = 0x00;
372
373 state->screen = SetBitField(h_blank_e, 6: 6, 4:4)
374 | SetBitField(v_blank_s, 10: 10, 3:3)
375 | SetBitField(v_start, 10: 10, 2:2)
376 | SetBitField(v_display, 10: 10, 1:1)
377 | SetBitField(v_total, 10: 10, 0:0);
378
379 state->horiz = SetBitField(h_total, 8: 8, 0:0)
380 | SetBitField(h_display, 8: 8, 1:1)
381 | SetBitField(h_blank_s, 8: 8, 2:2)
382 | SetBitField(h_start, 8: 8, 3:3);
383
384 state->extra = SetBitField(v_total, 11: 11, 0:0)
385 | SetBitField(v_display, 11: 11, 2:2)
386 | SetBitField(v_start, 11: 11, 4:4)
387 | SetBitField(v_blank_s, 11: 11, 6:6);
388
389 if (info->var.vmode & FB_VMODE_INTERLACED) {
390 h_total = (h_total >> 1) & ~1;
391 state->interlace = Set8Bits(h_total);
392 state->horiz |= SetBitField(h_total, 8: 8, 4:4);
393 } else {
394 state->interlace = 0xff; /* interlace off */
395 }
396
397 /*
398 * Calculate the extended registers.
399 */
400
401 if (depth < 24)
402 i = depth;
403 else
404 i = 32;
405
406 if (par->Architecture >= NV_ARCH_10)
407 par->CURSOR = (volatile u32 __iomem *)(info->screen_base +
408 par->CursorStart);
409
410 if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
411 state->misc_output &= ~0x40;
412 else
413 state->misc_output |= 0x40;
414 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
415 state->misc_output &= ~0x80;
416 else
417 state->misc_output |= 0x80;
418
419 NVCalcStateExt(par, state, i, info->var.xres_virtual,
420 info->var.xres, info->var.yres_virtual,
421 1000000000 / info->var.pixclock, info->var.vmode);
422
423 state->scale = NV_RD32(par->PRAMDAC, 0x00000848) & 0xfff000ff;
424 if (par->FlatPanel == 1) {
425 state->pixel |= (1 << 7);
426
427 if (!par->fpScaler || (par->fpWidth <= info->var.xres)
428 || (par->fpHeight <= info->var.yres)) {
429 state->scale |= (1 << 8);
430 }
431
432 if (!par->crtcSync_read) {
433 state->crtcSync = NV_RD32(par->PRAMDAC, 0x0828);
434 par->crtcSync_read = 1;
435 }
436
437 par->PanelTweak = nvidia_panel_tweak(par, state);
438 }
439
440 state->vpll = state->pll;
441 state->vpll2 = state->pll;
442 state->vpllB = state->pllB;
443 state->vpll2B = state->pllB;
444
445 VGA_WR08(par->PCIO, 0x03D4, 0x1C);
446 state->fifo = VGA_RD08(par->PCIO, 0x03D5) & ~(1<<5);
447
448 if (par->CRTCnumber) {
449 state->head = NV_RD32(par->PCRTC0, 0x00000860) & ~0x00001000;
450 state->head2 = NV_RD32(par->PCRTC0, 0x00002860) | 0x00001000;
451 state->crtcOwner = 3;
452 state->pllsel |= 0x20000800;
453 state->vpll = NV_RD32(par->PRAMDAC0, 0x00000508);
454 if (par->twoStagePLL)
455 state->vpllB = NV_RD32(par->PRAMDAC0, 0x00000578);
456 } else if (par->twoHeads) {
457 state->head = NV_RD32(par->PCRTC0, 0x00000860) | 0x00001000;
458 state->head2 = NV_RD32(par->PCRTC0, 0x00002860) & ~0x00001000;
459 state->crtcOwner = 0;
460 state->vpll2 = NV_RD32(par->PRAMDAC0, 0x0520);
461 if (par->twoStagePLL)
462 state->vpll2B = NV_RD32(par->PRAMDAC0, 0x057C);
463 }
464
465 state->cursorConfig = 0x00000100;
466
467 if (info->var.vmode & FB_VMODE_DOUBLE)
468 state->cursorConfig |= (1 << 4);
469
470 if (par->alphaCursor) {
471 if ((par->Chipset & 0x0ff0) != 0x0110)
472 state->cursorConfig |= 0x04011000;
473 else
474 state->cursorConfig |= 0x14011000;
475 state->general |= (1 << 29);
476 } else
477 state->cursorConfig |= 0x02000000;
478
479 if (par->twoHeads) {
480 if ((par->Chipset & 0x0ff0) == 0x0110) {
481 state->dither = NV_RD32(par->PRAMDAC, 0x0528) &
482 ~0x00010000;
483 if (par->FPDither)
484 state->dither |= 0x00010000;
485 } else {
486 state->dither = NV_RD32(par->PRAMDAC, 0x083C) & ~1;
487 if (par->FPDither)
488 state->dither |= 1;
489 }
490 }
491
492 state->timingH = 0;
493 state->timingV = 0;
494 state->displayV = info->var.xres;
495
496 return 0;
497}
498
499static void nvidia_init_vga(struct fb_info *info)
500{
501 struct nvidia_par *par = info->par;
502 struct _riva_hw_state *state = &par->ModeReg;
503 int i;
504
505 for (i = 0; i < 0x10; i++)
506 state->attr[i] = i;
507 state->attr[0x10] = 0x41;
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800508 state->attr[0x11] = 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 state->attr[0x12] = 0x0f;
510 state->attr[0x13] = 0x00;
511 state->attr[0x14] = 0x00;
512
513 memset(state->crtc, 0x00, NUM_CRT_REGS);
514 state->crtc[0x0a] = 0x20;
515 state->crtc[0x17] = 0xe3;
516 state->crtc[0x18] = 0xff;
517 state->crtc[0x28] = 0x40;
518
519 memset(state->gra, 0x00, NUM_GRC_REGS);
520 state->gra[0x05] = 0x40;
521 state->gra[0x06] = 0x05;
522 state->gra[0x07] = 0x0f;
523 state->gra[0x08] = 0xff;
524
525 state->seq[0x00] = 0x03;
526 state->seq[0x01] = 0x01;
527 state->seq[0x02] = 0x0f;
528 state->seq[0x03] = 0x00;
529 state->seq[0x04] = 0x0e;
530
531 state->misc_output = 0xeb;
532}
533
534static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
535{
536 struct nvidia_par *par = info->par;
537 u8 data[MAX_CURS * MAX_CURS / 8];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 int i, set = cursor->set;
James Simmonsf1ab5da2005-06-21 17:17:07 -0700539 u16 fg, bg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Antonino A. Daplas7a482422005-09-21 07:30:21 +0800541 if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
James Simmonsf1ab5da2005-06-21 17:17:07 -0700542 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 NVShowHideCursor(par, 0);
545
546 if (par->cursor_reset) {
547 set = FB_CUR_SETALL;
548 par->cursor_reset = 0;
549 }
550
551 if (set & FB_CUR_SETSIZE)
552 memset_io(par->CURSOR, 0, MAX_CURS * MAX_CURS * 2);
553
554 if (set & FB_CUR_SETPOS) {
555 u32 xx, yy, temp;
556
557 yy = cursor->image.dy - info->var.yoffset;
558 xx = cursor->image.dx - info->var.xoffset;
559 temp = xx & 0xFFFF;
560 temp |= yy << 16;
561
562 NV_WR32(par->PRAMDAC, 0x0000300, temp);
563 }
564
565 if (set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
566 u32 bg_idx = cursor->image.bg_color;
567 u32 fg_idx = cursor->image.fg_color;
568 u32 s_pitch = (cursor->image.width + 7) >> 3;
569 u32 d_pitch = MAX_CURS / 8;
570 u8 *dat = (u8 *) cursor->image.data;
571 u8 *msk = (u8 *) cursor->mask;
572 u8 *src;
573
574 src = kmalloc(s_pitch * cursor->image.height, GFP_ATOMIC);
575
576 if (src) {
577 switch (cursor->rop) {
578 case ROP_XOR:
James Simmonsf1ab5da2005-06-21 17:17:07 -0700579 for (i = 0; i < s_pitch * cursor->image.height; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 src[i] = dat[i] ^ msk[i];
581 break;
582 case ROP_COPY:
583 default:
James Simmonsf1ab5da2005-06-21 17:17:07 -0700584 for (i = 0; i < s_pitch * cursor->image.height; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 src[i] = dat[i] & msk[i];
586 break;
587 }
588
James Simmonsf1ab5da2005-06-21 17:17:07 -0700589 fb_pad_aligned_buffer(data, d_pitch, src, s_pitch,
590 cursor->image.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
592 bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
593 ((info->cmap.green[bg_idx] & 0xf8) << 2) |
594 ((info->cmap.blue[bg_idx] & 0xf8) >> 3) | 1 << 15;
595
596 fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
597 ((info->cmap.green[fg_idx] & 0xf8) << 2) |
598 ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | 1 << 15;
599
600 NVLockUnlock(par, 0);
601
602 nvidiafb_load_cursor_image(par, data, bg, fg,
603 cursor->image.width,
604 cursor->image.height);
605 kfree(src);
606 }
607 }
608
609 if (cursor->enable)
610 NVShowHideCursor(par, 1);
611
612 return 0;
613}
614
615static int nvidiafb_set_par(struct fb_info *info)
616{
617 struct nvidia_par *par = info->par;
618
619 NVTRACE_ENTER();
620
621 NVLockUnlock(par, 1);
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -0800622 if (!par->FlatPanel || !par->twoHeads)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 par->FPDither = 0;
624
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -0800625 if (par->FPDither < 0) {
626 if ((par->Chipset & 0x0ff0) == 0x0110)
627 par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x0528)
628 & 0x00010000);
629 else
630 par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x083C) & 1);
631 printk(KERN_INFO PFX "Flat panel dithering %s\n",
632 par->FPDither ? "enabled" : "disabled");
633 }
634
Antonino A. Daplasb8c90942005-09-09 13:04:37 -0700635 info->fix.visual = (info->var.bits_per_pixel == 8) ?
636 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 nvidia_init_vga(info);
639 nvidia_calc_regs(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 NVLockUnlock(par, 0);
642 if (par->twoHeads) {
643 VGA_WR08(par->PCIO, 0x03D4, 0x44);
644 VGA_WR08(par->PCIO, 0x03D5, par->ModeReg.crtcOwner);
645 NVLockUnlock(par, 0);
646 }
647
Antonino A. Daplasb9b26962007-05-08 00:38:23 -0700648 nvidia_screen_off(par, 1);
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800649
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -0800650 nvidia_write_regs(par, &par->ModeReg);
651 NVSetStartAddress(par, 0);
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800652
653#if defined (__BIG_ENDIAN)
654 /* turn on LFB swapping */
655 {
656 unsigned char tmp;
657
658 VGA_WR08(par->PCIO, 0x3d4, 0x46);
659 tmp = VGA_RD08(par->PCIO, 0x3d5);
660 tmp |= (1 << 7);
661 VGA_WR08(par->PCIO, 0x3d5, tmp);
662 }
663#endif
664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 info->fix.line_length = (info->var.xres_virtual *
666 info->var.bits_per_pixel) >> 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 if (info->var.accel_flags) {
668 info->fbops->fb_imageblit = nvidiafb_imageblit;
669 info->fbops->fb_fillrect = nvidiafb_fillrect;
670 info->fbops->fb_copyarea = nvidiafb_copyarea;
671 info->fbops->fb_sync = nvidiafb_sync;
672 info->pixmap.scan_align = 4;
673 info->flags &= ~FBINFO_HWACCEL_DISABLED;
Antonino A. Daplas01b15bd2007-07-17 04:05:25 -0700674 info->flags |= FBINFO_READS_FAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 NVResetGraphics(info);
676 } else {
677 info->fbops->fb_imageblit = cfb_imageblit;
678 info->fbops->fb_fillrect = cfb_fillrect;
679 info->fbops->fb_copyarea = cfb_copyarea;
680 info->fbops->fb_sync = NULL;
681 info->pixmap.scan_align = 1;
682 info->flags |= FBINFO_HWACCEL_DISABLED;
Antonino A. Daplas01b15bd2007-07-17 04:05:25 -0700683 info->flags &= ~FBINFO_READS_FAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
685
686 par->cursor_reset = 1;
687
Antonino A. Daplasb9b26962007-05-08 00:38:23 -0700688 nvidia_screen_off(par, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Paul Mackerras70abac62006-10-03 01:15:14 -0700690#ifdef CONFIG_BOOTX_TEXT
691 /* Update debug text engine */
692 btext_update_display(info->fix.smem_start,
693 info->var.xres, info->var.yres,
694 info->var.bits_per_pixel, info->fix.line_length);
695#endif
696
Antonino A. Daplasb9b26962007-05-08 00:38:23 -0700697 NVLockUnlock(par, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 NVTRACE_LEAVE();
699 return 0;
700}
701
702static int nvidiafb_setcolreg(unsigned regno, unsigned red, unsigned green,
703 unsigned blue, unsigned transp,
704 struct fb_info *info)
705{
706 struct nvidia_par *par = info->par;
707 int i;
708
709 NVTRACE_ENTER();
710 if (regno >= (1 << info->var.green.length))
711 return -EINVAL;
712
713 if (info->var.grayscale) {
714 /* gray = 0.30*R + 0.59*G + 0.11*B */
715 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
716 }
717
718 if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
719 ((u32 *) info->pseudo_palette)[regno] =
720 (regno << info->var.red.offset) |
721 (regno << info->var.green.offset) |
722 (regno << info->var.blue.offset);
723 }
724
725 switch (info->var.bits_per_pixel) {
726 case 8:
727 /* "transparent" stuff is completely ignored. */
728 nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8);
729 break;
730 case 16:
731 if (info->var.green.length == 5) {
732 for (i = 0; i < 8; i++) {
733 nvidia_write_clut(par, regno * 8 + i, red >> 8,
734 green >> 8, blue >> 8);
735 }
736 } else {
737 u8 r, g, b;
738
739 if (regno < 32) {
740 for (i = 0; i < 8; i++) {
741 nvidia_write_clut(par, regno * 8 + i,
742 red >> 8, green >> 8,
743 blue >> 8);
744 }
745 }
746
747 nvidia_read_clut(par, regno * 4, &r, &g, &b);
748
749 for (i = 0; i < 4; i++)
750 nvidia_write_clut(par, regno * 4 + i, r,
751 green >> 8, b);
752 }
753 break;
754 case 32:
755 nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8);
756 break;
757 default:
758 /* do nothing */
759 break;
760 }
761
762 NVTRACE_LEAVE();
763 return 0;
764}
765
766static int nvidiafb_check_var(struct fb_var_screeninfo *var,
767 struct fb_info *info)
768{
769 struct nvidia_par *par = info->par;
770 int memlen, vramlen, mode_valid = 0;
771 int pitch, err = 0;
772
773 NVTRACE_ENTER();
774
775 var->transp.offset = 0;
776 var->transp.length = 0;
777
778 var->xres &= ~7;
779
780 if (var->bits_per_pixel <= 8)
781 var->bits_per_pixel = 8;
782 else if (var->bits_per_pixel <= 16)
783 var->bits_per_pixel = 16;
784 else
785 var->bits_per_pixel = 32;
786
787 switch (var->bits_per_pixel) {
788 case 8:
789 var->red.offset = 0;
790 var->red.length = 8;
791 var->green.offset = 0;
792 var->green.length = 8;
793 var->blue.offset = 0;
794 var->blue.length = 8;
795 var->transp.offset = 0;
796 var->transp.length = 0;
797 break;
798 case 16:
799 var->green.length = (var->green.length < 6) ? 5 : 6;
800 var->red.length = 5;
801 var->blue.length = 5;
802 var->transp.length = 6 - var->green.length;
803 var->blue.offset = 0;
804 var->green.offset = 5;
805 var->red.offset = 5 + var->green.length;
806 var->transp.offset = (5 + var->red.offset) & 15;
807 break;
808 case 32: /* RGBA 8888 */
809 var->red.offset = 16;
810 var->red.length = 8;
811 var->green.offset = 8;
812 var->green.length = 8;
813 var->blue.offset = 0;
814 var->blue.length = 8;
815 var->transp.length = 8;
816 var->transp.offset = 24;
817 break;
818 }
819
820 var->red.msb_right = 0;
821 var->green.msb_right = 0;
822 var->blue.msb_right = 0;
823 var->transp.msb_right = 0;
824
825 if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
826 !info->monspecs.dclkmax || !fb_validate_mode(var, info))
827 mode_valid = 1;
828
829 /* calculate modeline if supported by monitor */
830 if (!mode_valid && info->monspecs.gtf) {
831 if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
832 mode_valid = 1;
833 }
834
835 if (!mode_valid) {
Geert Uytterhoeven9791d762007-02-12 00:55:19 -0800836 const struct fb_videomode *mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
838 mode = fb_find_best_mode(var, &info->modelist);
839 if (mode) {
840 fb_videomode_to_var(var, mode);
841 mode_valid = 1;
842 }
843 }
844
845 if (!mode_valid && info->monspecs.modedb_len)
846 return -EINVAL;
847
Paul Mundt74f482c2008-02-06 01:39:18 -0800848 /*
849 * If we're on a flat panel, check if the mode is outside of the
850 * panel dimensions. If so, cap it and try for the next best mode
851 * before bailing out.
852 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres ||
Paul Mundt74f482c2008-02-06 01:39:18 -0800854 par->fpHeight < var->yres)) {
855 const struct fb_videomode *mode;
856
857 var->xres = par->fpWidth;
858 var->yres = par->fpHeight;
859
860 mode = fb_find_best_mode(var, &info->modelist);
861 if (!mode) {
862 printk(KERN_ERR PFX "mode out of range of flat "
863 "panel dimensions\n");
864 return -EINVAL;
865 }
866
867 fb_videomode_to_var(var, mode);
868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
870 if (var->yres_virtual < var->yres)
871 var->yres_virtual = var->yres;
872
873 if (var->xres_virtual < var->xres)
874 var->xres_virtual = var->xres;
875
876 var->xres_virtual = (var->xres_virtual + 63) & ~63;
877
Antonino A. Daplas917bb072005-05-01 08:59:22 -0700878 vramlen = info->screen_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 pitch = ((var->xres_virtual * var->bits_per_pixel) + 7) / 8;
880 memlen = pitch * var->yres_virtual;
881
882 if (memlen > vramlen) {
883 var->yres_virtual = vramlen / pitch;
884
885 if (var->yres_virtual < var->yres) {
886 var->yres_virtual = var->yres;
887 var->xres_virtual = vramlen / var->yres_virtual;
888 var->xres_virtual /= var->bits_per_pixel / 8;
889 var->xres_virtual &= ~63;
890 pitch = (var->xres_virtual *
891 var->bits_per_pixel + 7) / 8;
892 memlen = pitch * var->yres;
893
894 if (var->xres_virtual < var->xres) {
895 printk("nvidiafb: required video memory, "
896 "%d bytes, for %dx%d-%d (virtual) "
897 "is out of range\n",
898 memlen, var->xres_virtual,
899 var->yres_virtual, var->bits_per_pixel);
900 err = -ENOMEM;
901 }
902 }
903 }
904
905 if (var->accel_flags) {
906 if (var->yres_virtual > 0x7fff)
907 var->yres_virtual = 0x7fff;
908 if (var->xres_virtual > 0x7fff)
909 var->xres_virtual = 0x7fff;
910 }
911
912 var->xres_virtual &= ~63;
913
914 NVTRACE_LEAVE();
915
916 return err;
917}
918
919static int nvidiafb_pan_display(struct fb_var_screeninfo *var,
920 struct fb_info *info)
921{
922 struct nvidia_par *par = info->par;
923 u32 total;
924
Antonino A. Daplas3c8d61b2005-11-13 16:06:34 -0800925 total = var->yoffset * info->fix.line_length + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
927 NVSetStartAddress(par, total);
928
929 return 0;
930}
931
932static int nvidiafb_blank(int blank, struct fb_info *info)
933{
934 struct nvidia_par *par = info->par;
935 unsigned char tmp, vesa;
936
937 tmp = NVReadSeq(par, 0x01) & ~0x20; /* screen on/off */
938 vesa = NVReadCrtc(par, 0x1a) & ~0xc0; /* sync on/off */
939
940 NVTRACE_ENTER();
941
942 if (blank)
943 tmp |= 0x20;
944
945 switch (blank) {
946 case FB_BLANK_UNBLANK:
947 case FB_BLANK_NORMAL:
948 break;
949 case FB_BLANK_VSYNC_SUSPEND:
950 vesa |= 0x80;
951 break;
952 case FB_BLANK_HSYNC_SUSPEND:
953 vesa |= 0x40;
954 break;
955 case FB_BLANK_POWERDOWN:
956 vesa |= 0xc0;
957 break;
958 }
959
960 NVWriteSeq(par, 0x01, tmp);
961 NVWriteCrtc(par, 0x1a, vesa);
962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 NVTRACE_LEAVE();
964
965 return 0;
966}
967
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -0700968/*
969 * Because the VGA registers are not mapped linearly in its MMIO space,
970 * restrict VGA register saving and restore to x86 only, where legacy VGA IO
971 * access is legal. Consequently, we must also check if the device is the
972 * primary display.
973 */
974#ifdef CONFIG_X86
975static void save_vga_x86(struct nvidia_par *par)
976{
977 struct resource *res= &par->pci_dev->resource[PCI_ROM_RESOURCE];
978
979 if (res && res->flags & IORESOURCE_ROM_SHADOW) {
980 memset(&par->vgastate, 0, sizeof(par->vgastate));
981 par->vgastate.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS |
982 VGA_SAVE_CMAP;
983 save_vga(&par->vgastate);
984 }
985}
986
987static void restore_vga_x86(struct nvidia_par *par)
988{
989 struct resource *res= &par->pci_dev->resource[PCI_ROM_RESOURCE];
990
991 if (res && res->flags & IORESOURCE_ROM_SHADOW)
992 restore_vga(&par->vgastate);
993}
994#else
995#define save_vga_x86(x) do {} while (0)
996#define restore_vga_x86(x) do {} while (0)
997#endif /* X86 */
998
999static int nvidiafb_open(struct fb_info *info, int user)
1000{
1001 struct nvidia_par *par = info->par;
1002
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -07001003 if (!par->open_count) {
1004 save_vga_x86(par);
1005 nvidia_save_vga(par, &par->initial_state);
1006 }
1007
1008 par->open_count++;
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -07001009 return 0;
1010}
1011
1012static int nvidiafb_release(struct fb_info *info, int user)
1013{
1014 struct nvidia_par *par = info->par;
1015 int err = 0;
1016
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -07001017 if (!par->open_count) {
1018 err = -EINVAL;
1019 goto done;
1020 }
1021
1022 if (par->open_count == 1) {
1023 nvidia_write_regs(par, &par->initial_state);
1024 restore_vga_x86(par);
1025 }
1026
1027 par->open_count--;
1028done:
Antonino A. Daplas2620c6e2007-05-08 00:39:42 -07001029 return err;
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -07001030}
1031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032static struct fb_ops nvidia_fb_ops = {
1033 .owner = THIS_MODULE,
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -07001034 .fb_open = nvidiafb_open,
1035 .fb_release = nvidiafb_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 .fb_check_var = nvidiafb_check_var,
1037 .fb_set_par = nvidiafb_set_par,
1038 .fb_setcolreg = nvidiafb_setcolreg,
1039 .fb_pan_display = nvidiafb_pan_display,
1040 .fb_blank = nvidiafb_blank,
1041 .fb_fillrect = nvidiafb_fillrect,
1042 .fb_copyarea = nvidiafb_copyarea,
1043 .fb_imageblit = nvidiafb_imageblit,
1044 .fb_cursor = nvidiafb_cursor,
1045 .fb_sync = nvidiafb_sync,
1046};
1047
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001048#ifdef CONFIG_PM
David Brownellc78a7c22006-08-14 23:11:06 -07001049static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001050{
1051 struct fb_info *info = pci_get_drvdata(dev);
1052 struct nvidia_par *par = info->par;
1053
David Brownellc78a7c22006-08-14 23:11:06 -07001054 if (mesg.event == PM_EVENT_PRETHAW)
1055 mesg.event = PM_EVENT_FREEZE;
Torben Hohnac751ef2011-01-25 15:07:35 -08001056 console_lock();
David Brownellc78a7c22006-08-14 23:11:06 -07001057 par->pm_state = mesg.event;
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001058
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01001059 if (mesg.event & PM_EVENT_SLEEP) {
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001060 fb_set_suspend(info, 1);
1061 nvidiafb_blank(FB_BLANK_POWERDOWN, info);
1062 nvidia_write_regs(par, &par->SavedReg);
1063 pci_save_state(dev);
1064 pci_disable_device(dev);
David Brownellc78a7c22006-08-14 23:11:06 -07001065 pci_set_power_state(dev, pci_choose_state(dev, mesg));
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001066 }
David Brownellc78a7c22006-08-14 23:11:06 -07001067 dev->dev.power.power_state = mesg;
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001068
Torben Hohnac751ef2011-01-25 15:07:35 -08001069 console_unlock();
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001070 return 0;
1071}
1072
1073static int nvidiafb_resume(struct pci_dev *dev)
1074{
1075 struct fb_info *info = pci_get_drvdata(dev);
1076 struct nvidia_par *par = info->par;
1077
Torben Hohnac751ef2011-01-25 15:07:35 -08001078 console_lock();
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001079 pci_set_power_state(dev, PCI_D0);
1080
1081 if (par->pm_state != PM_EVENT_FREEZE) {
1082 pci_restore_state(dev);
Antonino A. Daplas7b566b12006-10-03 01:14:53 -07001083
1084 if (pci_enable_device(dev))
1085 goto fail;
1086
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001087 pci_set_master(dev);
1088 }
1089
1090 par->pm_state = PM_EVENT_ON;
1091 nvidiafb_set_par(info);
1092 fb_set_suspend (info, 0);
1093 nvidiafb_blank(FB_BLANK_UNBLANK, info);
1094
Antonino A. Daplas7b566b12006-10-03 01:14:53 -07001095fail:
Torben Hohnac751ef2011-01-25 15:07:35 -08001096 console_unlock();
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001097 return 0;
1098}
1099#else
1100#define nvidiafb_suspend NULL
1101#define nvidiafb_resume NULL
1102#endif
1103
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001104static int nvidia_set_fbinfo(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105{
1106 struct fb_monspecs *specs = &info->monspecs;
1107 struct fb_videomode modedb;
1108 struct nvidia_par *par = info->par;
1109 int lpitch;
1110
1111 NVTRACE_ENTER();
1112 info->flags = FBINFO_DEFAULT
1113 | FBINFO_HWACCEL_IMAGEBLIT
1114 | FBINFO_HWACCEL_FILLRECT
1115 | FBINFO_HWACCEL_COPYAREA
1116 | FBINFO_HWACCEL_YPAN;
1117
1118 fb_videomode_to_modelist(info->monspecs.modedb,
1119 info->monspecs.modedb_len, &info->modelist);
1120 fb_var_to_videomode(&modedb, &nvidiafb_default_var);
1121
Antonino A. Daplasade91852006-01-09 20:53:39 -08001122 switch (bpp) {
1123 case 0 ... 8:
1124 bpp = 8;
1125 break;
1126 case 9 ... 16:
1127 bpp = 16;
1128 break;
1129 default:
1130 bpp = 32;
1131 break;
1132 }
1133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 if (specs->modedb != NULL) {
Geert Uytterhoeven9791d762007-02-12 00:55:19 -08001135 const struct fb_videomode *mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Geert Uytterhoeven9791d762007-02-12 00:55:19 -08001137 mode = fb_find_best_display(specs, &info->modelist);
1138 fb_videomode_to_var(&nvidiafb_default_var, mode);
Antonino A. Daplasade91852006-01-09 20:53:39 -08001139 nvidiafb_default_var.bits_per_pixel = bpp;
Antonino Daplasdb6778d2005-08-08 14:22:43 +08001140 } else if (par->fpWidth && par->fpHeight) {
1141 char buf[16];
1142
1143 memset(buf, 0, 16);
Antonino A. Daplas948a95f2005-09-09 13:09:59 -07001144 snprintf(buf, 15, "%dx%dMR", par->fpWidth, par->fpHeight);
Antonino Daplasdb6778d2005-08-08 14:22:43 +08001145 fb_find_mode(&nvidiafb_default_var, info, buf, specs->modedb,
Antonino A. Daplasade91852006-01-09 20:53:39 -08001146 specs->modedb_len, &modedb, bpp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148
1149 if (mode_option)
1150 fb_find_mode(&nvidiafb_default_var, info, mode_option,
Antonino A. Daplasade91852006-01-09 20:53:39 -08001151 specs->modedb, specs->modedb_len, &modedb, bpp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
1153 info->var = nvidiafb_default_var;
1154 info->fix.visual = (info->var.bits_per_pixel == 8) ?
1155 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
1156 info->pseudo_palette = par->pseudo_palette;
1157 fb_alloc_cmap(&info->cmap, 256, 0);
1158 fb_destroy_modedb(info->monspecs.modedb);
1159 info->monspecs.modedb = NULL;
1160
1161 /* maximize virtual vertical length */
1162 lpitch = info->var.xres_virtual *
1163 ((info->var.bits_per_pixel + 7) >> 3);
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001164 info->var.yres_virtual = info->screen_size / lpitch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166 info->pixmap.scan_align = 4;
1167 info->pixmap.buf_align = 4;
James Simmons58a60642005-06-21 17:17:08 -07001168 info->pixmap.access_align = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 info->pixmap.size = 8 * 1024;
1170 info->pixmap.flags = FB_PIXMAP_SYSTEM;
1171
Antonino A. Daplas7a482422005-09-21 07:30:21 +08001172 if (!hwcur)
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001173 info->fbops->fb_cursor = NULL;
Antonino A. Daplas7a482422005-09-21 07:30:21 +08001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 info->var.accel_flags = (!noaccel);
1176
1177 switch (par->Architecture) {
1178 case NV_ARCH_04:
1179 info->fix.accel = FB_ACCEL_NV4;
1180 break;
1181 case NV_ARCH_10:
1182 info->fix.accel = FB_ACCEL_NV_10;
1183 break;
1184 case NV_ARCH_20:
1185 info->fix.accel = FB_ACCEL_NV_20;
1186 break;
1187 case NV_ARCH_30:
1188 info->fix.accel = FB_ACCEL_NV_30;
1189 break;
1190 case NV_ARCH_40:
1191 info->fix.accel = FB_ACCEL_NV_40;
1192 break;
1193 }
1194
1195 NVTRACE_LEAVE();
1196
1197 return nvidiafb_check_var(&info->var, info);
1198}
1199
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001200static u32 nvidia_get_chipset(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001202 struct nvidia_par *par = info->par;
1203 u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device;
1204
Antonino A. Daplas8eec4982006-06-26 00:26:30 -07001205 printk(KERN_INFO PFX "Device ID: %x \n", id);
1206
Antonino A. Daplasac1ae162007-07-17 04:05:30 -07001207 if ((id & 0xfff0) == 0x00f0 ||
1208 (id & 0xfff0) == 0x02e0) {
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001209 /* pci-e */
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001210 id = NV_RD32(par->REGS, 0x1800);
1211
1212 if ((id & 0x0000ffff) == 0x000010DE)
1213 id = 0x10DE0000 | (id >> 16);
1214 else if ((id & 0xffff0000) == 0xDE100000) /* wrong endian */
1215 id = 0x10DE0000 | ((id << 8) & 0x0000ff00) |
1216 ((id >> 8) & 0x000000ff);
Antonino A. Daplas8eec4982006-06-26 00:26:30 -07001217 printk(KERN_INFO PFX "Subsystem ID: %x \n", id);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001218 }
1219
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001220 return id;
1221}
1222
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001223static u32 nvidia_get_arch(struct fb_info *info)
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001224{
1225 struct nvidia_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 u32 arch = 0;
1227
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001228 switch (par->Chipset & 0x0ff0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 case 0x0100: /* GeForce 256 */
1230 case 0x0110: /* GeForce2 MX */
1231 case 0x0150: /* GeForce2 */
1232 case 0x0170: /* GeForce4 MX */
1233 case 0x0180: /* GeForce4 MX (8x AGP) */
1234 case 0x01A0: /* nForce */
1235 case 0x01F0: /* nForce2 */
1236 arch = NV_ARCH_10;
1237 break;
1238 case 0x0200: /* GeForce3 */
1239 case 0x0250: /* GeForce4 Ti */
1240 case 0x0280: /* GeForce4 Ti (8x AGP) */
1241 arch = NV_ARCH_20;
1242 break;
1243 case 0x0300: /* GeForceFX 5800 */
1244 case 0x0310: /* GeForceFX 5600 */
1245 case 0x0320: /* GeForceFX 5200 */
1246 case 0x0330: /* GeForceFX 5900 */
1247 case 0x0340: /* GeForceFX 5700 */
1248 arch = NV_ARCH_30;
1249 break;
Wink Savillee40c6752006-11-10 12:27:52 -08001250 case 0x0040: /* GeForce 6800 */
1251 case 0x00C0: /* GeForce 6800 */
1252 case 0x0120: /* GeForce 6800 */
Wink Savillee40c6752006-11-10 12:27:52 -08001253 case 0x0140: /* GeForce 6600 */
1254 case 0x0160: /* GeForce 6200 */
1255 case 0x01D0: /* GeForce 7200, 7300, 7400 */
1256 case 0x0090: /* GeForce 7800 */
1257 case 0x0210: /* GeForce 6800 */
1258 case 0x0220: /* GeForce 6200 */
Wink Savillee40c6752006-11-10 12:27:52 -08001259 case 0x0240: /* GeForce 6100 */
1260 case 0x0290: /* GeForce 7900 */
1261 case 0x0390: /* GeForce 7600 */
Antonino A. Daplasac1ae162007-07-17 04:05:30 -07001262 case 0x03D0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 arch = NV_ARCH_40;
1264 break;
1265 case 0x0020: /* TNT, TNT2 */
1266 arch = NV_ARCH_04;
1267 break;
1268 default: /* unknown architecture */
1269 break;
1270 }
1271
1272 return arch;
1273}
1274
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001275static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276{
1277 struct nvidia_par *par;
1278 struct fb_info *info;
1279 unsigned short cmd;
1280
1281
1282 NVTRACE_ENTER();
1283 assert(pd != NULL);
1284
1285 info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev);
1286
1287 if (!info)
1288 goto err_out;
1289
Antonino A. Daplasc439e342006-01-09 20:53:02 -08001290 par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 par->pci_dev = pd;
Jiri Slabyf5610b92007-02-12 00:55:12 -08001292 info->pixmap.addr = kzalloc(8 * 1024, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
1294 if (info->pixmap.addr == NULL)
1295 goto err_out_kfree;
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (pci_enable_device(pd)) {
1298 printk(KERN_ERR PFX "cannot enable PCI device\n");
1299 goto err_out_enable;
1300 }
1301
1302 if (pci_request_regions(pd, "nvidiafb")) {
1303 printk(KERN_ERR PFX "cannot request PCI regions\n");
Antonino A. Daplasa06630f2006-06-26 00:27:04 -07001304 goto err_out_enable;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 }
1306
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 par->FlatPanel = flatpanel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 if (flatpanel == 1)
1309 printk(KERN_INFO PFX "flatpanel support enabled\n");
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -08001310 par->FPDither = fpdither;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
1312 par->CRTCnumber = forceCRTC;
1313 par->FpScale = (!noscale);
1314 par->paneltweak = paneltweak;
Antonino A. Daplas3c03ec22007-10-16 01:29:20 -07001315 par->reverse_i2c = reverse_i2c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
1317 /* enable IO and mem if not already done */
1318 pci_read_config_word(pd, PCI_COMMAND, &cmd);
1319 cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
1320 pci_write_config_word(pd, PCI_COMMAND, cmd);
1321
1322 nvidiafb_fix.mmio_start = pci_resource_start(pd, 0);
1323 nvidiafb_fix.smem_start = pci_resource_start(pd, 1);
1324 nvidiafb_fix.mmio_len = pci_resource_len(pd, 0);
1325
1326 par->REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len);
1327
1328 if (!par->REGS) {
1329 printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
1330 goto err_out_free_base0;
1331 }
1332
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001333 par->Chipset = nvidia_get_chipset(info);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001334 par->Architecture = nvidia_get_arch(info);
1335
1336 if (par->Architecture == 0) {
1337 printk(KERN_ERR PFX "unknown NV_ARCH\n");
1338 goto err_out_arch;
1339 }
1340
1341 sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4);
1342
Antonino A. Daplas918799a2006-01-09 20:53:40 -08001343 if (NVCommonSetup(info))
1344 goto err_out_arch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 par->FbAddress = nvidiafb_fix.smem_start;
1347 par->FbMapSize = par->RamAmountKBytes * 1024;
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001348 if (vram && vram * 1024 * 1024 < par->FbMapSize)
1349 par->FbMapSize = vram * 1024 * 1024;
1350
1351 /* Limit amount of vram to 64 MB */
1352 if (par->FbMapSize > 64 * 1024 * 1024)
1353 par->FbMapSize = 64 * 1024 * 1024;
1354
Benjamin Herrenschmidt0137ecf2006-01-09 20:51:27 -08001355 if(par->Architecture >= NV_ARCH_40)
1356 par->FbUsableSize = par->FbMapSize - (560 * 1024);
1357 else
1358 par->FbUsableSize = par->FbMapSize - (128 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 par->ScratchBufferSize = (par->Architecture < NV_ARCH_10) ? 8 * 1024 :
1360 16 * 1024;
1361 par->ScratchBufferStart = par->FbUsableSize - par->ScratchBufferSize;
Benjamin Herrenschmidt0137ecf2006-01-09 20:51:27 -08001362 par->CursorStart = par->FbUsableSize + (32 * 1024);
1363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 info->screen_base = ioremap(nvidiafb_fix.smem_start, par->FbMapSize);
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001365 info->screen_size = par->FbUsableSize;
1366 nvidiafb_fix.smem_len = par->RamAmountKBytes * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 if (!info->screen_base) {
1369 printk(KERN_ERR PFX "cannot ioremap FB base\n");
1370 goto err_out_free_base1;
1371 }
1372
1373 par->FbStart = info->screen_base;
1374
1375#ifdef CONFIG_MTRR
1376 if (!nomtrr) {
1377 par->mtrr.vram = mtrr_add(nvidiafb_fix.smem_start,
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001378 par->RamAmountKBytes * 1024,
1379 MTRR_TYPE_WRCOMB, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 if (par->mtrr.vram < 0) {
1381 printk(KERN_ERR PFX "unable to setup MTRR\n");
1382 } else {
1383 par->mtrr.vram_valid = 1;
1384 /* let there be speed */
1385 printk(KERN_INFO PFX "MTRR set to ON\n");
1386 }
1387 }
1388#endif /* CONFIG_MTRR */
1389
1390 info->fbops = &nvidia_fb_ops;
1391 info->fix = nvidiafb_fix;
1392
1393 if (nvidia_set_fbinfo(info) < 0) {
1394 printk(KERN_ERR PFX "error setting initial video mode\n");
1395 goto err_out_iounmap_fb;
1396 }
1397
1398 nvidia_save_vga(par, &par->SavedReg);
1399
Guido Guentherce38cac2006-07-30 03:04:21 -07001400 pci_set_drvdata(pd, info);
Richard Purdie202d4e62007-03-03 17:43:52 +00001401
1402 if (backlight)
1403 nvidia_bl_init(par);
1404
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 if (register_framebuffer(info) < 0) {
1406 printk(KERN_ERR PFX "error registering nVidia framebuffer\n");
1407 goto err_out_iounmap_fb;
1408 }
1409
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411 printk(KERN_INFO PFX
1412 "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
1413 info->fix.id,
1414 par->FbMapSize / (1024 * 1024), info->fix.smem_start);
Michael Hanselmann5474c122006-06-25 05:47:08 -07001415
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 NVTRACE_LEAVE();
1417 return 0;
1418
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001419err_out_iounmap_fb:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 iounmap(info->screen_base);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001421err_out_free_base1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 fb_destroy_modedb(info->monspecs.modedb);
1423 nvidia_delete_i2c_busses(par);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001424err_out_arch:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 iounmap(par->REGS);
Antonino A. Daplasa06630f2006-06-26 00:27:04 -07001426 err_out_free_base0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 pci_release_regions(pd);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001428err_out_enable:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 kfree(info->pixmap.addr);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001430err_out_kfree:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 framebuffer_release(info);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001432err_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 return -ENODEV;
1434}
1435
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001436static void nvidiafb_remove(struct pci_dev *pd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437{
1438 struct fb_info *info = pci_get_drvdata(pd);
1439 struct nvidia_par *par = info->par;
1440
1441 NVTRACE_ENTER();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
Richard Purdie37ce69a2007-02-10 14:10:33 +00001443 unregister_framebuffer(info);
1444
Michael Hanselmann5474c122006-06-25 05:47:08 -07001445 nvidia_bl_exit(par);
1446
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447#ifdef CONFIG_MTRR
1448 if (par->mtrr.vram_valid)
1449 mtrr_del(par->mtrr.vram, info->fix.smem_start,
1450 info->fix.smem_len);
1451#endif /* CONFIG_MTRR */
1452
1453 iounmap(info->screen_base);
1454 fb_destroy_modedb(info->monspecs.modedb);
1455 nvidia_delete_i2c_busses(par);
1456 iounmap(par->REGS);
1457 pci_release_regions(pd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 kfree(info->pixmap.addr);
1459 framebuffer_release(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 NVTRACE_LEAVE();
1461}
1462
1463/* ------------------------------------------------------------------------- *
1464 *
1465 * initialization
1466 *
1467 * ------------------------------------------------------------------------- */
1468
1469#ifndef MODULE
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001470static int nvidiafb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471{
1472 char *this_opt;
1473
1474 NVTRACE_ENTER();
1475 if (!options || !*options)
1476 return 0;
1477
1478 while ((this_opt = strsep(&options, ",")) != NULL) {
1479 if (!strncmp(this_opt, "forceCRTC", 9)) {
1480 char *p;
1481
1482 p = this_opt + 9;
1483 if (!*p || !*(++p))
1484 continue;
1485 forceCRTC = *p - '0';
1486 if (forceCRTC < 0 || forceCRTC > 1)
1487 forceCRTC = -1;
1488 } else if (!strncmp(this_opt, "flatpanel", 9)) {
1489 flatpanel = 1;
1490 } else if (!strncmp(this_opt, "hwcur", 5)) {
1491 hwcur = 1;
1492 } else if (!strncmp(this_opt, "noaccel", 6)) {
1493 noaccel = 1;
1494 } else if (!strncmp(this_opt, "noscale", 7)) {
1495 noscale = 1;
Antonino A. Daplas3c03ec22007-10-16 01:29:20 -07001496 } else if (!strncmp(this_opt, "reverse_i2c", 11)) {
1497 reverse_i2c = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 } else if (!strncmp(this_opt, "paneltweak:", 11)) {
1499 paneltweak = simple_strtoul(this_opt+11, NULL, 0);
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001500 } else if (!strncmp(this_opt, "vram:", 5)) {
1501 vram = simple_strtoul(this_opt+5, NULL, 0);
Richard Purdie202d4e62007-03-03 17:43:52 +00001502 } else if (!strncmp(this_opt, "backlight:", 10)) {
1503 backlight = simple_strtoul(this_opt+10, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504#ifdef CONFIG_MTRR
1505 } else if (!strncmp(this_opt, "nomtrr", 6)) {
Andrew Morton08346bf2012-01-12 17:17:34 -08001506 nomtrr = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507#endif
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -08001508 } else if (!strncmp(this_opt, "fpdither:", 9)) {
1509 fpdither = simple_strtol(this_opt+9, NULL, 0);
Antonino A. Daplasade91852006-01-09 20:53:39 -08001510 } else if (!strncmp(this_opt, "bpp:", 4)) {
1511 bpp = simple_strtoul(this_opt+4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 } else
1513 mode_option = this_opt;
1514 }
1515 NVTRACE_LEAVE();
1516 return 0;
1517}
1518#endif /* !MODULE */
1519
1520static struct pci_driver nvidiafb_driver = {
1521 .name = "nvidiafb",
1522 .id_table = nvidiafb_pci_tbl,
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001523 .probe = nvidiafb_probe,
1524 .suspend = nvidiafb_suspend,
1525 .resume = nvidiafb_resume,
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001526 .remove = nvidiafb_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527};
1528
1529/* ------------------------------------------------------------------------- *
1530 *
1531 * modularization
1532 *
1533 * ------------------------------------------------------------------------- */
1534
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001535static int nvidiafb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536{
1537#ifndef MODULE
1538 char *option = NULL;
1539
1540 if (fb_get_options("nvidiafb", &option))
1541 return -ENODEV;
1542 nvidiafb_setup(option);
1543#endif
1544 return pci_register_driver(&nvidiafb_driver);
1545}
1546
1547module_init(nvidiafb_init);
1548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549static void __exit nvidiafb_exit(void)
1550{
1551 pci_unregister_driver(&nvidiafb_driver);
1552}
1553
1554module_exit(nvidiafb_exit);
1555
1556module_param(flatpanel, int, 0);
1557MODULE_PARM_DESC(flatpanel,
1558 "Enables experimental flat panel support for some chipsets. "
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -08001559 "(0=disabled, 1=enabled, -1=autodetect) (default=-1)");
1560module_param(fpdither, int, 0);
1561MODULE_PARM_DESC(fpdither,
1562 "Enables dithering of flat panel for 6 bits panels. "
1563 "(0=disabled, 1=enabled, -1=autodetect) (default=-1)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564module_param(hwcur, int, 0);
1565MODULE_PARM_DESC(hwcur,
1566 "Enables hardware cursor implementation. (0 or 1=enabled) "
1567 "(default=0)");
1568module_param(noaccel, int, 0);
1569MODULE_PARM_DESC(noaccel,
1570 "Disables hardware acceleration. (0 or 1=disable) "
1571 "(default=0)");
1572module_param(noscale, int, 0);
1573MODULE_PARM_DESC(noscale,
1574 "Disables screen scaleing. (0 or 1=disable) "
1575 "(default=0, do scaling)");
1576module_param(paneltweak, int, 0);
1577MODULE_PARM_DESC(paneltweak,
1578 "Tweak display settings for flatpanels. "
1579 "(default=0, no tweaks)");
1580module_param(forceCRTC, int, 0);
1581MODULE_PARM_DESC(forceCRTC,
1582 "Forces usage of a particular CRTC in case autodetection "
1583 "fails. (0 or 1) (default=autodetect)");
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001584module_param(vram, int, 0);
1585MODULE_PARM_DESC(vram,
1586 "amount of framebuffer memory to remap in MiB"
1587 "(default=0 - remap entire memory)");
Antonino A. Daplasc439e342006-01-09 20:53:02 -08001588module_param(mode_option, charp, 0);
1589MODULE_PARM_DESC(mode_option, "Specify initial video mode");
Antonino A. Daplasade91852006-01-09 20:53:39 -08001590module_param(bpp, int, 0);
1591MODULE_PARM_DESC(bpp, "pixel width in bits"
1592 "(default=8)");
Antonino A. Daplas3c03ec22007-10-16 01:29:20 -07001593module_param(reverse_i2c, int, 0);
1594MODULE_PARM_DESC(reverse_i2c, "reverse port assignment of the i2c bus");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595#ifdef CONFIG_MTRR
Andrew Morton08346bf2012-01-12 17:17:34 -08001596module_param(nomtrr, bool, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) "
1598 "(default=0)");
1599#endif
1600
1601MODULE_AUTHOR("Antonino Daplas");
1602MODULE_DESCRIPTION("Framebuffer driver for nVidia graphics chipset");
1603MODULE_LICENSE("GPL");