/* * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * * Copyright (C) 1995 Jay Estabrook * Copyright (C) 1997 Geert Uytterhoeven * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha * Copyright (C) 2002 Richard Henderson * Copyright (C) 2006, 2007 Maciej W. Rozycki * * 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.
*/
if (var->xres_virtual != var->xres || var->yres_virtual != var->yres) return -EINVAL; if (var->xres * var->yres * (var->bits_per_pixel >> 3) > info->fix.smem_len) return -EINVAL; if (var->nonstd) return -EINVAL; if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ) return -EINVAL; if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) return -EINVAL;
/* Some of the acceleration routines assume the line width is
a multiple of 8 bytes. */ if (var->xres * (par->tga_type == TGA_TYPE_8PLANE ? 1 : 4) % 8) return -EINVAL;
/* Fill the palette. */
BT463_LOAD_ADDR(par, 0x0000);
TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
#ifdef CONFIG_VT for (i = 0; i < 16; i++) { int j = color_table[i];
TGA_WRITE_REG(par, default_red[j], TGA_RAMDAC_REG);
TGA_WRITE_REG(par, default_grn[j], TGA_RAMDAC_REG);
TGA_WRITE_REG(par, default_blu[j], TGA_RAMDAC_REG);
} for (i = 0; i < 512 * 3; i += 4) { #else for (i = 0; i < 528 * 3; i += 4) { #endif
TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG);
TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
}
/* Fill window type table after start of vertical retrace. */ while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) continue;
TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);
mb(); while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) continue;
TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);
base = target * r; while (base < 449) { for (n = base < 7 ? 7 : base; n < base + target && n < 449; n++) {
m = ((n + 3) / 7) - 1;
a = 0;
DIFFCHECK((m + 1) * 7);
m++;
DIFFCHECK((m + 1) * 7);
m = (n / 6) - 1; if ((a = n % 6))
DIFFCHECK(n);
}
r++;
base += target;
}
vr--;
for (r = 0; r < 8; r++)
TGA_WRITE_REG(par, (vm >> r) & 1, TGA_CLOCK_REG); for (r = 0; r < 8 ; r++)
TGA_WRITE_REG(par, (va >> r) & 1, TGA_CLOCK_REG); for (r = 0; r < 7 ; r++)
TGA_WRITE_REG(par, (vr >> r) & 1, TGA_CLOCK_REG);
TGA_WRITE_REG(par, ((vr >> 7) & 1)|2, TGA_CLOCK_REG);
}
/** * tgafb_setcolreg - Optional function. Sets a color register. * @regno: boolean, 0 copy local, 1 get_user() function * @red: frame buffer colormap structure * @green: The green value which can be up to 16 bits wide * @blue: The blue value which can be up to 16 bits wide. * @transp: If supported the alpha value which can be up to 16 bits wide. * @info: frame buffer info structure
*/ staticint
tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
{ struct tga_par *par = (struct tga_par *) info->par; int tga_bus_pci = dev_is_pci(par->dev); int tga_bus_tc = TGA_BUS_TC(par->dev);
if (regno > 255) return 1;
red >>= 8;
green >>= 8;
blue >>= 8;
/* Expand the color values to fill 32-bits. */ /* ??? Would be nice to notice colour changes elsewhere, so
that we can do this only when necessary. */
fgcolor = image->fg_color;
bgcolor = image->bg_color; if (is8bpp) {
fgcolor |= fgcolor << 8;
fgcolor |= fgcolor << 16;
bgcolor |= bgcolor << 8;
bgcolor |= bgcolor << 16;
} else { if (fgcolor < 16)
fgcolor = ((u32 *)info->pseudo_palette)[fgcolor]; if (bgcolor < 16)
bgcolor = ((u32 *)info->pseudo_palette)[bgcolor];
}
__raw_writel(fgcolor, regs_base + TGA_FOREGROUND_REG);
__raw_writel(bgcolor, regs_base + TGA_BACKGROUND_REG);
/* Acquire proper alignment; set up the PIXELMASK register
so that we only write the proper character cell. */
pos = dy * line_length; if (is8bpp) {
pos += dx;
shift = pos & 3;
pos &= -4;
} else {
pos += dx * 4;
shift = (pos & 7) >> 2;
pos &= -8;
}
/* Handle another common case in which accel_putcs generates a large bitmap, which happens to be aligned. Allow the tail to be misaligned. This case is interesting because we've not got to hold partial
bytes across the words being written. */
/* Finally, handle the generic case of misaligned start. Here we split the write into 16-bit spans. This allows us to use only one pixel mask, instead of four as would
be required by writing 24-bit spans. */
/* Crop the image to the screen. */ if (dx > vxres || dy > vyres) return; if (dx + width > vxres)
width = vxres - dx; if (dy + height > vyres)
height = vyres - dy;
fb_base = par->tga_fb_base;
pos = dy * line_length + (dx * 4);
data = image->data;
/* Now copy the image, color_expanding via the palette. */ for (i = 0; i < height; i++) { for (j = 0; j < width; j++) {
color = palette[*data++];
__raw_writel(color, fb_base + pos + j*4);
}
pos += line_length;
}
}
/** * tgafb_imageblit - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. * Copies a image from system memory to the screen. * * @info: frame buffer structure that represents a single frame buffer * @image: structure defining the image.
*/ staticvoid
tgafb_imageblit(struct fb_info *info, conststruct fb_image *image)
{ unsignedint is8bpp = info->var.bits_per_pixel == 8;
/* If a mono image, regardless of FB depth, go do it. */ if (image->depth == 1) {
tgafb_mono_imageblit(info, image); return;
}
/* For copies that aren't pixel expansion, there's little we
can do better than the generic code. */ /* ??? There is a DMA write mode; I wonder if that could be
made to pull the data from the image buffer... */ if (image->depth == info->var.bits_per_pixel) {
cfb_imageblit(info, image); return;
}
/* If 24-plane FB and the image is 8-plane with CLUT, we can do it. */ if (!is8bpp && image->depth == 8) {
tgafb_clut_imageblit(info, image); return;
}
/* Silently return... */
}
/** * tgafb_fillrect - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. * Draws a rectangle on the screen. * * @info: frame buffer structure that represents a single frame buffer * @rect: structure defining the rectagle and operation.
*/ staticvoid
tgafb_fillrect(struct fb_info *info, conststruct fb_fillrect *rect)
{ struct tga_par *par = (struct tga_par *) info->par; int is8bpp = info->var.bits_per_pixel == 8;
u32 dx, dy, width, height, vxres, vyres, color; unsignedlong pos, align, line_length, i, j; void __iomem *regs_base; void __iomem *fb_base;
/* Crop the rectangle to the screen. */ if (dx > vxres || dy > vyres || !width || !height) return; if (dx + width > vxres)
width = vxres - dx; if (dy + height > vyres)
height = vyres - dy;
pos = dy * line_length + dx * (is8bpp ? 1 : 4);
/* ??? We could implement ROP_XOR with opaque fill mode and a RasterOp setting of GXxor, but as far as I can tell, this mode is not actually used in the kernel.
Thus I am ignoring it for now. */ if (rect->rop != ROP_COPY) {
cfb_fillrect(info, rect); return;
}
/* Expand the color value to fill 8 pixels. */
color = rect->color; if (is8bpp) {
color |= color << 8;
color |= color << 16;
__raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG);
__raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG);
} else { if (color < 16)
color = ((u32 *)info->pseudo_palette)[color];
__raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG);
__raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG);
__raw_writel(color, regs_base + TGA_BLOCK_COLOR2_REG);
__raw_writel(color, regs_base + TGA_BLOCK_COLOR3_REG);
__raw_writel(color, regs_base + TGA_BLOCK_COLOR4_REG);
__raw_writel(color, regs_base + TGA_BLOCK_COLOR5_REG);
__raw_writel(color, regs_base + TGA_BLOCK_COLOR6_REG);
__raw_writel(color, regs_base + TGA_BLOCK_COLOR7_REG);
}
/* The DATA register holds the fill mask for block fill mode.
Since we're not stippling, this is all ones. */
__raw_writel(0xffffffff, regs_base + TGA_DATA_REG);
/* We can fill 2k pixels per operation. Notice blocks that fit the width of the screen so that we can take advantage of this
and fill more than one line per write. */ if (width == line_length) {
width *= height;
height = 1;
}
/* The write into the frame buffer must be aligned to 4 bytes, but we are allowed to encode the offset within the word in
the data word written. */
align = (pos & 3) << 16;
pos &= -4;
/* * tgafb_copyarea - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. * Copies on area of the screen to another area. * * @info: frame buffer structure that represents a single frame buffer * @area: structure defining the source and destination.
*/
/* Handle the special case of copying entire lines, e.g. during scrolling. We can avoid a lot of needless computation in this case. In the 8bpp case we need to use the COPY64 registers instead of mask writes into
the frame buffer to achieve maximum performance. */
/* Set up the MODE and PIXELSHIFT registers. */
__raw_writel(TGA_MODE_SBM_8BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
__raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG);
wmb();
/* Set up the MODE and PIXELSHIFT registers. */
__raw_writel(TGA_MODE_SBM_24BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
__raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG);
wmb();
for (i = 0; i < n16; ++i) {
src -= 64;
dst -= 64;
__raw_writel(0xffff, src);
wmb();
__raw_writel(0xffff, dst);
wmb();
}
} else {
src = tga_fb + sy * width * 4;
dst = tga_fb + dy * width * 4;
for (i = 0; i < n16; ++i) {
__raw_writel(0xffff, src);
wmb();
__raw_writel(0xffff, dst);
wmb();
src += 64;
dst += 64;
}
}
/* Reset the MODE register to normal. */
__raw_writel(TGA_MODE_SBM_24BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
}
/* The (almost) general case of backward copy in 8bpp mode. */ staticinlinevoid
copyarea_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
u32 height, u32 width, u32 line_length, conststruct fb_copyarea *area)
{ struct tga_par *par = (struct tga_par *) info->par; unsigned i, yincr; int depos, sepos, backward, last_step, step;
u32 mask_last; unsigned n32; void __iomem *tga_regs; void __iomem *tga_fb;
/* Do acceleration only if we are aligned on 8 pixels */ if ((dx | sx | width) & 7) {
cfb_copyarea(info, area); return;
}
yincr = line_length; if (dy > sy) {
dy += height - 1;
sy += height - 1;
yincr = -yincr;
}
backward = dy == sy && dx > sx && dx < sx + width;
/* Compute the offsets and alignments in the frame buffer.
More than anything else, these control how we do copies. */
depos = dy * line_length + dx;
sepos = sy * line_length + sx; if (backward) {
depos += width;
sepos += width;
}
/* Next copy full words at a time. */
n32 = width / 32;
last_step = width % 32;
/* Finally copy the unaligned head of the span. */
mask_last = (1ul << last_step) - 1;
/* Set up the MODE and PIXELSHIFT registers. */
__raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
__raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG);
wmb();
for (i = 0; i < height; ++i) { unsignedlong j; void __iomem *sfb; void __iomem *dfb;
/* The top left corners must be in the virtual screen. */ if (dx > vxres || sx > vxres || dy > vyres || sy > vyres) return;
/* Clip the destination. */ if (dx + width > vxres)
width = vxres - dx; if (dy + height > vyres)
height = vyres - dy;
/* The source must be completely inside the virtual screen. */ if (sx + width > vxres || sy + height > vyres) return;
bpp = info->var.bits_per_pixel;
/* Detect copies of the entire line. */ if (!(line_length & 63) && width * (bpp >> 3) == line_length) { if (bpp == 8)
copyarea_line_8bpp(info, dy, sy, height, width); else
copyarea_line_32bpp(info, dy, sy, height, width);
}
/* ??? The documentation is unclear to me exactly how the pixelshift register works in 32bpp mode. Since I don't have hardware to test,
give up for now and fall back on the generic routines. */ elseif (bpp == 32)
cfb_copyarea(info, area);
/* * These are needed by fb_set_logo_truepalette(), so we * set them here for 24-plane cards.
*/ if (tga_type != TGA_TYPE_8PLANE) {
info->var.red.length = 8;
info->var.green.length = 8;
info->var.blue.length = 8;
info->var.red.offset = 16;
info->var.green.offset = 8;
info->var.blue.offset = 0;
}
}
staticint tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{ /* We just use this to catch switches out of graphics mode. */
tgafb_set_par(info); /* A bit of overkill for BASE_ADDR reset. */ return 0;
}
/* This should give a reasonable default video mode. */ if (tga_bus_pci) {
mode_option_tga = mode_option_pci;
} if (tga_bus_tc) {
mode_option_tga = mode_option_tc;
modedb_tga = &modedb_tc;
modedbsize_tga = 1;
}
tgafb_init_fix(info);
ret = fb_find_mode(&info->var, info,
mode_option ? mode_option : mode_option_tga,
modedb_tga, modedbsize_tga, NULL,
tga_type == TGA_TYPE_8PLANE ? 8 : 32); if (ret == 0 || ret == 4) {
printk(KERN_ERR "tgafb: Could not find valid video mode\n");
ret = -EINVAL; goto err1;
}
if (fb_alloc_cmap(&info->cmap, 256, 0)) {
printk(KERN_ERR "tgafb: Could not allocate color map\n");
ret = -ENOMEM; goto err1;
}
tgafb_set_par(info);
if (register_framebuffer(info) < 0) {
printk(KERN_ERR "tgafb: Could not register framebuffer\n");
ret = -EINVAL; goto err2;
}
if (tga_bus_pci) {
pr_info("tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
par->tga_chip_rev);
pr_info("tgafb: at PCI bus %d, device %d, function %d\n",
to_pci_dev(dev)->bus->number,
PCI_SLOT(to_pci_dev(dev)->devfn),
PCI_FUNC(to_pci_dev(dev)->devfn));
} if (tga_bus_tc)
pr_info("tgafb: SFB+ detected, rev=0x%02x\n",
par->tga_chip_rev);
fb_info(info, "%s frame buffer device at 0x%lx\n",
info->fix.id, (long)bar0_start);
if (fb_modesetting_disabled("tgafb")) return -ENODEV;
#ifndef MODULE if (fb_get_options("tgafb", &option)) return -ENODEV;
tgafb_setup(option); #endif
status = pci_register_driver(&tgafb_pci_driver); if (!status)
status = tc_register_driver(&tgafb_tc_driver); return status;
}
/* * Modularisation
*/
module_init(tgafb_init);
module_exit(tgafb_exit);
MODULE_DESCRIPTION("Framebuffer driver for TGA/SFB+ chipset");
MODULE_LICENSE("GPL");
Messung V0.5
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet)
¤
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.