/*
* linux/drivers/video/nvidia/nvidia.c - nVidia fb driver
*
* Copyright 2004 Antonino Daplas <adaplas@pol.net>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
*/
#include <linux/aperture.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/console.h>
#include <linux/backlight.h>
#include <linux/string_choices.h>
#ifdef CONFIG_BOOTX_TEXT
#include <asm/btext.h>
#endif
#include "nv_local.h"
#include "nv_type.h"
#include "nv_proto.h"
#include "nv_dma.h"
#ifdef CONFIG_FB_NVIDIA_DEBUG
#define NVTRACE printk
#else
#define NVTRACE if (0) printk
#endif
#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__)
#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__)
#ifdef CONFIG_FB_NVIDIA_DEBUG
#define assert(expr) \
if (!(expr)) { \
printk( "Assertion failed! %s,%s,%s,line=%d\n",\
#expr,__FILE__,__func__,__LINE__); \
BUG(); \
}
#else
#define assert(expr)
#endif
#define PFX "nvidiafb: "
/* HW cursor parameters */
#define MAX_CURS 32
static const struct pci_device_id nvidiafb_pci_tbl[] = {
{PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl);
/* command line data, set in nvidiafb_setup() */
static int flatpanel = -1; /* Autodetect later */
static int fpdither = -1;
static int forceCRTC = -1;
static int hwcur = 0;
static int noaccel = 0;
static int noscale = 0;
static int paneltweak = 0;
static int vram = 0;
static int bpp = 8;
static int reverse_i2c;
static bool nomtrr = false;
static int backlight = IS_BUILTIN(CONFIG_PMAC_BACKLIGHT);
static char *mode_option = NULL;
static struct fb_fix_screeninfo nvidiafb_fix = {
.type = FB_TYPE_PACKED_PIXELS,
.xpanstep = 8,
.ypanstep = 1,
};
static struct fb_var_screeninfo nvidiafb_default_var = {
.xres = 640,
.yres = 480,
.xres_virtual = 640,
.yres_virtual = 480,
.bits_per_pixel = 8,
.red = {0, 8, 0},
.green = {0, 8, 0},
.blue = {0, 8, 0},
.transp = {0, 0, 0},
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
.pixclock = 39721,
.left_margin = 40,
.right_margin = 24,
.upper_margin = 32,
.lower_margin = 11,
.hsync_len = 96,
.vsync_len = 2,
.vmode = FB_VMODE_NONINTERLACED
};
static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
u16 bg, u16 fg, u32 w, u32 h)
{
u32 *data = (u32 *) data8;
int i, j, k = 0;
u32 b, tmp;
w = (w + 1) & ~1;
for (i = 0; i < h; i++) {
b = *data++;
reverse_order(&b);
for (j = 0; j < w / 2; j++) {
tmp = 0;
#if defined (__BIG_ENDIAN)
tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
b <<= 1;
tmp |= (b & (1 << 31)) ? fg : bg;
b <<= 1;
#else
tmp = (b & 1) ? fg : bg;
b >>= 1;
tmp |= (b & 1) ? fg << 16 : bg << 16;
b >>= 1;
#endif
NV_WR32(&par->CURSOR[k++], 0, tmp);
}
k += (MAX_CURS - w) / 2;
}
}
static void nvidia_write_clut(struct nvidia_par *par,
u8 regnum, u8 red, u8 green, u8 blue)
{
NVWriteDacMask(par, 0xff);
NVWriteDacWriteAddr(par, regnum);
NVWriteDacData(par, red);
NVWriteDacData(par, green);
NVWriteDacData(par, blue);
}
static void nvidia_read_clut(struct nvidia_par *par,
u8 regnum, u8 * red, u8 * green, u8 * blue)
{
NVWriteDacMask(par, 0xff);
NVWriteDacReadAddr(par, regnum);
*red = NVReadDacData(par);
*green = NVReadDacData(par);
*blue = NVReadDacData(par);
}
static int nvidia_panel_tweak(struct nvidia_par *par,
struct _riva_hw_state *state)
{
int tweak = 0;
if (par->paneltweak) {
tweak = par->paneltweak;
} else {
/* Begin flat panel hacks.
* This is unfortunate, but some chips need this register
* tweaked or else you get artifacts where adjacent pixels are
* swapped. There are no hard rules for what to set here so all
* we can do is experiment and apply hacks.
*/
if (((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) {
/* At least one NV34 laptop needs this workaround. */
tweak = -1;
}
if ((par->Chipset & 0xfff0) == 0x0310)
tweak = 1;
/* end flat panel hacks */
}
return tweak;
}
static void nvidia_screen_off(struct nvidia_par *par, int on)
{
unsigned char tmp;
if (on) {
/*
* Turn off screen and disable sequencer.
*/
tmp = NVReadSeq(par, 0x01);
NVWriteSeq(par
|