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);
/* 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 generatesalargebitmap,whichhappenstobealigned. Allowthetailtobemisaligned.Thiscaseis interestingbecausewe'venotgottoholdpartial
bytes across the words being written. */
/* Finally, handle the generic case of misaligned start. Herewesplitthewriteinto16-bitspans.Thisallows ustouseonlyonepixelmask,insteadoffouraswould
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;
}
}
/* 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;
}
/* 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 andaRasterOpsettingofGXxor,butasfarasIcan tell,thismodeisnotactuallyusedinthekernel.
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 thewidthofthescreensothatwecantakeadvantageofthis
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, butweareallowedtoencodetheoffsetwithinthewordin
the data word written. */
align = (pos & 3) << 16;
pos &= -4;
/* Handle the special case of copying entire lines, e.g. during scrolling. Wecanavoidalotofneedlesscomputationinthiscase.Inthe8bpp caseweneedtousetheCOPY64registersinsteadofmaskwritesinto
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 registerworksin32bppmode.SinceIdon'thavehardwaretotest,
give up for now and fall back on the generic routines. */ elseif (bpp == 32)
cfb_copyarea(info, area);
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. */ return0;
}
/* 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 in Prozent
¤ Dauer der Verarbeitung: 0.25 Sekunden
(vorverarbeitet am 2026-10-11)
¤
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.