blob: fbeeed5afe350deff19eea67c1463ba5ba158fe6 [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>
Paul Mackerras70abac62006-10-03 01:15:14 -070024#ifdef CONFIG_BOOTX_TEXT
25#include <asm/btext.h>
26#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include "nv_local.h"
29#include "nv_type.h"
30#include "nv_proto.h"
31#include "nv_dma.h"
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#ifdef CONFIG_FB_NVIDIA_DEBUG
34#define NVTRACE printk
35#else
36#define NVTRACE if (0) printk
37#endif
38
Harvey Harrison5ae12172008-04-28 02:15:47 -070039#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__)
40#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#ifdef CONFIG_FB_NVIDIA_DEBUG
43#define assert(expr) \
44 if (!(expr)) { \
45 printk( "Assertion failed! %s,%s,%s,line=%d\n",\
Harvey Harrison5ae12172008-04-28 02:15:47 -070046 #expr,__FILE__,__func__,__LINE__); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 BUG(); \
48 }
49#else
50#define assert(expr)
51#endif
52
53#define PFX "nvidiafb: "
54
55/* HW cursor parameters */
56#define MAX_CURS 32
57
Arvind Yadave40bbde2017-08-01 17:20:43 +020058static const struct pci_device_id nvidiafb_pci_tbl[] = {
Antonino A. Daplas8eec4982006-06-26 00:26:30 -070059 {PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
60 PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0},
61 { 0, }
Linus Torvalds1da177e2005-04-16 15:20:36 -070062};
Linus Torvalds1da177e2005-04-16 15:20:36 -070063MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl);
64
65/* command line data, set in nvidiafb_setup() */
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080066static int flatpanel = -1; /* Autodetect later */
67static int fpdither = -1;
68static int forceCRTC = -1;
69static int hwcur = 0;
70static int noaccel = 0;
71static int noscale = 0;
72static int paneltweak = 0;
73static int vram = 0;
74static int bpp = 8;
75static int reverse_i2c;
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080076static bool nomtrr = false;
Richard Purdie202d4e62007-03-03 17:43:52 +000077#ifdef CONFIG_PMAC_BACKLIGHT
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080078static int backlight = 1;
Richard Purdie202d4e62007-03-03 17:43:52 +000079#else
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080080static int backlight = 0;
Richard Purdie202d4e62007-03-03 17:43:52 +000081#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080083static char *mode_option = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080085static struct fb_fix_screeninfo nvidiafb_fix = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 .type = FB_TYPE_PACKED_PIXELS,
87 .xpanstep = 8,
88 .ypanstep = 1,
89};
90
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080091static struct fb_var_screeninfo nvidiafb_default_var = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 .xres = 640,
93 .yres = 480,
94 .xres_virtual = 640,
95 .yres_virtual = 480,
96 .bits_per_pixel = 8,
97 .red = {0, 8, 0},
98 .green = {0, 8, 0},
99 .blue = {0, 8, 0},
100 .transp = {0, 0, 0},
101 .activate = FB_ACTIVATE_NOW,
102 .height = -1,
103 .width = -1,
104 .pixclock = 39721,
105 .left_margin = 40,
106 .right_margin = 24,
107 .upper_margin = 32,
108 .lower_margin = 11,
109 .hsync_len = 96,
110 .vsync_len = 2,
111 .vmode = FB_VMODE_NONINTERLACED
112};
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
115 u16 bg, u16 fg, u32 w, u32 h)
116{
James Simmonsf1ab5da2005-06-21 17:17:07 -0700117 u32 *data = (u32 *) data8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 int i, j, k = 0;
119 u32 b, tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121 w = (w + 1) & ~1;
122
123 for (i = 0; i < h; i++) {
124 b = *data++;
125 reverse_order(&b);
126
127 for (j = 0; j < w / 2; j++) {
128 tmp = 0;
129#if defined (__BIG_ENDIAN)
130 tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
131 b <<= 1;
132 tmp |= (b & (1 << 31)) ? fg : bg;
133 b <<= 1;
134#else
135 tmp = (b & 1) ? fg : bg;
136 b >>= 1;
137 tmp |= (b & 1) ? fg << 16 : bg << 16;
138 b >>= 1;
139#endif
140 NV_WR32(&par->CURSOR[k++], 0, tmp);
141 }
142 k += (MAX_CURS - w) / 2;
143 }
144}
145
146static void nvidia_write_clut(struct nvidia_par *par,
147 u8 regnum, u8 red, u8 green, u8 blue)
148{
149 NVWriteDacMask(par, 0xff);
150 NVWriteDacWriteAddr(par, regnum);
151 NVWriteDacData(par, red);
152 NVWriteDacData(par, green);
153 NVWriteDacData(par, blue);
154}
155
156static void nvidia_read_clut(struct nvidia_par *par,
157 u8 regnum, u8 * red, u8 * green, u8 * blue)
158{
159 NVWriteDacMask(par, 0xff);
160 NVWriteDacReadAddr(par, regnum);
161 *red = NVReadDacData(par);
162 *green = NVReadDacData(par);
163 *blue = NVReadDacData(par);
164}
165
166static int nvidia_panel_tweak(struct nvidia_par *par,
167 struct _riva_hw_state *state)
168{
169 int tweak = 0;
170
171 if (par->paneltweak) {
172 tweak = par->paneltweak;
173 } else {
174 /* begin flat panel hacks */
175 /* This is unfortunate, but some chips need this register
176 tweaked or else you get artifacts where adjacent pixels are
177 swapped. There are no hard rules for what to set here so all
178 we can do is experiment and apply hacks. */
179
180 if(((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) {
181 /* At least one NV34 laptop needs this workaround. */
182 tweak = -1;
183 }
184
185 if((par->Chipset & 0xfff0) == 0x0310) {
186 tweak = 1;
187 }
188 /* end flat panel hacks */
189 }
190
191 return tweak;
192}
193
Antonino A. Daplasb9b26962007-05-08 00:38:23 -0700194static void nvidia_screen_off(struct nvidia_par *par, int on)
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -0800195{
196 unsigned char tmp;
197
198 if (on) {
199 /*
200 * Turn off screen and disable sequencer.
201 */
202 tmp = NVReadSeq(par, 0x01);
203
204 NVWriteSeq(par, 0x00, 0x01); /* Synchronous Reset */
205 NVWriteSeq(par, 0x01, tmp | 0x20); /* disable the display */
206 } else {
207 /*
208 * Reenable sequencer, then turn on screen.
209 */
210
211 tmp = NVReadSeq(par, 0x01);
212
213 NVWriteSeq(par, 0x01, tmp & ~0x20); /* reenable display */
214 NVWriteSeq(par, 0x00, 0x03); /* End Reset */
215 }
216}
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218static void nvidia_save_vga(struct nvidia_par *par,
219 struct _riva_hw_state *state)
220{
221 int i;
222
223 NVTRACE_ENTER();
224 NVLockUnlock(par, 0);
225
226 NVUnloadStateExt(par, state);
227
228 state->misc_output = NVReadMiscOut(par);
229
230 for (i = 0; i < NUM_CRT_REGS; i++)
231 state->crtc[i] = NVReadCrtc(par, i);
232
233 for (i = 0; i < NUM_ATC_REGS; i++)
234 state->attr[i] = NVReadAttr(par, i);
235
236 for (i = 0; i < NUM_GRC_REGS; i++)
237 state->gra[i] = NVReadGr(par, i);
238
239 for (i = 0; i < NUM_SEQ_REGS; i++)
240 state->seq[i] = NVReadSeq(par, i);
241 NVTRACE_LEAVE();
242}
243
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800244#undef DUMP_REG
245
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -0800246static void nvidia_write_regs(struct nvidia_par *par,
247 struct _riva_hw_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 int i;
250
251 NVTRACE_ENTER();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253 NVLoadStateExt(par, state);
254
255 NVWriteMiscOut(par, state->misc_output);
256
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800257 for (i = 1; i < NUM_SEQ_REGS; i++) {
258#ifdef DUMP_REG
259 printk(" SEQ[%02x] = %08x\n", i, state->seq[i]);
260#endif
261 NVWriteSeq(par, i, state->seq[i]);
262 }
263
264 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17] */
265 NVWriteCrtc(par, 0x11, state->crtc[0x11] & ~0x80);
266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 for (i = 0; i < NUM_CRT_REGS; i++) {
268 switch (i) {
269 case 0x19:
270 case 0x20 ... 0x40:
271 break;
272 default:
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800273#ifdef DUMP_REG
274 printk("CRTC[%02x] = %08x\n", i, state->crtc[i]);
275#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 NVWriteCrtc(par, i, state->crtc[i]);
277 }
278 }
279
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800280 for (i = 0; i < NUM_GRC_REGS; i++) {
281#ifdef DUMP_REG
282 printk(" GRA[%02x] = %08x\n", i, state->gra[i]);
283#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 NVWriteGr(par, i, state->gra[i]);
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800287 for (i = 0; i < NUM_ATC_REGS; i++) {
288#ifdef DUMP_REG
289 printk("ATTR[%02x] = %08x\n", i, state->attr[i]);
290#endif
291 NVWriteAttr(par, i, state->attr[i]);
292 }
293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 NVTRACE_LEAVE();
295}
296
297static int nvidia_calc_regs(struct fb_info *info)
298{
299 struct nvidia_par *par = info->par;
300 struct _riva_hw_state *state = &par->ModeReg;
Antonino A. Daplasb8c90942005-09-09 13:04:37 -0700301 int i, depth = fb_get_color_depth(&info->var, &info->fix);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 int h_display = info->var.xres / 8 - 1;
303 int h_start = (info->var.xres + info->var.right_margin) / 8 - 1;
304 int h_end = (info->var.xres + info->var.right_margin +
305 info->var.hsync_len) / 8 - 1;
306 int h_total = (info->var.xres + info->var.right_margin +
307 info->var.hsync_len + info->var.left_margin) / 8 - 5;
308 int h_blank_s = h_display;
309 int h_blank_e = h_total + 4;
310 int v_display = info->var.yres - 1;
311 int v_start = info->var.yres + info->var.lower_margin - 1;
312 int v_end = (info->var.yres + info->var.lower_margin +
313 info->var.vsync_len) - 1;
314 int v_total = (info->var.yres + info->var.lower_margin +
315 info->var.vsync_len + info->var.upper_margin) - 2;
316 int v_blank_s = v_display;
317 int v_blank_e = v_total + 1;
318
319 /*
320 * Set all CRTC values.
321 */
322
323 if (info->var.vmode & FB_VMODE_INTERLACED)
324 v_total |= 1;
325
326 if (par->FlatPanel == 1) {
327 v_start = v_total - 3;
328 v_end = v_total - 2;
329 v_blank_s = v_start;
330 h_start = h_total - 5;
331 h_end = h_total - 2;
332 h_blank_e = h_total + 4;
333 }
334
335 state->crtc[0x0] = Set8Bits(h_total);
336 state->crtc[0x1] = Set8Bits(h_display);
337 state->crtc[0x2] = Set8Bits(h_blank_s);
338 state->crtc[0x3] = SetBitField(h_blank_e, 4: 0, 4:0)
339 | SetBit(7);
340 state->crtc[0x4] = Set8Bits(h_start);
341 state->crtc[0x5] = SetBitField(h_blank_e, 5: 5, 7:7)
342 | SetBitField(h_end, 4: 0, 4:0);
343 state->crtc[0x6] = SetBitField(v_total, 7: 0, 7:0);
344 state->crtc[0x7] = SetBitField(v_total, 8: 8, 0:0)
345 | SetBitField(v_display, 8: 8, 1:1)
346 | SetBitField(v_start, 8: 8, 2:2)
347 | SetBitField(v_blank_s, 8: 8, 3:3)
348 | SetBit(4)
349 | SetBitField(v_total, 9: 9, 5:5)
350 | SetBitField(v_display, 9: 9, 6:6)
351 | SetBitField(v_start, 9: 9, 7:7);
352 state->crtc[0x9] = SetBitField(v_blank_s, 9: 9, 5:5)
353 | SetBit(6)
354 | ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0x00);
355 state->crtc[0x10] = Set8Bits(v_start);
356 state->crtc[0x11] = SetBitField(v_end, 3: 0, 3:0) | SetBit(5);
357 state->crtc[0x12] = Set8Bits(v_display);
358 state->crtc[0x13] = ((info->var.xres_virtual / 8) *
359 (info->var.bits_per_pixel / 8));
360 state->crtc[0x15] = Set8Bits(v_blank_s);
361 state->crtc[0x16] = Set8Bits(v_blank_e);
362
363 state->attr[0x10] = 0x01;
364
365 if (par->Television)
366 state->attr[0x11] = 0x00;
367
368 state->screen = SetBitField(h_blank_e, 6: 6, 4:4)
369 | SetBitField(v_blank_s, 10: 10, 3:3)
370 | SetBitField(v_start, 10: 10, 2:2)
371 | SetBitField(v_display, 10: 10, 1:1)
372 | SetBitField(v_total, 10: 10, 0:0);
373
374 state->horiz = SetBitField(h_total, 8: 8, 0:0)
375 | SetBitField(h_display, 8: 8, 1:1)
376 | SetBitField(h_blank_s, 8: 8, 2:2)
377 | SetBitField(h_start, 8: 8, 3:3);
378
379 state->extra = SetBitField(v_total, 11: 11, 0:0)
380 | SetBitField(v_display, 11: 11, 2:2)
381 | SetBitField(v_start, 11: 11, 4:4)
382 | SetBitField(v_blank_s, 11: 11, 6:6);
383
384 if (info->var.vmode & FB_VMODE_INTERLACED) {
385 h_total = (h_total >> 1) & ~1;
386 state->interlace = Set8Bits(h_total);
387 state->horiz |= SetBitField(h_total, 8: 8, 4:4);
388 } else {
389 state->interlace = 0xff; /* interlace off */
390 }
391
392 /*
393 * Calculate the extended registers.
394 */
395
396 if (depth < 24)
397 i = depth;
398 else
399 i = 32;
400
401 if (par->Architecture >= NV_ARCH_10)
402 par->CURSOR = (volatile u32 __iomem *)(info->screen_base +
403 par->CursorStart);
404
405 if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
406 state->misc_output &= ~0x40;
407 else
408 state->misc_output |= 0x40;
409 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
410 state->misc_output &= ~0x80;
411 else
412 state->misc_output |= 0x80;
413
414 NVCalcStateExt(par, state, i, info->var.xres_virtual,
415 info->var.xres, info->var.yres_virtual,
416 1000000000 / info->var.pixclock, info->var.vmode);
417
418 state->scale = NV_RD32(par->PRAMDAC, 0x00000848) & 0xfff000ff;
419 if (par->FlatPanel == 1) {
420 state->pixel |= (1 << 7);
421
422 if (!par->fpScaler || (par->fpWidth <= info->var.xres)
423 || (par->fpHeight <= info->var.yres)) {
424 state->scale |= (1 << 8);
425 }
426
427 if (!par->crtcSync_read) {
428 state->crtcSync = NV_RD32(par->PRAMDAC, 0x0828);
429 par->crtcSync_read = 1;
430 }
431
432 par->PanelTweak = nvidia_panel_tweak(par, state);
433 }
434
435 state->vpll = state->pll;
436 state->vpll2 = state->pll;
437 state->vpllB = state->pllB;
438 state->vpll2B = state->pllB;
439
440 VGA_WR08(par->PCIO, 0x03D4, 0x1C);
441 state->fifo = VGA_RD08(par->PCIO, 0x03D5) & ~(1<<5);
442
443 if (par->CRTCnumber) {
444 state->head = NV_RD32(par->PCRTC0, 0x00000860) & ~0x00001000;
445 state->head2 = NV_RD32(par->PCRTC0, 0x00002860) | 0x00001000;
446 state->crtcOwner = 3;
447 state->pllsel |= 0x20000800;
448 state->vpll = NV_RD32(par->PRAMDAC0, 0x00000508);
449 if (par->twoStagePLL)
450 state->vpllB = NV_RD32(par->PRAMDAC0, 0x00000578);
451 } else if (par->twoHeads) {
452 state->head = NV_RD32(par->PCRTC0, 0x00000860) | 0x00001000;
453 state->head2 = NV_RD32(par->PCRTC0, 0x00002860) & ~0x00001000;
454 state->crtcOwner = 0;
455 state->vpll2 = NV_RD32(par->PRAMDAC0, 0x0520);
456 if (par->twoStagePLL)
457 state->vpll2B = NV_RD32(par->PRAMDAC0, 0x057C);
458 }
459
460 state->cursorConfig = 0x00000100;
461
462 if (info->var.vmode & FB_VMODE_DOUBLE)
463 state->cursorConfig |= (1 << 4);
464
465 if (par->alphaCursor) {
466 if ((par->Chipset & 0x0ff0) != 0x0110)
467 state->cursorConfig |= 0x04011000;
468 else
469 state->cursorConfig |= 0x14011000;
470 state->general |= (1 << 29);
471 } else
472 state->cursorConfig |= 0x02000000;
473
474 if (par->twoHeads) {
475 if ((par->Chipset & 0x0ff0) == 0x0110) {
476 state->dither = NV_RD32(par->PRAMDAC, 0x0528) &
477 ~0x00010000;
478 if (par->FPDither)
479 state->dither |= 0x00010000;
480 } else {
481 state->dither = NV_RD32(par->PRAMDAC, 0x083C) & ~1;
482 if (par->FPDither)
483 state->dither |= 1;
484 }
485 }
486
487 state->timingH = 0;
488 state->timingV = 0;
489 state->displayV = info->var.xres;
490
491 return 0;
492}
493
494static void nvidia_init_vga(struct fb_info *info)
495{
496 struct nvidia_par *par = info->par;
497 struct _riva_hw_state *state = &par->ModeReg;
498 int i;
499
500 for (i = 0; i < 0x10; i++)
501 state->attr[i] = i;
502 state->attr[0x10] = 0x41;
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800503 state->attr[0x11] = 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 state->attr[0x12] = 0x0f;
505 state->attr[0x13] = 0x00;
506 state->attr[0x14] = 0x00;
507
508 memset(state->crtc, 0x00, NUM_CRT_REGS);
509 state->crtc[0x0a] = 0x20;
510 state->crtc[0x17] = 0xe3;
511 state->crtc[0x18] = 0xff;
512 state->crtc[0x28] = 0x40;
513
514 memset(state->gra, 0x00, NUM_GRC_REGS);
515 state->gra[0x05] = 0x40;
516 state->gra[0x06] = 0x05;
517 state->gra[0x07] = 0x0f;
518 state->gra[0x08] = 0xff;
519
520 state->seq[0x00] = 0x03;
521 state->seq[0x01] = 0x01;
522 state->seq[0x02] = 0x0f;
523 state->seq[0x03] = 0x00;
524 state->seq[0x04] = 0x0e;
525
526 state->misc_output = 0xeb;
527}
528
529static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
530{
531 struct nvidia_par *par = info->par;
532 u8 data[MAX_CURS * MAX_CURS / 8];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 int i, set = cursor->set;
James Simmonsf1ab5da2005-06-21 17:17:07 -0700534 u16 fg, bg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Antonino A. Daplas7a482422005-09-21 07:30:21 +0800536 if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
James Simmonsf1ab5da2005-06-21 17:17:07 -0700537 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 NVShowHideCursor(par, 0);
540
541 if (par->cursor_reset) {
542 set = FB_CUR_SETALL;
543 par->cursor_reset = 0;
544 }
545
546 if (set & FB_CUR_SETSIZE)
547 memset_io(par->CURSOR, 0, MAX_CURS * MAX_CURS * 2);
548
549 if (set & FB_CUR_SETPOS) {
550 u32 xx, yy, temp;
551
552 yy = cursor->image.dy - info->var.yoffset;
553 xx = cursor->image.dx - info->var.xoffset;
554 temp = xx & 0xFFFF;
555 temp |= yy << 16;
556
557 NV_WR32(par->PRAMDAC, 0x0000300, temp);
558 }
559
560 if (set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
561 u32 bg_idx = cursor->image.bg_color;
562 u32 fg_idx = cursor->image.fg_color;
563 u32 s_pitch = (cursor->image.width + 7) >> 3;
564 u32 d_pitch = MAX_CURS / 8;
565 u8 *dat = (u8 *) cursor->image.data;
566 u8 *msk = (u8 *) cursor->mask;
567 u8 *src;
568
Kees Cook6da2ec52018-06-12 13:55:00 -0700569 src = kmalloc_array(s_pitch, cursor->image.height, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 if (src) {
572 switch (cursor->rop) {
573 case ROP_XOR:
James Simmonsf1ab5da2005-06-21 17:17:07 -0700574 for (i = 0; i < s_pitch * cursor->image.height; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 src[i] = dat[i] ^ msk[i];
576 break;
577 case ROP_COPY:
578 default:
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 }
583
James Simmonsf1ab5da2005-06-21 17:17:07 -0700584 fb_pad_aligned_buffer(data, d_pitch, src, s_pitch,
585 cursor->image.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
587 bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
588 ((info->cmap.green[bg_idx] & 0xf8) << 2) |
589 ((info->cmap.blue[bg_idx] & 0xf8) >> 3) | 1 << 15;
590
591 fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
592 ((info->cmap.green[fg_idx] & 0xf8) << 2) |
593 ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | 1 << 15;
594
595 NVLockUnlock(par, 0);
596
597 nvidiafb_load_cursor_image(par, data, bg, fg,
598 cursor->image.width,
599 cursor->image.height);
600 kfree(src);
601 }
602 }
603
604 if (cursor->enable)
605 NVShowHideCursor(par, 1);
606
607 return 0;
608}
609
610static int nvidiafb_set_par(struct fb_info *info)
611{
612 struct nvidia_par *par = info->par;
613
614 NVTRACE_ENTER();
615
616 NVLockUnlock(par, 1);
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -0800617 if (!par->FlatPanel || !par->twoHeads)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 par->FPDither = 0;
619
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -0800620 if (par->FPDither < 0) {
621 if ((par->Chipset & 0x0ff0) == 0x0110)
622 par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x0528)
623 & 0x00010000);
624 else
625 par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x083C) & 1);
626 printk(KERN_INFO PFX "Flat panel dithering %s\n",
627 par->FPDither ? "enabled" : "disabled");
628 }
629
Antonino A. Daplasb8c90942005-09-09 13:04:37 -0700630 info->fix.visual = (info->var.bits_per_pixel == 8) ?
631 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 nvidia_init_vga(info);
634 nvidia_calc_regs(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 NVLockUnlock(par, 0);
637 if (par->twoHeads) {
638 VGA_WR08(par->PCIO, 0x03D4, 0x44);
639 VGA_WR08(par->PCIO, 0x03D5, par->ModeReg.crtcOwner);
640 NVLockUnlock(par, 0);
641 }
642
Antonino A. Daplasb9b26962007-05-08 00:38:23 -0700643 nvidia_screen_off(par, 1);
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800644
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -0800645 nvidia_write_regs(par, &par->ModeReg);
646 NVSetStartAddress(par, 0);
Benjamin Herrenschmidt85f15032005-11-07 01:00:30 -0800647
648#if defined (__BIG_ENDIAN)
649 /* turn on LFB swapping */
650 {
651 unsigned char tmp;
652
653 VGA_WR08(par->PCIO, 0x3d4, 0x46);
654 tmp = VGA_RD08(par->PCIO, 0x3d5);
655 tmp |= (1 << 7);
656 VGA_WR08(par->PCIO, 0x3d5, tmp);
657 }
658#endif
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 info->fix.line_length = (info->var.xres_virtual *
661 info->var.bits_per_pixel) >> 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 if (info->var.accel_flags) {
663 info->fbops->fb_imageblit = nvidiafb_imageblit;
664 info->fbops->fb_fillrect = nvidiafb_fillrect;
665 info->fbops->fb_copyarea = nvidiafb_copyarea;
666 info->fbops->fb_sync = nvidiafb_sync;
667 info->pixmap.scan_align = 4;
668 info->flags &= ~FBINFO_HWACCEL_DISABLED;
Antonino A. Daplas01b15bd2007-07-17 04:05:25 -0700669 info->flags |= FBINFO_READS_FAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 NVResetGraphics(info);
671 } else {
672 info->fbops->fb_imageblit = cfb_imageblit;
673 info->fbops->fb_fillrect = cfb_fillrect;
674 info->fbops->fb_copyarea = cfb_copyarea;
675 info->fbops->fb_sync = NULL;
676 info->pixmap.scan_align = 1;
677 info->flags |= FBINFO_HWACCEL_DISABLED;
Antonino A. Daplas01b15bd2007-07-17 04:05:25 -0700678 info->flags &= ~FBINFO_READS_FAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 }
680
681 par->cursor_reset = 1;
682
Antonino A. Daplasb9b26962007-05-08 00:38:23 -0700683 nvidia_screen_off(par, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Paul Mackerras70abac62006-10-03 01:15:14 -0700685#ifdef CONFIG_BOOTX_TEXT
686 /* Update debug text engine */
687 btext_update_display(info->fix.smem_start,
688 info->var.xres, info->var.yres,
689 info->var.bits_per_pixel, info->fix.line_length);
690#endif
691
Antonino A. Daplasb9b26962007-05-08 00:38:23 -0700692 NVLockUnlock(par, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 NVTRACE_LEAVE();
694 return 0;
695}
696
697static int nvidiafb_setcolreg(unsigned regno, unsigned red, unsigned green,
698 unsigned blue, unsigned transp,
699 struct fb_info *info)
700{
701 struct nvidia_par *par = info->par;
702 int i;
703
704 NVTRACE_ENTER();
705 if (regno >= (1 << info->var.green.length))
706 return -EINVAL;
707
708 if (info->var.grayscale) {
709 /* gray = 0.30*R + 0.59*G + 0.11*B */
710 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
711 }
712
713 if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
714 ((u32 *) info->pseudo_palette)[regno] =
715 (regno << info->var.red.offset) |
716 (regno << info->var.green.offset) |
717 (regno << info->var.blue.offset);
718 }
719
720 switch (info->var.bits_per_pixel) {
721 case 8:
722 /* "transparent" stuff is completely ignored. */
723 nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8);
724 break;
725 case 16:
726 if (info->var.green.length == 5) {
727 for (i = 0; i < 8; i++) {
728 nvidia_write_clut(par, regno * 8 + i, red >> 8,
729 green >> 8, blue >> 8);
730 }
731 } else {
732 u8 r, g, b;
733
734 if (regno < 32) {
735 for (i = 0; i < 8; i++) {
736 nvidia_write_clut(par, regno * 8 + i,
737 red >> 8, green >> 8,
738 blue >> 8);
739 }
740 }
741
742 nvidia_read_clut(par, regno * 4, &r, &g, &b);
743
744 for (i = 0; i < 4; i++)
745 nvidia_write_clut(par, regno * 4 + i, r,
746 green >> 8, b);
747 }
748 break;
749 case 32:
750 nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8);
751 break;
752 default:
753 /* do nothing */
754 break;
755 }
756
757 NVTRACE_LEAVE();
758 return 0;
759}
760
761static int nvidiafb_check_var(struct fb_var_screeninfo *var,
762 struct fb_info *info)
763{
764 struct nvidia_par *par = info->par;
765 int memlen, vramlen, mode_valid = 0;
766 int pitch, err = 0;
767
768 NVTRACE_ENTER();
769
770 var->transp.offset = 0;
771 var->transp.length = 0;
772
773 var->xres &= ~7;
774
775 if (var->bits_per_pixel <= 8)
776 var->bits_per_pixel = 8;
777 else if (var->bits_per_pixel <= 16)
778 var->bits_per_pixel = 16;
779 else
780 var->bits_per_pixel = 32;
781
782 switch (var->bits_per_pixel) {
783 case 8:
784 var->red.offset = 0;
785 var->red.length = 8;
786 var->green.offset = 0;
787 var->green.length = 8;
788 var->blue.offset = 0;
789 var->blue.length = 8;
790 var->transp.offset = 0;
791 var->transp.length = 0;
792 break;
793 case 16:
794 var->green.length = (var->green.length < 6) ? 5 : 6;
795 var->red.length = 5;
796 var->blue.length = 5;
797 var->transp.length = 6 - var->green.length;
798 var->blue.offset = 0;
799 var->green.offset = 5;
800 var->red.offset = 5 + var->green.length;
801 var->transp.offset = (5 + var->red.offset) & 15;
802 break;
803 case 32: /* RGBA 8888 */
804 var->red.offset = 16;
805 var->red.length = 8;
806 var->green.offset = 8;
807 var->green.length = 8;
808 var->blue.offset = 0;
809 var->blue.length = 8;
810 var->transp.length = 8;
811 var->transp.offset = 24;
812 break;
813 }
814
815 var->red.msb_right = 0;
816 var->green.msb_right = 0;
817 var->blue.msb_right = 0;
818 var->transp.msb_right = 0;
819
820 if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
821 !info->monspecs.dclkmax || !fb_validate_mode(var, info))
822 mode_valid = 1;
823
824 /* calculate modeline if supported by monitor */
825 if (!mode_valid && info->monspecs.gtf) {
826 if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
827 mode_valid = 1;
828 }
829
830 if (!mode_valid) {
Geert Uytterhoeven9791d762007-02-12 00:55:19 -0800831 const struct fb_videomode *mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 mode = fb_find_best_mode(var, &info->modelist);
834 if (mode) {
835 fb_videomode_to_var(var, mode);
836 mode_valid = 1;
837 }
838 }
839
840 if (!mode_valid && info->monspecs.modedb_len)
841 return -EINVAL;
842
Paul Mundt74f482c2008-02-06 01:39:18 -0800843 /*
844 * If we're on a flat panel, check if the mode is outside of the
845 * panel dimensions. If so, cap it and try for the next best mode
846 * before bailing out.
847 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres ||
Paul Mundt74f482c2008-02-06 01:39:18 -0800849 par->fpHeight < var->yres)) {
850 const struct fb_videomode *mode;
851
852 var->xres = par->fpWidth;
853 var->yres = par->fpHeight;
854
855 mode = fb_find_best_mode(var, &info->modelist);
856 if (!mode) {
857 printk(KERN_ERR PFX "mode out of range of flat "
858 "panel dimensions\n");
859 return -EINVAL;
860 }
861
862 fb_videomode_to_var(var, mode);
863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
865 if (var->yres_virtual < var->yres)
866 var->yres_virtual = var->yres;
867
868 if (var->xres_virtual < var->xres)
869 var->xres_virtual = var->xres;
870
871 var->xres_virtual = (var->xres_virtual + 63) & ~63;
872
Antonino A. Daplas917bb072005-05-01 08:59:22 -0700873 vramlen = info->screen_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 pitch = ((var->xres_virtual * var->bits_per_pixel) + 7) / 8;
875 memlen = pitch * var->yres_virtual;
876
877 if (memlen > vramlen) {
878 var->yres_virtual = vramlen / pitch;
879
880 if (var->yres_virtual < var->yres) {
881 var->yres_virtual = var->yres;
882 var->xres_virtual = vramlen / var->yres_virtual;
883 var->xres_virtual /= var->bits_per_pixel / 8;
884 var->xres_virtual &= ~63;
885 pitch = (var->xres_virtual *
886 var->bits_per_pixel + 7) / 8;
887 memlen = pitch * var->yres;
888
889 if (var->xres_virtual < var->xres) {
890 printk("nvidiafb: required video memory, "
891 "%d bytes, for %dx%d-%d (virtual) "
892 "is out of range\n",
893 memlen, var->xres_virtual,
894 var->yres_virtual, var->bits_per_pixel);
895 err = -ENOMEM;
896 }
897 }
898 }
899
900 if (var->accel_flags) {
901 if (var->yres_virtual > 0x7fff)
902 var->yres_virtual = 0x7fff;
903 if (var->xres_virtual > 0x7fff)
904 var->xres_virtual = 0x7fff;
905 }
906
907 var->xres_virtual &= ~63;
908
909 NVTRACE_LEAVE();
910
911 return err;
912}
913
914static int nvidiafb_pan_display(struct fb_var_screeninfo *var,
915 struct fb_info *info)
916{
917 struct nvidia_par *par = info->par;
918 u32 total;
919
Antonino A. Daplas3c8d61b2005-11-13 16:06:34 -0800920 total = var->yoffset * info->fix.line_length + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
922 NVSetStartAddress(par, total);
923
924 return 0;
925}
926
927static int nvidiafb_blank(int blank, struct fb_info *info)
928{
929 struct nvidia_par *par = info->par;
930 unsigned char tmp, vesa;
931
932 tmp = NVReadSeq(par, 0x01) & ~0x20; /* screen on/off */
933 vesa = NVReadCrtc(par, 0x1a) & ~0xc0; /* sync on/off */
934
935 NVTRACE_ENTER();
936
937 if (blank)
938 tmp |= 0x20;
939
940 switch (blank) {
941 case FB_BLANK_UNBLANK:
942 case FB_BLANK_NORMAL:
943 break;
944 case FB_BLANK_VSYNC_SUSPEND:
945 vesa |= 0x80;
946 break;
947 case FB_BLANK_HSYNC_SUSPEND:
948 vesa |= 0x40;
949 break;
950 case FB_BLANK_POWERDOWN:
951 vesa |= 0xc0;
952 break;
953 }
954
955 NVWriteSeq(par, 0x01, tmp);
956 NVWriteCrtc(par, 0x1a, vesa);
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 NVTRACE_LEAVE();
959
960 return 0;
961}
962
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -0700963/*
964 * Because the VGA registers are not mapped linearly in its MMIO space,
965 * restrict VGA register saving and restore to x86 only, where legacy VGA IO
966 * access is legal. Consequently, we must also check if the device is the
967 * primary display.
968 */
969#ifdef CONFIG_X86
970static void save_vga_x86(struct nvidia_par *par)
971{
972 struct resource *res= &par->pci_dev->resource[PCI_ROM_RESOURCE];
973
974 if (res && res->flags & IORESOURCE_ROM_SHADOW) {
975 memset(&par->vgastate, 0, sizeof(par->vgastate));
976 par->vgastate.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS |
977 VGA_SAVE_CMAP;
978 save_vga(&par->vgastate);
979 }
980}
981
982static void restore_vga_x86(struct nvidia_par *par)
983{
984 struct resource *res= &par->pci_dev->resource[PCI_ROM_RESOURCE];
985
986 if (res && res->flags & IORESOURCE_ROM_SHADOW)
987 restore_vga(&par->vgastate);
988}
989#else
990#define save_vga_x86(x) do {} while (0)
991#define restore_vga_x86(x) do {} while (0)
992#endif /* X86 */
993
994static int nvidiafb_open(struct fb_info *info, int user)
995{
996 struct nvidia_par *par = info->par;
997
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -0700998 if (!par->open_count) {
999 save_vga_x86(par);
1000 nvidia_save_vga(par, &par->initial_state);
1001 }
1002
1003 par->open_count++;
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -07001004 return 0;
1005}
1006
1007static int nvidiafb_release(struct fb_info *info, int user)
1008{
1009 struct nvidia_par *par = info->par;
1010 int err = 0;
1011
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -07001012 if (!par->open_count) {
1013 err = -EINVAL;
1014 goto done;
1015 }
1016
1017 if (par->open_count == 1) {
1018 nvidia_write_regs(par, &par->initial_state);
1019 restore_vga_x86(par);
1020 }
1021
1022 par->open_count--;
1023done:
Antonino A. Daplas2620c6e2007-05-08 00:39:42 -07001024 return err;
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -07001025}
1026
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027static struct fb_ops nvidia_fb_ops = {
1028 .owner = THIS_MODULE,
Antonino A. Daplas7dfe50b2007-05-08 00:38:33 -07001029 .fb_open = nvidiafb_open,
1030 .fb_release = nvidiafb_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 .fb_check_var = nvidiafb_check_var,
1032 .fb_set_par = nvidiafb_set_par,
1033 .fb_setcolreg = nvidiafb_setcolreg,
1034 .fb_pan_display = nvidiafb_pan_display,
1035 .fb_blank = nvidiafb_blank,
1036 .fb_fillrect = nvidiafb_fillrect,
1037 .fb_copyarea = nvidiafb_copyarea,
1038 .fb_imageblit = nvidiafb_imageblit,
1039 .fb_cursor = nvidiafb_cursor,
1040 .fb_sync = nvidiafb_sync,
1041};
1042
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001043#ifdef CONFIG_PM
David Brownellc78a7c22006-08-14 23:11:06 -07001044static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001045{
1046 struct fb_info *info = pci_get_drvdata(dev);
1047 struct nvidia_par *par = info->par;
1048
David Brownellc78a7c22006-08-14 23:11:06 -07001049 if (mesg.event == PM_EVENT_PRETHAW)
1050 mesg.event = PM_EVENT_FREEZE;
Torben Hohnac751ef2011-01-25 15:07:35 -08001051 console_lock();
David Brownellc78a7c22006-08-14 23:11:06 -07001052 par->pm_state = mesg.event;
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001053
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01001054 if (mesg.event & PM_EVENT_SLEEP) {
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001055 fb_set_suspend(info, 1);
1056 nvidiafb_blank(FB_BLANK_POWERDOWN, info);
1057 nvidia_write_regs(par, &par->SavedReg);
1058 pci_save_state(dev);
1059 pci_disable_device(dev);
David Brownellc78a7c22006-08-14 23:11:06 -07001060 pci_set_power_state(dev, pci_choose_state(dev, mesg));
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001061 }
David Brownellc78a7c22006-08-14 23:11:06 -07001062 dev->dev.power.power_state = mesg;
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001063
Torben Hohnac751ef2011-01-25 15:07:35 -08001064 console_unlock();
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001065 return 0;
1066}
1067
1068static int nvidiafb_resume(struct pci_dev *dev)
1069{
1070 struct fb_info *info = pci_get_drvdata(dev);
1071 struct nvidia_par *par = info->par;
1072
Torben Hohnac751ef2011-01-25 15:07:35 -08001073 console_lock();
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001074 pci_set_power_state(dev, PCI_D0);
1075
1076 if (par->pm_state != PM_EVENT_FREEZE) {
1077 pci_restore_state(dev);
Antonino A. Daplas7b566b12006-10-03 01:14:53 -07001078
1079 if (pci_enable_device(dev))
1080 goto fail;
1081
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001082 pci_set_master(dev);
1083 }
1084
1085 par->pm_state = PM_EVENT_ON;
1086 nvidiafb_set_par(info);
1087 fb_set_suspend (info, 0);
1088 nvidiafb_blank(FB_BLANK_UNBLANK, info);
1089
Antonino A. Daplas7b566b12006-10-03 01:14:53 -07001090fail:
Torben Hohnac751ef2011-01-25 15:07:35 -08001091 console_unlock();
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001092 return 0;
1093}
1094#else
1095#define nvidiafb_suspend NULL
1096#define nvidiafb_resume NULL
1097#endif
1098
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001099static int nvidia_set_fbinfo(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100{
1101 struct fb_monspecs *specs = &info->monspecs;
1102 struct fb_videomode modedb;
1103 struct nvidia_par *par = info->par;
1104 int lpitch;
1105
1106 NVTRACE_ENTER();
1107 info->flags = FBINFO_DEFAULT
1108 | FBINFO_HWACCEL_IMAGEBLIT
1109 | FBINFO_HWACCEL_FILLRECT
1110 | FBINFO_HWACCEL_COPYAREA
1111 | FBINFO_HWACCEL_YPAN;
1112
1113 fb_videomode_to_modelist(info->monspecs.modedb,
1114 info->monspecs.modedb_len, &info->modelist);
1115 fb_var_to_videomode(&modedb, &nvidiafb_default_var);
1116
Antonino A. Daplasade91852006-01-09 20:53:39 -08001117 switch (bpp) {
1118 case 0 ... 8:
1119 bpp = 8;
1120 break;
1121 case 9 ... 16:
1122 bpp = 16;
1123 break;
1124 default:
1125 bpp = 32;
1126 break;
1127 }
1128
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 if (specs->modedb != NULL) {
Geert Uytterhoeven9791d762007-02-12 00:55:19 -08001130 const struct fb_videomode *mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Geert Uytterhoeven9791d762007-02-12 00:55:19 -08001132 mode = fb_find_best_display(specs, &info->modelist);
1133 fb_videomode_to_var(&nvidiafb_default_var, mode);
Antonino A. Daplasade91852006-01-09 20:53:39 -08001134 nvidiafb_default_var.bits_per_pixel = bpp;
Antonino Daplasdb6778d2005-08-08 14:22:43 +08001135 } else if (par->fpWidth && par->fpHeight) {
1136 char buf[16];
1137
1138 memset(buf, 0, 16);
Antonino A. Daplas948a95f2005-09-09 13:09:59 -07001139 snprintf(buf, 15, "%dx%dMR", par->fpWidth, par->fpHeight);
Antonino Daplasdb6778d2005-08-08 14:22:43 +08001140 fb_find_mode(&nvidiafb_default_var, info, buf, specs->modedb,
Antonino A. Daplasade91852006-01-09 20:53:39 -08001141 specs->modedb_len, &modedb, bpp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 }
1143
1144 if (mode_option)
1145 fb_find_mode(&nvidiafb_default_var, info, mode_option,
Antonino A. Daplasade91852006-01-09 20:53:39 -08001146 specs->modedb, specs->modedb_len, &modedb, bpp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
1148 info->var = nvidiafb_default_var;
1149 info->fix.visual = (info->var.bits_per_pixel == 8) ?
1150 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
1151 info->pseudo_palette = par->pseudo_palette;
1152 fb_alloc_cmap(&info->cmap, 256, 0);
1153 fb_destroy_modedb(info->monspecs.modedb);
1154 info->monspecs.modedb = NULL;
1155
1156 /* maximize virtual vertical length */
1157 lpitch = info->var.xres_virtual *
1158 ((info->var.bits_per_pixel + 7) >> 3);
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001159 info->var.yres_virtual = info->screen_size / lpitch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
1161 info->pixmap.scan_align = 4;
1162 info->pixmap.buf_align = 4;
James Simmons58a60642005-06-21 17:17:08 -07001163 info->pixmap.access_align = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 info->pixmap.size = 8 * 1024;
1165 info->pixmap.flags = FB_PIXMAP_SYSTEM;
1166
Antonino A. Daplas7a482422005-09-21 07:30:21 +08001167 if (!hwcur)
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001168 info->fbops->fb_cursor = NULL;
Antonino A. Daplas7a482422005-09-21 07:30:21 +08001169
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 info->var.accel_flags = (!noaccel);
1171
1172 switch (par->Architecture) {
1173 case NV_ARCH_04:
1174 info->fix.accel = FB_ACCEL_NV4;
1175 break;
1176 case NV_ARCH_10:
1177 info->fix.accel = FB_ACCEL_NV_10;
1178 break;
1179 case NV_ARCH_20:
1180 info->fix.accel = FB_ACCEL_NV_20;
1181 break;
1182 case NV_ARCH_30:
1183 info->fix.accel = FB_ACCEL_NV_30;
1184 break;
1185 case NV_ARCH_40:
1186 info->fix.accel = FB_ACCEL_NV_40;
1187 break;
1188 }
1189
1190 NVTRACE_LEAVE();
1191
1192 return nvidiafb_check_var(&info->var, info);
1193}
1194
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001195static u32 nvidia_get_chipset(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196{
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001197 struct nvidia_par *par = info->par;
1198 u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device;
1199
Antonino A. Daplas8eec4982006-06-26 00:26:30 -07001200 printk(KERN_INFO PFX "Device ID: %x \n", id);
1201
Antonino A. Daplasac1ae162007-07-17 04:05:30 -07001202 if ((id & 0xfff0) == 0x00f0 ||
1203 (id & 0xfff0) == 0x02e0) {
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001204 /* pci-e */
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001205 id = NV_RD32(par->REGS, 0x1800);
1206
1207 if ((id & 0x0000ffff) == 0x000010DE)
1208 id = 0x10DE0000 | (id >> 16);
1209 else if ((id & 0xffff0000) == 0xDE100000) /* wrong endian */
1210 id = 0x10DE0000 | ((id << 8) & 0x0000ff00) |
1211 ((id >> 8) & 0x000000ff);
Antonino A. Daplas8eec4982006-06-26 00:26:30 -07001212 printk(KERN_INFO PFX "Subsystem ID: %x \n", id);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001213 }
1214
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001215 return id;
1216}
1217
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001218static u32 nvidia_get_arch(struct fb_info *info)
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001219{
1220 struct nvidia_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 u32 arch = 0;
1222
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001223 switch (par->Chipset & 0x0ff0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 case 0x0100: /* GeForce 256 */
1225 case 0x0110: /* GeForce2 MX */
1226 case 0x0150: /* GeForce2 */
1227 case 0x0170: /* GeForce4 MX */
1228 case 0x0180: /* GeForce4 MX (8x AGP) */
1229 case 0x01A0: /* nForce */
1230 case 0x01F0: /* nForce2 */
1231 arch = NV_ARCH_10;
1232 break;
1233 case 0x0200: /* GeForce3 */
1234 case 0x0250: /* GeForce4 Ti */
1235 case 0x0280: /* GeForce4 Ti (8x AGP) */
1236 arch = NV_ARCH_20;
1237 break;
1238 case 0x0300: /* GeForceFX 5800 */
1239 case 0x0310: /* GeForceFX 5600 */
1240 case 0x0320: /* GeForceFX 5200 */
1241 case 0x0330: /* GeForceFX 5900 */
1242 case 0x0340: /* GeForceFX 5700 */
1243 arch = NV_ARCH_30;
1244 break;
Wink Savillee40c6752006-11-10 12:27:52 -08001245 case 0x0040: /* GeForce 6800 */
1246 case 0x00C0: /* GeForce 6800 */
1247 case 0x0120: /* GeForce 6800 */
Wink Savillee40c6752006-11-10 12:27:52 -08001248 case 0x0140: /* GeForce 6600 */
1249 case 0x0160: /* GeForce 6200 */
1250 case 0x01D0: /* GeForce 7200, 7300, 7400 */
1251 case 0x0090: /* GeForce 7800 */
1252 case 0x0210: /* GeForce 6800 */
1253 case 0x0220: /* GeForce 6200 */
Wink Savillee40c6752006-11-10 12:27:52 -08001254 case 0x0240: /* GeForce 6100 */
1255 case 0x0290: /* GeForce 7900 */
1256 case 0x0390: /* GeForce 7600 */
Antonino A. Daplasac1ae162007-07-17 04:05:30 -07001257 case 0x03D0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 arch = NV_ARCH_40;
1259 break;
1260 case 0x0020: /* TNT, TNT2 */
1261 arch = NV_ARCH_04;
1262 break;
1263 default: /* unknown architecture */
1264 break;
1265 }
1266
1267 return arch;
1268}
1269
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001270static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271{
1272 struct nvidia_par *par;
1273 struct fb_info *info;
1274 unsigned short cmd;
1275
1276
1277 NVTRACE_ENTER();
1278 assert(pd != NULL);
1279
1280 info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev);
1281
1282 if (!info)
1283 goto err_out;
1284
Antonino A. Daplasc439e342006-01-09 20:53:02 -08001285 par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 par->pci_dev = pd;
Jiri Slabyf5610b92007-02-12 00:55:12 -08001287 info->pixmap.addr = kzalloc(8 * 1024, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
1289 if (info->pixmap.addr == NULL)
1290 goto err_out_kfree;
1291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 if (pci_enable_device(pd)) {
1293 printk(KERN_ERR PFX "cannot enable PCI device\n");
1294 goto err_out_enable;
1295 }
1296
1297 if (pci_request_regions(pd, "nvidiafb")) {
1298 printk(KERN_ERR PFX "cannot request PCI regions\n");
Antonino A. Daplasa06630f2006-06-26 00:27:04 -07001299 goto err_out_enable;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 }
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 par->FlatPanel = flatpanel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 if (flatpanel == 1)
1304 printk(KERN_INFO PFX "flatpanel support enabled\n");
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -08001305 par->FPDither = fpdither;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
1307 par->CRTCnumber = forceCRTC;
1308 par->FpScale = (!noscale);
1309 par->paneltweak = paneltweak;
Antonino A. Daplas3c03ec22007-10-16 01:29:20 -07001310 par->reverse_i2c = reverse_i2c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
1312 /* enable IO and mem if not already done */
1313 pci_read_config_word(pd, PCI_COMMAND, &cmd);
1314 cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
1315 pci_write_config_word(pd, PCI_COMMAND, cmd);
1316
1317 nvidiafb_fix.mmio_start = pci_resource_start(pd, 0);
1318 nvidiafb_fix.smem_start = pci_resource_start(pd, 1);
1319 nvidiafb_fix.mmio_len = pci_resource_len(pd, 0);
1320
1321 par->REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len);
1322
1323 if (!par->REGS) {
1324 printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
1325 goto err_out_free_base0;
1326 }
1327
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001328 par->Chipset = nvidia_get_chipset(info);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001329 par->Architecture = nvidia_get_arch(info);
1330
1331 if (par->Architecture == 0) {
1332 printk(KERN_ERR PFX "unknown NV_ARCH\n");
1333 goto err_out_arch;
1334 }
1335
1336 sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4);
1337
Antonino A. Daplas918799a2006-01-09 20:53:40 -08001338 if (NVCommonSetup(info))
1339 goto err_out_arch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
1341 par->FbAddress = nvidiafb_fix.smem_start;
1342 par->FbMapSize = par->RamAmountKBytes * 1024;
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001343 if (vram && vram * 1024 * 1024 < par->FbMapSize)
1344 par->FbMapSize = vram * 1024 * 1024;
1345
1346 /* Limit amount of vram to 64 MB */
1347 if (par->FbMapSize > 64 * 1024 * 1024)
1348 par->FbMapSize = 64 * 1024 * 1024;
1349
Benjamin Herrenschmidt0137ecf2006-01-09 20:51:27 -08001350 if(par->Architecture >= NV_ARCH_40)
1351 par->FbUsableSize = par->FbMapSize - (560 * 1024);
1352 else
1353 par->FbUsableSize = par->FbMapSize - (128 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 par->ScratchBufferSize = (par->Architecture < NV_ARCH_10) ? 8 * 1024 :
1355 16 * 1024;
1356 par->ScratchBufferStart = par->FbUsableSize - par->ScratchBufferSize;
Benjamin Herrenschmidt0137ecf2006-01-09 20:51:27 -08001357 par->CursorStart = par->FbUsableSize + (32 * 1024);
1358
Luis R. Rodriguez3b213c2f2015-04-21 13:16:28 -07001359 info->screen_base = ioremap_wc(nvidiafb_fix.smem_start,
1360 par->FbMapSize);
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001361 info->screen_size = par->FbUsableSize;
1362 nvidiafb_fix.smem_len = par->RamAmountKBytes * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
1364 if (!info->screen_base) {
1365 printk(KERN_ERR PFX "cannot ioremap FB base\n");
1366 goto err_out_free_base1;
1367 }
1368
1369 par->FbStart = info->screen_base;
1370
Luis R. Rodriguez3b213c2f2015-04-21 13:16:28 -07001371 if (!nomtrr)
1372 par->wc_cookie = arch_phys_wc_add(nvidiafb_fix.smem_start,
1373 par->RamAmountKBytes * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
1375 info->fbops = &nvidia_fb_ops;
1376 info->fix = nvidiafb_fix;
1377
1378 if (nvidia_set_fbinfo(info) < 0) {
1379 printk(KERN_ERR PFX "error setting initial video mode\n");
1380 goto err_out_iounmap_fb;
1381 }
1382
1383 nvidia_save_vga(par, &par->SavedReg);
1384
Guido Guentherce38cac2006-07-30 03:04:21 -07001385 pci_set_drvdata(pd, info);
Richard Purdie202d4e62007-03-03 17:43:52 +00001386
1387 if (backlight)
1388 nvidia_bl_init(par);
1389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 if (register_framebuffer(info) < 0) {
1391 printk(KERN_ERR PFX "error registering nVidia framebuffer\n");
1392 goto err_out_iounmap_fb;
1393 }
1394
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396 printk(KERN_INFO PFX
1397 "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
1398 info->fix.id,
1399 par->FbMapSize / (1024 * 1024), info->fix.smem_start);
Michael Hanselmann5474c122006-06-25 05:47:08 -07001400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 NVTRACE_LEAVE();
1402 return 0;
1403
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001404err_out_iounmap_fb:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 iounmap(info->screen_base);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001406err_out_free_base1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 fb_destroy_modedb(info->monspecs.modedb);
1408 nvidia_delete_i2c_busses(par);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001409err_out_arch:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 iounmap(par->REGS);
Antonino A. Daplasa06630f2006-06-26 00:27:04 -07001411 err_out_free_base0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 pci_release_regions(pd);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001413err_out_enable:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 kfree(info->pixmap.addr);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001415err_out_kfree:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 framebuffer_release(info);
Antonino A. Daplasc549dc62006-01-09 20:53:33 -08001417err_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 return -ENODEV;
1419}
1420
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001421static void nvidiafb_remove(struct pci_dev *pd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422{
1423 struct fb_info *info = pci_get_drvdata(pd);
1424 struct nvidia_par *par = info->par;
1425
1426 NVTRACE_ENTER();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Richard Purdie37ce69a2007-02-10 14:10:33 +00001428 unregister_framebuffer(info);
1429
Michael Hanselmann5474c122006-06-25 05:47:08 -07001430 nvidia_bl_exit(par);
Luis R. Rodriguez3b213c2f2015-04-21 13:16:28 -07001431 arch_phys_wc_del(par->wc_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 iounmap(info->screen_base);
1433 fb_destroy_modedb(info->monspecs.modedb);
1434 nvidia_delete_i2c_busses(par);
1435 iounmap(par->REGS);
1436 pci_release_regions(pd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 kfree(info->pixmap.addr);
1438 framebuffer_release(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 NVTRACE_LEAVE();
1440}
1441
1442/* ------------------------------------------------------------------------- *
1443 *
1444 * initialization
1445 *
1446 * ------------------------------------------------------------------------- */
1447
1448#ifndef MODULE
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001449static int nvidiafb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450{
1451 char *this_opt;
1452
1453 NVTRACE_ENTER();
1454 if (!options || !*options)
1455 return 0;
1456
1457 while ((this_opt = strsep(&options, ",")) != NULL) {
1458 if (!strncmp(this_opt, "forceCRTC", 9)) {
1459 char *p;
1460
1461 p = this_opt + 9;
1462 if (!*p || !*(++p))
1463 continue;
1464 forceCRTC = *p - '0';
1465 if (forceCRTC < 0 || forceCRTC > 1)
1466 forceCRTC = -1;
1467 } else if (!strncmp(this_opt, "flatpanel", 9)) {
1468 flatpanel = 1;
1469 } else if (!strncmp(this_opt, "hwcur", 5)) {
1470 hwcur = 1;
1471 } else if (!strncmp(this_opt, "noaccel", 6)) {
1472 noaccel = 1;
1473 } else if (!strncmp(this_opt, "noscale", 7)) {
1474 noscale = 1;
Antonino A. Daplas3c03ec22007-10-16 01:29:20 -07001475 } else if (!strncmp(this_opt, "reverse_i2c", 11)) {
1476 reverse_i2c = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 } else if (!strncmp(this_opt, "paneltweak:", 11)) {
1478 paneltweak = simple_strtoul(this_opt+11, NULL, 0);
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001479 } else if (!strncmp(this_opt, "vram:", 5)) {
1480 vram = simple_strtoul(this_opt+5, NULL, 0);
Richard Purdie202d4e62007-03-03 17:43:52 +00001481 } else if (!strncmp(this_opt, "backlight:", 10)) {
1482 backlight = simple_strtoul(this_opt+10, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 } else if (!strncmp(this_opt, "nomtrr", 6)) {
Andrew Morton08346bf2012-01-12 17:17:34 -08001484 nomtrr = true;
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -08001485 } else if (!strncmp(this_opt, "fpdither:", 9)) {
1486 fpdither = simple_strtol(this_opt+9, NULL, 0);
Antonino A. Daplasade91852006-01-09 20:53:39 -08001487 } else if (!strncmp(this_opt, "bpp:", 4)) {
1488 bpp = simple_strtoul(this_opt+4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 } else
1490 mode_option = this_opt;
1491 }
1492 NVTRACE_LEAVE();
1493 return 0;
1494}
1495#endif /* !MODULE */
1496
1497static struct pci_driver nvidiafb_driver = {
1498 .name = "nvidiafb",
1499 .id_table = nvidiafb_pci_tbl,
Antonino A. Daplas7a07cd72006-03-27 01:17:22 -08001500 .probe = nvidiafb_probe,
1501 .suspend = nvidiafb_suspend,
1502 .resume = nvidiafb_resume,
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001503 .remove = nvidiafb_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504};
1505
1506/* ------------------------------------------------------------------------- *
1507 *
1508 * modularization
1509 *
1510 * ------------------------------------------------------------------------- */
1511
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001512static int nvidiafb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513{
1514#ifndef MODULE
1515 char *option = NULL;
1516
1517 if (fb_get_options("nvidiafb", &option))
1518 return -ENODEV;
1519 nvidiafb_setup(option);
1520#endif
1521 return pci_register_driver(&nvidiafb_driver);
1522}
1523
1524module_init(nvidiafb_init);
1525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526static void __exit nvidiafb_exit(void)
1527{
1528 pci_unregister_driver(&nvidiafb_driver);
1529}
1530
1531module_exit(nvidiafb_exit);
1532
1533module_param(flatpanel, int, 0);
1534MODULE_PARM_DESC(flatpanel,
1535 "Enables experimental flat panel support for some chipsets. "
Benjamin Herrenschmidtb8c49ef2005-11-07 01:00:32 -08001536 "(0=disabled, 1=enabled, -1=autodetect) (default=-1)");
1537module_param(fpdither, int, 0);
1538MODULE_PARM_DESC(fpdither,
1539 "Enables dithering of flat panel for 6 bits panels. "
1540 "(0=disabled, 1=enabled, -1=autodetect) (default=-1)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541module_param(hwcur, int, 0);
1542MODULE_PARM_DESC(hwcur,
1543 "Enables hardware cursor implementation. (0 or 1=enabled) "
1544 "(default=0)");
1545module_param(noaccel, int, 0);
1546MODULE_PARM_DESC(noaccel,
1547 "Disables hardware acceleration. (0 or 1=disable) "
1548 "(default=0)");
1549module_param(noscale, int, 0);
1550MODULE_PARM_DESC(noscale,
Colin Ian King105ac272018-05-15 12:41:11 +02001551 "Disables screen scaling. (0 or 1=disable) "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 "(default=0, do scaling)");
1553module_param(paneltweak, int, 0);
1554MODULE_PARM_DESC(paneltweak,
1555 "Tweak display settings for flatpanels. "
1556 "(default=0, no tweaks)");
1557module_param(forceCRTC, int, 0);
1558MODULE_PARM_DESC(forceCRTC,
1559 "Forces usage of a particular CRTC in case autodetection "
1560 "fails. (0 or 1) (default=autodetect)");
Antonino A. Daplas917bb072005-05-01 08:59:22 -07001561module_param(vram, int, 0);
1562MODULE_PARM_DESC(vram,
1563 "amount of framebuffer memory to remap in MiB"
1564 "(default=0 - remap entire memory)");
Antonino A. Daplasc439e342006-01-09 20:53:02 -08001565module_param(mode_option, charp, 0);
1566MODULE_PARM_DESC(mode_option, "Specify initial video mode");
Antonino A. Daplasade91852006-01-09 20:53:39 -08001567module_param(bpp, int, 0);
1568MODULE_PARM_DESC(bpp, "pixel width in bits"
1569 "(default=8)");
Antonino A. Daplas3c03ec22007-10-16 01:29:20 -07001570module_param(reverse_i2c, int, 0);
1571MODULE_PARM_DESC(reverse_i2c, "reverse port assignment of the i2c bus");
Andrew Morton08346bf2012-01-12 17:17:34 -08001572module_param(nomtrr, bool, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) "
1574 "(default=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576MODULE_AUTHOR("Antonino Daplas");
1577MODULE_DESCRIPTION("Framebuffer driver for nVidia graphics chipset");
1578MODULE_LICENSE("GPL");