2191 lines · 57.2 KB · C
RawDownload
/* * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver * * Maintained by Ani Joshi <ajoshi@shell.unixbox.com> * * Copyright 1999-2000 Jeff Garzik * * Contributors: * *	Ani Joshi:  Lots of debugging and cleanup work, really helped *	get the driver going * *	Ferenc Bakonyi:  Bug fixes, cleanup, modularization * *	Jindrich Makovicka:  Accel code help, hw cursor, mtrr * *	Paul Richards:  Bug fixes, updates * * Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven * Includes riva_hw.c from nVidia, see copyright below. * KGI code provided the basis for state storage, init, and mode switching. * * 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. * * Known bugs and issues: *	restoring text mode fails *	doublescan modes are broken */ #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/backlight.h>#include <linux/bitrev.h>#ifdef CONFIG_PMAC_BACKLIGHT#include <asm/machdep.h>#include <asm/backlight.h>#endif #include "rivafb.h"#include "nvreg.h" /* version number of this driver */#define RIVAFB_VERSION "0.9.5b" /* ------------------------------------------------------------------------- * * * various helpful macros and constants * * ------------------------------------------------------------------------- */#ifdef CONFIG_FB_RIVA_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_RIVA_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 "rivafb: " /* macro that allows you to set overflow bits */#define SetBitField(value,from,to) SetBF(to,GetBF(value,from))#define SetBit(n)		(1<<(n))#define Set8Bits(value)		((value)&0xff) /* HW cursor parameters */#define MAX_CURS		32 /* ------------------------------------------------------------------------- * * * prototypes * * ------------------------------------------------------------------------- */ static int rivafb_blank(int blank, struct fb_info *info); /* ------------------------------------------------------------------------- * * * card identification * * ------------------------------------------------------------------------- */ static const struct pci_device_id rivafb_pci_tbl[] = {	{ PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	// NF2/IGP version, GeForce 4 MX, NV18	{ PCI_VENDOR_ID_NVIDIA, 0x01f0,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ 0, } /* terminate list */};MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); /* ------------------------------------------------------------------------- * * * global variables * * ------------------------------------------------------------------------- */ /* command line data, set in rivafb_setup() */static int flatpanel = -1; /* Autodetect later */static int forceCRTC = -1;static bool noaccel  = 0;static bool nomtrr = 0;static int backlight = IS_BUILTIN(CONFIG_PMAC_BACKLIGHT); static char *mode_option = NULL;static bool strictmode       = 0; static struct fb_fix_screeninfo rivafb_fix = {	.type		= FB_TYPE_PACKED_PIXELS,	.xpanstep	= 1,	.ypanstep	= 1,}; static struct fb_var_screeninfo rivafb_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}; /* from GGI */static const struct riva_regs reg_template = {	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* ATTR */	 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,	 0x41, 0x01, 0x0F, 0x00, 0x00},	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* CRT  */	 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3,	/* 0x10 */	 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0x20 */	 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0x30 */	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	 0x00,							/* 0x40 */	 },	{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,	/* GRA  */	 0xFF},	{0x03, 0x01, 0x0F, 0x00, 0x0E},				/* SEQ  */	0xEB							/* MISC */}; /* * Backlight control */#ifdef CONFIG_FB_RIVA_BACKLIGHT/* We do not have any information about which values are allowed, thus * we used safe values. */#define MIN_LEVEL 0x158#define MAX_LEVEL 0x534#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX) static int riva_bl_get_level_brightness(struct riva_par *par,		int level){	struct fb_info *info = pci_get_drvdata(par->pdev);	int nlevel; 	/* Get and convert the value */	/* No locking on bl_curve since accessing a single value */	nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP; 	if (nlevel < 0)		nlevel = 0;	else if (nlevel < MIN_LEVEL)		nlevel = MIN_LEVEL;	else if (nlevel > MAX_LEVEL)		nlevel = MAX_LEVEL; 	return nlevel;} static int riva_bl_update_status(struct backlight_device *bd){	struct riva_par *par = bl_get_data(bd);	U032 tmp_pcrt, tmp_pmc;	int level; 	if (bd->props.power != FB_BLANK_UNBLANK ||	    bd->props.fb_blank != FB_BLANK_UNBLANK)		level = 0;	else		level = bd->props.brightness; 	tmp_pmc = NV_RD32(par->riva.PMC, 0x10F0) & 0x0000FFFF;	tmp_pcrt = NV_RD32(par->riva.PCRTC0, 0x081C) & 0xFFFFFFFC;	if(level > 0) {		tmp_pcrt |= 0x1;		tmp_pmc |= (1 << 31); /* backlight bit */		tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */	}	NV_WR32(par->riva.PCRTC0, 0x081C, tmp_pcrt);	NV_WR32(par->riva.PMC, 0x10F0, tmp_pmc); 	return 0;} static const struct backlight_ops riva_bl_ops = {	.update_status	= riva_bl_update_status,}; static void riva_bl_init(struct riva_par *par){	struct backlight_properties props;	struct fb_info *info = pci_get_drvdata(par->pdev);	struct backlight_device *bd;	char name[12]; 	if (!par->FlatPanel)		return; #ifdef CONFIG_PMAC_BACKLIGHT	if (!machine_is(powermac) ||	    !pmac_has_backlight_type("mnca"))		return;#endif 	snprintf(name, sizeof(name), "rivabl%d", info->node); 	memset(&props, 0, sizeof(struct backlight_properties));	props.type = BACKLIGHT_RAW;	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;	bd = backlight_device_register(name, info->dev, par, &riva_bl_ops,				       &props);	if (IS_ERR(bd)) {		info->bl_dev = NULL;		printk(KERN_WARNING "riva: Backlight registration failed\n");		goto error;	} 	info->bl_dev = bd;	fb_bl_default_curve(info, 0,		MIN_LEVEL * FB_BACKLIGHT_MAX / MAX_LEVEL,		FB_BACKLIGHT_MAX); 	bd->props.brightness = bd->props.max_brightness;	bd->props.power = FB_BLANK_UNBLANK;	backlight_update_status(bd); 	printk("riva: Backlight initialized (%s)\n", name); 	return; error:	return;} static void riva_bl_exit(struct fb_info *info){	struct backlight_device *bd = info->bl_dev; 	backlight_device_unregister(bd);	printk("riva: Backlight unloaded\n");}#elsestatic inline void riva_bl_init(struct riva_par *par) {}static inline void riva_bl_exit(struct fb_info *info) {}#endif /* CONFIG_FB_RIVA_BACKLIGHT */ /* ------------------------------------------------------------------------- * * * MMIO access macros * * ------------------------------------------------------------------------- */ static inline void CRTCout(struct riva_par *par, unsigned char index,			   unsigned char val){	VGA_WR08(par->riva.PCIO, 0x3d4, index);	VGA_WR08(par->riva.PCIO, 0x3d5, val);} static inline unsigned char CRTCin(struct riva_par *par,				   unsigned char index){	VGA_WR08(par->riva.PCIO, 0x3d4, index);	return (VGA_RD08(par->riva.PCIO, 0x3d5));} static inline void GRAout(struct riva_par *par, unsigned char index,			  unsigned char val){	VGA_WR08(par->riva.PVIO, 0x3ce, index);	VGA_WR08(par->riva.PVIO, 0x3cf, val);} static inline unsigned char GRAin(struct riva_par *par,				  unsigned char index){	VGA_WR08(par->riva.PVIO, 0x3ce, index);	return (VGA_RD08(par->riva.PVIO, 0x3cf));} static inline void SEQout(struct riva_par *par, unsigned char index,			  unsigned char val){	VGA_WR08(par->riva.PVIO, 0x3c4, index);	VGA_WR08(par->riva.PVIO, 0x3c5, val);} static inline unsigned char SEQin(struct riva_par *par,				  unsigned char index){	VGA_WR08(par->riva.PVIO, 0x3c4, index);	return (VGA_RD08(par->riva.PVIO, 0x3c5));} static inline void ATTRout(struct riva_par *par, unsigned char index,			   unsigned char val){	VGA_WR08(par->riva.PCIO, 0x3c0, index);	VGA_WR08(par->riva.PCIO, 0x3c0, val);} static inline unsigned char ATTRin(struct riva_par *par,				   unsigned char index){	VGA_WR08(par->riva.PCIO, 0x3c0, index);	return (VGA_RD08(par->riva.PCIO, 0x3c1));} static inline void MISCout(struct riva_par *par, unsigned char val){	VGA_WR08(par->riva.PVIO, 0x3c2, val);} static inline unsigned char MISCin(struct riva_par *par){	return (VGA_RD08(par->riva.PVIO, 0x3cc));} static inline void reverse_order(u32 *l){	u8 *a = (u8 *)l;	a[0] = bitrev8(a[0]);	a[1] = bitrev8(a[1]);	a[2] = bitrev8(a[2]);	a[3] = bitrev8(a[3]);} /* ------------------------------------------------------------------------- * * * cursor stuff * * ------------------------------------------------------------------------- */ /** * rivafb_load_cursor_image - load cursor image to hardware * @data8: address to monochrome bitmap (1 = foreground color, 0 = background) * @par:  pointer to private data * @w:    width of cursor image in pixels * @h:    height of cursor image in scanlines * @bg:   background color (ARGB1555) - alpha bit determines opacity * @fg:   foreground color (ARGB1555) * * DESCRIPTiON: * Loads cursor image based on a monochrome source and mask bitmap.  The * image bits determines the color of the pixel, 0 for background, 1 for * foreground.  Only the affected region (as determined by @w and @h  * parameters) will be updated. * * CALLED FROM: * rivafb_cursor() */static void rivafb_load_cursor_image(struct riva_par *par, u8 *data8,				     u16 bg, u16 fg, u32 w, u32 h){	int i, j, k = 0;	u32 b, tmp;	u32 *data = (u32 *)data8;	bg = le16_to_cpu(bg);	fg = le16_to_cpu(fg); 	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)

Lines 1–500 of 2191.