/* * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device * * Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>. * * Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl> * based on pm2fb.c * * Based on code written by: * Sven Luther, <luther@dpt-info.u-strasbg.fr> * Alan Hourihane, <alanh@fairlite.demon.co.uk> * Russell King, <rmk@arm.linux.org.uk> * Based on linux/drivers/video/skeletonfb.c: * Copyright (C) 1997 Geert Uytterhoeven * Based on linux/driver/video/pm2fb.c: * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) * * 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. *
*/
/* * This structure defines the hardware state of the graphics card. Normally * you place this in a header file in linux/include/video. This file usually * also includes register information. That allows other driver subsystems * and userland applications the ability to use the same header file to * avoid duplicate work and easy porting of software.
*/ struct pm3_par { unsignedchar __iomem *v_regs;/* virtual address of p_regs */
u32 video; /* video flags before blanking */
u32 base; /* screen base in 128 bits unit */
u32 palette[16]; int wc_cookie;
};
/* * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo * if we don't use modedb. If we do use modedb see pm3fb_init how to use it * to get a fb_var_screeninfo. Otherwise define a default var as well.
*/ staticstruct fb_fix_screeninfo pm3fb_fix = {
.id = "Permedia3",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
.xpanstep = 1,
.ypanstep = 1,
.ywrapstep = 0,
.accel = FB_ACCEL_3DLABS_PERMEDIA3,
};
staticinlineint pm3fb_shift_bpp(unsigned bpp, int v)
{ switch (bpp) { case 8: return (v >> 4); case 16: return (v >> 3); case 32: return (v >> 2);
}
DPRINTK("Unsupported depth %u\n", bpp); return 0;
}
if (!hwcursor) return -EINVAL; /* just to force soft_cursor() call */
/* Too large of a cursor or wrong bpp :-( */ if (cursor->image.width > 64 ||
cursor->image.height > 64 ||
cursor->image.depth > 1) return -EINVAL;
mode = PM3RD_CursorMode_TYPE_X; if (cursor->enable)
mode |= PM3RD_CursorMode_CURSOR_ENABLE;
PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, mode);
/* * If the cursor is not be changed this means either we want the * current cursor state (if enable is set) or we want to query what * we can do with the cursor (if enable is not set)
*/ if (!cursor->set) return 0;
if (cursor->set & FB_CUR_SETPOS) { int x = cursor->image.dx - info->var.xoffset; int y = cursor->image.dy - info->var.yoffset;
/* the X11 driver says one should use these color registers */
PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39),
cmap.red[fg_idx] >> 8 );
PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40),
cmap.green[fg_idx] >> 8 );
PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41),
cmap.blue[fg_idx] >> 8 );
/* * Oxygen VX1 - it appears that setting PM3VideoControl and * then PM3RD_SyncControl to the same SYNC settings undoes * any net change - they seem to xor together. Only set the * sync options in PM3RD_SyncControl. --rmk
*/
{ unsignedint video = par->video;
if (regno >= 256) /* no. of hw registers */ return -EINVAL;
/* grayscale works only partially under directcolor */ /* grayscale = 0.30*R + 0.59*G + 0.11*B */ if (info->var.grayscale)
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
/* Directcolor: * var->{color}.offset contains start of bitfield * var->{color}.length contains length of bitfield * {hardwarespecific} contains width of DAC * pseudo_palette[X] is programmed to (X << red.offset) | * (X << green.offset) | * (X << blue.offset) * RAMDAC[X] is programmed to (red, green, blue) * color depth = SUM(var->{color}.length) * * Pseudocolor: * var->{color}.offset is 0 * var->{color}.length contains width of DAC or the number * of unique colors available (color depth) * pseudo_palette is not used * RAMDAC[X] is programmed to (red, green, blue) * color depth = var->{color}.length
*/
/* * This is the point where the color is converted to something that * is acceptable by the hardware.
*/ #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
transp = CNVT_TOHW(transp, info->var.transp.length); #undef CNVT_TOHW
/* * Oxygen VX1 - it appears that setting PM3VideoControl and * then PM3RD_SyncControl to the same SYNC settings undoes * any net change - they seem to xor together. Only set the * sync options in PM3RD_SyncControl. --rmk
*/
video &= ~(PM3VideoControl_HSYNC_MASK |
PM3VideoControl_VSYNC_MASK);
video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
PM3VideoControl_VSYNC_ACTIVE_HIGH;
switch (blank_mode) { case FB_BLANK_UNBLANK:
video |= PM3VideoControl_ENABLE; break; case FB_BLANK_NORMAL:
video &= ~PM3VideoControl_ENABLE; break; case FB_BLANK_HSYNC_SUSPEND:
video &= ~(PM3VideoControl_HSYNC_MASK |
PM3VideoControl_BLANK_ACTIVE_LOW); break; case FB_BLANK_VSYNC_SUSPEND:
video &= ~(PM3VideoControl_VSYNC_MASK |
PM3VideoControl_BLANK_ACTIVE_LOW); break; case FB_BLANK_POWERDOWN:
video &= ~(PM3VideoControl_HSYNC_MASK |
PM3VideoControl_VSYNC_MASK |
PM3VideoControl_BLANK_ACTIVE_LOW); break; default:
DPRINTK("Unsupported blanking %d\n", blank_mode); return 1;
}
/* mmio register are already mapped when this function is called */ /* the pm3fb_fix.smem_start is also set */ staticunsignedlong pm3fb_size_memory(struct pm3_par *par)
{ unsignedlong memsize = 0; unsignedlong tempBypass, i, temp1, temp2; unsignedchar __iomem *screen_mem;
pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ /* Linear frame buffer - request region and map it. */ if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, "pm3fb smem")) {
printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); return 0;
}
screen_mem =
ioremap(pm3fb_fix.smem_start, pm3fb_fix.smem_len); if (!screen_mem) {
printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); return 0;
}
/* TODO: card-specific stuff, *before* accessing *any* FB memory */ /* For Appian Jeronimo 2000 board second head */
/* pm3 split up memory, replicates, and do a lot of * nasty stuff IMHO ;-)
*/ for (i = 0; i < 32; i++) {
fb_writel(i * 0x00345678,
(screen_mem + (i * 1048576)));
mb();
temp1 = fb_readl((screen_mem + (i * 1048576)));
/* Let's check for wrapover, write will fail at 16MB boundary */ if (temp1 == (i * 0x00345678))
memsize = i; else break;
}
if (memsize + 1 == i) { for (i = 0; i < 32; i++) { /* Clear first 32MB ; 0 is 0, no need to byteswap */
writel(0x0000000, (screen_mem + (i * 1048576)));
}
wmb();
for (i = 32; i < 64; i++) {
fb_writel(i * 0x00345678,
(screen_mem + (i * 1048576)));
mb();
temp1 =
fb_readl((screen_mem + (i * 1048576)));
temp2 =
fb_readl((screen_mem + ((i - 32) * 1048576))); /* different value, different RAM... */ if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
memsize = i; else break;
}
}
DPRINTK("Second detect pass got %ld MB\n", memsize + 1);
staticint pm3fb_probe(struct pci_dev *dev, conststruct pci_device_id *ent)
{ struct fb_info *info; struct pm3_par *par; struct device *device = &dev->dev; /* for pci drivers */ int err; int retval = -ENXIO;
err = aperture_remove_conflicting_pci_devices(dev, "pm3fb"); if (err) return err;
err = pci_enable_device(dev); if (err) {
printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err); return err;
} /* * Dynamically allocate info and par
*/
info = framebuffer_alloc(sizeof(struct pm3_par), device);
if (!info) return -ENOMEM;
par = info->par;
/* * Here we set the screen_base to the virtual memory address * for the framebuffer.
*/
pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
pm3fb_fix.mmio_len = PM3_REGS_SIZE; #ifdefined(__BIG_ENDIAN)
pm3fb_fix.mmio_start += PM3_REGS_SIZE;
DPRINTK("Adjusting register base for big-endian.\n"); #endif
/* Registers - request region and map it. */ if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, "pm3fb regbase")) {
printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n"); goto err_exit_neither;
}
par->v_regs =
ioremap(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); if (!par->v_regs) {
printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n",
pm3fb_fix.id);
release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); goto err_exit_neither;
}
/* Linear frame buffer - request region and map it. */
pm3fb_fix.smem_start = pci_resource_start(dev, 1);
pm3fb_fix.smem_len = pm3fb_size_memory(par); if (!pm3fb_fix.smem_len) {
printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); goto err_exit_mmio;
} if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, "pm3fb smem")) {
printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); goto err_exit_mmio;
}
info->screen_base = ioremap_wc(pm3fb_fix.smem_start,
pm3fb_fix.smem_len); if (!info->screen_base) {
printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); goto err_exit_mmio;
}
info->screen_size = pm3fb_fix.smem_len;
if (!nomtrr)
par->wc_cookie = arch_phys_wc_add(pm3fb_fix.smem_start,
pm3fb_fix.smem_len);
info->fbops = &pm3fb_ops;
/* * This should give a reasonable default video mode. The following is * done when we can set a video mode.
*/ if (!mode_option)
mode_option = "640x480@60";
/* * Only necessary if your driver takes special options, * otherwise we fall back on the generic fb_setup().
*/ staticint __init pm3fb_setup(char *options)
{ char *this_opt;
/* Parse user specified options (`video=pm3fb:') */ if (!options || !*options) return 0;
¤ 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.0.19Bemerkung:
(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.