/* * 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
*/
/* 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)
/* * 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)
staticint 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;
/** * 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()
*/ staticvoid 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);
/** * riva_save_state - saves current chip state * @par: pointer to riva_par object containing info for current riva board * @regs: pointer to riva_regs object * * DESCRIPTION: * Saves current chip state to @regs. * * CALLED FROM: * rivafb_probe()
*/ /* from GGI */ staticvoid riva_save_state(struct riva_par *par, struct riva_regs *regs)
{ int i;
/** * rivafb_do_maximize - * @info: pointer to fb_info object containing info for current riva board * @var: standard kernel fb changeable data * @nom: nom * @den: den * * DESCRIPTION: * . * * RETURNS: * -EINVAL on failure, 0 on success * * * CALLED FROM: * rivafb_check_var()
*/ staticint rivafb_do_maximize(struct fb_info *info, struct fb_var_screeninfo *var, int nom, int den)
{ staticstruct { int xres, yres;
} modes[] = {
{1600, 1280},
{1280, 1024},
{1024, 768},
{800, 600},
{640, 480},
{-1, -1}
}; int i;
NVTRACE_ENTER(); /* use highest possible virtual resolution */ if (var->xres_virtual == -1 && var->yres_virtual == -1) {
printk(KERN_WARNING PFX "using maximum available virtual resolution\n"); for (i = 0; modes[i].xres != -1; i++) { if (modes[i].xres * nom / den * modes[i].yres <
info->fix.smem_len) break;
} if (modes[i].xres == -1) {
printk(KERN_ERR PFX "could not find a virtual resolution that fits into video memory!!\n");
NVTRACE("EXIT - EINVAL error\n"); return -EINVAL;
}
var->xres_virtual = modes[i].xres;
var->yres_virtual = modes[i].yres;
printk(KERN_INFO PFX "virtual resolution set to maximum of %dx%d\n",
var->xres_virtual, var->yres_virtual);
} elseif (var->xres_virtual == -1) {
var->xres_virtual = (info->fix.smem_len * den /
(nom * var->yres_virtual)) & ~15;
printk(KERN_WARNING PFX "setting virtual X resolution to %d\n", var->xres_virtual);
} elseif (var->yres_virtual == -1) {
var->xres_virtual = (var->xres_virtual + 15) & ~15;
var->yres_virtual = info->fix.smem_len * den /
(nom * var->xres_virtual);
printk(KERN_WARNING PFX "setting virtual Y resolution to %d\n", var->yres_virtual);
} else {
var->xres_virtual = (var->xres_virtual + 15) & ~15; if (var->xres_virtual * nom / den * var->yres_virtual > info->fix.smem_len) {
printk(KERN_ERR PFX "mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
var->xres, var->yres, var->bits_per_pixel);
NVTRACE("EXIT - EINVAL error\n"); return -EINVAL;
}
}
if (var->xres_virtual * nom / den >= 8192) {
printk(KERN_WARNING PFX "virtual X resolution (%d) is too high, lowering to %d\n",
var->xres_virtual, 8192 * den / nom - 16);
var->xres_virtual = 8192 * den / nom - 16;
}
if (var->xres_virtual < var->xres) {
printk(KERN_ERR PFX "virtual X resolution (%d) is smaller than real\n", var->xres_virtual); return -EINVAL;
}
if (var->yres_virtual < var->yres) {
printk(KERN_ERR PFX "virtual Y resolution (%d) is smaller than real\n", var->yres_virtual); return -EINVAL;
} if (var->yres_virtual > 0x7fff/nom)
var->yres_virtual = 0x7fff/nom; if (var->xres_virtual > 0x7fff/nom)
var->xres_virtual = 0x7fff/nom;
NVTRACE_LEAVE(); return 0;
}
staticvoid
riva_set_pattern(struct riva_par *par, int clr0, int clr1, int pat0, int pat1)
{
RIVA_FIFO_FREE(par->riva, Patt, 4);
NV_WR32(&par->riva.Patt->Color0, 0, clr0);
NV_WR32(&par->riva.Patt->Color1, 0, clr1);
NV_WR32(par->riva.Patt->Monochrome, 0, pat0);
NV_WR32(par->riva.Patt->Monochrome, 4, pat1);
}
/** * riva_get_cmap_len - query current color map length * @var: standard kernel fb changeable data * * DESCRIPTION: * Get current color map length. * * RETURNS: * Length of color map * * CALLED FROM: * rivafb_setcolreg()
*/ staticint riva_get_cmap_len(conststruct fb_var_screeninfo *var)
{ int rc = 256; /* reasonable default */
switch (var->green.length) { case 8:
rc = 256; /* 256 entries (2^8), 8 bpp and RGB8888 */ break; case 5:
rc = 32; /* 32 entries (2^5), 16 bpp, RGB555 */ break; case 6:
rc = 64; /* 64 entries (2^6), 16 bpp, RGB565 */ break; default: /* should not occur */ break;
} return rc;
}
if (!strictmode) { if (!info->monspecs.vfmax || !info->monspecs.hfmax ||
!info->monspecs.dclkmax || !fb_validate_mode(var, info))
mode_valid = 1;
}
/* calculate modeline if supported by monitor */ if (!mode_valid && info->monspecs.gtf) { if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
mode_valid = 1;
}
if (!mode_valid) {
mode = fb_find_best_mode(var, &info->modelist); if (mode) {
riva_update_var(var, mode);
mode_valid = 1;
}
}
if (!mode_valid && info->monspecs.modedb_len) return -EINVAL;
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres; if (var->yres_virtual <= var->yres)
var->yres_virtual = -1; if (rivafb_do_maximize(info, var, nom, den) < 0) return -EINVAL;
/* truncate xoffset and yoffset to maximum if too high */ if (var->xoffset > var->xres_virtual - var->xres)
var->xoffset = var->xres_virtual - var->xres - 1;
/** * rivafb_pan_display * @var: standard kernel fb changeable data * @info: pointer to fb_info object containing info for current riva board * * DESCRIPTION: * Pan (or wrap, depending on the `vmode' field) the display using the * `xoffset' and `yoffset' fields of the `var' structure. * If the values don't fit, return -EINVAL. * * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/ staticint rivafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{ struct riva_par *par = info->par; unsignedint base;
switch (blank) { case FB_BLANK_UNBLANK: case FB_BLANK_NORMAL: break; case FB_BLANK_VSYNC_SUSPEND:
vesa |= 0x80; break; case FB_BLANK_HSYNC_SUSPEND:
vesa |= 0x40; break; case FB_BLANK_POWERDOWN:
vesa |= 0xc0; break;
}
SEQout(par, 0x01, tmp);
CRTCout(par, 0x1a, vesa);
NVTRACE_LEAVE();
return 0;
}
/** * rivafb_setcolreg * @regno: register index * @red: red component * @green: green component * @blue: blue component * @transp: transparency * @info: pointer to fb_info object containing info for current riva board * * DESCRIPTION: * Set a single color register. The values supplied have a 16 bit * magnitude. * * RETURNS: * Return != 0 for invalid regno. * * CALLED FROM: * fbcmap.c:fb_set_cmap()
*/ staticint rivafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
{ struct riva_par *par = info->par;
RIVA_HW_INST *chip = &par->riva; int i;
if (regno >= riva_get_cmap_len(&info->var)) return -EINVAL;
if (info->var.grayscale) { /* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue =
(red * 77 + green * 151 + blue * 28) >> 8;
}
if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
((u32 *) info->pseudo_palette)[regno] =
(regno << info->var.red.offset) |
(regno << info->var.green.offset) |
(regno << info->var.blue.offset); /* * The Riva128 2D engine requires color information in * TrueColor format even if framebuffer is in DirectColor
*/ if (par->riva.Architecture == NV_ARCH_03) { switch (info->var.bits_per_pixel) { case 16:
par->palette[regno] = ((red & 0xf800) >> 1) |
((green & 0xf800) >> 6) |
((blue & 0xf800) >> 11); break; case 32:
par->palette[regno] = ((red & 0xff00) << 8) |
((green & 0xff00)) |
((blue & 0xff00) >> 8); break;
}
}
}
switch (info->var.bits_per_pixel) { case 8: /* "transparent" stuff is completely ignored. */
riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8); break; case 16: if (info->var.green.length == 5) { for (i = 0; i < 8; i++) {
riva_wclut(chip, regno*8+i, red >> 8,
green >> 8, blue >> 8);
}
} else {
u8 r, g, b;
if (regno < 32) { for (i = 0; i < 8; i++) {
riva_wclut(chip, regno*8+i,
red >> 8, green >> 8,
blue >> 8);
}
}
riva_rclut(chip, regno*4, &r, &g, &b); for (i = 0; i < 4; i++)
riva_wclut(chip, regno*4+i, r,
green >> 8, b);
} break; case 32:
riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8); break; default: /* do nothing */ break;
} return 0;
}
/** * rivafb_fillrect - hardware accelerated color fill function * @info: pointer to fb_info structure * @rect: pointer to fb_fillrect structure * * DESCRIPTION: * This function fills up a region of framebuffer memory with a solid * color with a choice of two different ROP's, copy or invert. * * CALLED FROM: * framebuffer hook
*/ staticvoid rivafb_fillrect(struct fb_info *info, conststruct fb_fillrect *rect)
{ struct riva_par *par = info->par;
u_int color, rop = 0;
if ((info->flags & FBINFO_HWACCEL_DISABLED)) {
cfb_fillrect(info, rect); return;
}
if (info->var.bits_per_pixel == 8)
color = rect->color; else { if (par->riva.Architecture != NV_ARCH_03)
color = ((u32 *)info->pseudo_palette)[rect->color]; else
color = par->palette[rect->color];
}
switch (rect->rop) { case ROP_XOR:
rop = 0x66; break; case ROP_COPY: default:
rop = 0xCC; break;
}
/** * rivafb_copyarea - hardware accelerated blit function * @info: pointer to fb_info structure * @region: pointer to fb_copyarea structure * * DESCRIPTION: * This copies an area of pixels from one location to another * * CALLED FROM: * framebuffer hook
*/ staticvoid rivafb_copyarea(struct fb_info *info, conststruct fb_copyarea *region)
{ struct riva_par *par = info->par;
if ((info->flags & FBINFO_HWACCEL_DISABLED)) {
cfb_copyarea(info, region); return;
}
/** * rivafb_imageblit: hardware accelerated color expand function * @info: pointer to fb_info structure * @image: pointer to fb_image structure * * DESCRIPTION: * If the source is a monochrome bitmap, the function fills up a a region * of framebuffer memory with pixels whose color is determined by the bit * setting of the bitmap, 1 - foreground, 0 - background. * * If the source is not a monochrome bitmap, color expansion is not done. * In this case, it is channeled to a software function. * * CALLED FROM: * framebuffer hook
*/ staticvoid rivafb_imageblit(struct fb_info *info, conststruct fb_image *image)
{ struct riva_par *par = info->par;
u32 fgx = 0, bgx = 0, width, tmp;
u8 *cdat = (u8 *) image->data; volatile u32 __iomem *d; int i, size;
/** * rivafb_cursor - hardware cursor function * @info: pointer to info structure * @cursor: pointer to fbcursor structure * * DESCRIPTION: * A cursor function that supports displaying a cursor image via hardware. * Within the kernel, copy and invert rops are supported. If exported * to user space, only the copy rop will be supported. * * CALLED FROM * framebuffer hook
*/ staticint rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{ struct riva_par *par = info->par;
u8 data[MAX_CURS * MAX_CURS/8]; int i, set = cursor->set;
u16 fg, bg;
if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) return -ENXIO;
par->riva.ShowHideCursor(&par->riva, 0);
if (par->cursor_reset) {
set = FB_CUR_SETALL;
par->cursor_reset = 0;
}
if (src) { switch (cursor->rop) { case ROP_XOR: for (i = 0; i < s_pitch * cursor->image.height; i++)
src[i] = dat[i] ^ msk[i]; break; case ROP_COPY: default: for (i = 0; i < s_pitch * cursor->image.height; i++)
src[i] = dat[i] & msk[i]; break;
}
/* Accel seems to not work properly on NV30 yet...*/ if ((par->riva.Architecture == NV_ARCH_30) || noaccel) {
printk(KERN_DEBUG PFX "disabling acceleration\n");
info->flags |= FBINFO_HWACCEL_DISABLED;
}
NVTRACE_ENTER();
par->riva.LockUnlock(&par->riva, 0);
riva_create_i2c_busses(par); for (i = 0; i < 3; i++) { if (!par->chan[i].par) continue;
riva_probe_i2c_connector(par, i, &par->EDID); if (par->EDID && !fb_parse_edid(par->EDID, &var)) {
printk(PFX "Found EDID Block from BUS %i\n", i); break;
}
}
default_par->ctrl_base = ioremap(rivafb_fix.mmio_start,
rivafb_fix.mmio_len); if (!default_par->ctrl_base) {
printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
ret = -EIO; goto err_release_region;
}
switch (default_par->riva.Architecture) { case NV_ARCH_03: /* Riva128's PRAMIN is in the "framebuffer" space * Since these cards were never made with more than 8 megabytes * we can safely allocate this separately.
*/
default_par->riva.PRAMIN = ioremap(rivafb_fix.smem_start + 0x00C00000, 0x00008000); if (!default_par->riva.PRAMIN) {
printk(KERN_ERR PFX "cannot ioremap PRAMIN region\n");
ret = -EIO; goto err_iounmap_ctrl_base;
} break; case NV_ARCH_04: case NV_ARCH_10: case NV_ARCH_20: case NV_ARCH_30:
default_par->riva.PCRTC0 =
(u32 __iomem *)(default_par->ctrl_base + 0x00600000);
default_par->riva.PRAMIN =
(u32 __iomem *)(default_par->ctrl_base + 0x00710000); break;
}
riva_common_setup(default_par);
module_param(noaccel, bool, 0);
MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
module_param(flatpanel, int, 0);
MODULE_PARM_DESC(flatpanel, "Enables experimental flat panel support for some chipsets. (0 or 1=enabled) (default=0)");
module_param(forceCRTC, int, 0);
MODULE_PARM_DESC(forceCRTC, "Forces usage of a particular CRTC in case autodetection fails. (0 or 1) (default=autodetect)");
module_param(nomtrr, bool, 0);
MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)");
module_param(strictmode, bool, 0);
MODULE_PARM_DESC(strictmode, "Only use video modes from EDID");
MODULE_AUTHOR("Ani Joshi, maintainer");
MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2, and the GeForce series");
MODULE_LICENSE("GPL");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.