📄 fbdev.c
字号:
/* * 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_MTRR#include <asm/mtrr.h>#endif#ifdef CONFIG_PPC_OF#include <asm/prom.h>#include <asm/pci-bridge.h>#endif#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 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 __devinitdata = -1; /* Autodetect later */static int forceCRTC __devinitdata = -1;static int noaccel __devinitdata = 0;#ifdef CONFIG_MTRRstatic int nomtrr __devinitdata = 0;#endif#ifdef CONFIG_PMAC_BACKLIGHTstatic int backlight __devinitdata = 1;#elsestatic int backlight __devinitdata = 0;#endifstatic char *mode_option __devinitdata = NULL;static int strictmode = 0;static struct fb_fix_screeninfo __devinitdata rivafb_fix = { .type = FB_TYPE_PACKED_PIXELS, .xpanstep = 1, .ypanstep = 1,};static struct fb_var_screeninfo __devinitdata 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 int riva_bl_get_brightness(struct backlight_device *bd){ return bd->props.brightness;}static struct backlight_ops riva_bl_ops = { .get_brightness = riva_bl_get_brightness, .update_status = riva_bl_update_status,};static void riva_bl_init(struct riva_par *par){ 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); bd = backlight_device_register(name, info->dev, par, &riva_bl_ops); 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.max_brightness = FB_BACKLIGHT_LEVELS - 1; 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 * @data: 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) 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 writel(tmp, &par->riva.CURSOR[k++]); } k += (MAX_CURS - w)/2; }}/* ------------------------------------------------------------------------- * * * general utility functions * * ------------------------------------------------------------------------- *//** * riva_wclut - set CLUT entry * @chip: pointer to RIVA_HW_INST object * @regnum: register number * @red: red component * @green: green component * @blue: blue component * * DESCRIPTION: * Sets color register @regnum. * * CALLED FROM: * rivafb_setcolreg() */static void riva_wclut(RIVA_HW_INST *chip, unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue){ VGA_WR08(chip->PDIO, 0x3c8, regnum); VGA_WR08(chip->PDIO, 0x3c9, red); VGA_WR08(chip->PDIO, 0x3c9, green); VGA_WR08(chip->PDIO, 0x3c9, blue);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -