bnx2: Use netif_carrier_off() to prevent timeout.
[safe/jmp/linux-2.6] / drivers / video / tridentfb.c
index 854e2e5..c6c7756 100644 (file)
@@ -2,7 +2,7 @@
  * Frame buffer driver for Trident TGUI, Blade and Image series
  *
  * Copyright 2001, 2002 - Jani Monoses   <jani@iv.ro>
- *
+ * Copyright 2009 Krzysztof Helt <krzysztof.h1@wp.pl>
  *
  * CREDITS:(in order of appearance)
  *     skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
@@ -19,6 +19,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/slab.h>
 
 #include <linux/delay.h>
 #include <video/vga.h>
@@ -35,11 +36,12 @@ struct tridentfb_par {
                (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32);
        void (*copy_rect)
                (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32);
+       void (*image_blit)
+               (struct tridentfb_par *par, const char*,
+                u32, u32, u32, u32, u32, u32);
        unsigned char eng_oper; /* engine operation... */
 };
 
-static struct fb_ops tridentfb_ops;
-
 static struct fb_fix_screeninfo tridentfb_fix = {
        .id = "Trident",
        .type = FB_TYPE_PACKED_PIXELS,
@@ -212,6 +214,21 @@ static void blade_fill_rect(struct tridentfb_par *par,
        writemmr(par, DST2, point(x + w - 1, y + h - 1));
 }
 
+static void blade_image_blit(struct tridentfb_par *par, const char *data,
+                            u32 x, u32 y, u32 w, u32 h, u32 c, u32 b)
+{
+       unsigned size = ((w + 31) >> 5) * h;
+
+       writemmr(par, COLOR, c);
+       writemmr(par, BGCOLOR, b);
+       writemmr(par, CMD, 0xa0000000 | 3 << 19);
+
+       writemmr(par, DST1, point(x, y));
+       writemmr(par, DST2, point(x + w - 1, y + h - 1));
+
+       memcpy(par->io_virt + 0x10000, data, 4 * size);
+}
+
 static void blade_copy_rect(struct tridentfb_par *par,
                            u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
 {
@@ -474,7 +491,6 @@ static void tgui_copy_rect(struct tridentfb_par *par,
 /*
  * Accel functions called by the upper layers
  */
-#ifdef CONFIG_FB_TRIDENT_ACCEL
 static void tridentfb_fillrect(struct fb_info *info,
                               const struct fb_fillrect *fr)
 {
@@ -497,6 +513,36 @@ static void tridentfb_fillrect(struct fb_info *info,
                       fr->height, col, fr->rop);
 }
 
+static void tridentfb_imageblit(struct fb_info *info,
+                               const struct fb_image *img)
+{
+       struct tridentfb_par *par = info->par;
+       int col, bgcol;
+
+       if ((info->flags & FBINFO_HWACCEL_DISABLED) || img->depth != 1) {
+               cfb_imageblit(info, img);
+               return;
+       }
+       if (info->var.bits_per_pixel == 8) {
+               col = img->fg_color;
+               col |= col << 8;
+               col |= col << 16;
+               bgcol = img->bg_color;
+               bgcol |= bgcol << 8;
+               bgcol |= bgcol << 16;
+       } else {
+               col = ((u32 *)(info->pseudo_palette))[img->fg_color];
+               bgcol = ((u32 *)(info->pseudo_palette))[img->bg_color];
+       }
+
+       par->wait_engine(par);
+       if (par->image_blit)
+               par->image_blit(par, img->data, img->dx, img->dy,
+                               img->width, img->height, col, bgcol);
+       else
+               cfb_imageblit(info, img);
+}
+
 static void tridentfb_copyarea(struct fb_info *info,
                               const struct fb_copyarea *ca)
 {
@@ -519,10 +565,6 @@ static int tridentfb_sync(struct fb_info *info)
                par->wait_engine(par);
        return 0;
 }
-#else
-#define tridentfb_fillrect cfb_fillrect
-#define tridentfb_copyarea cfb_copyarea
-#endif /* CONFIG_FB_TRIDENT_ACCEL */
 
 /*
  * Hardware access functions
@@ -1285,10 +1327,8 @@ static struct fb_ops tridentfb_ops = {
        .fb_set_par = tridentfb_set_par,
        .fb_fillrect = tridentfb_fillrect,
        .fb_copyarea = tridentfb_copyarea,
-       .fb_imageblit = cfb_imageblit,
-#ifdef CONFIG_FB_TRIDENT_ACCEL
+       .fb_imageblit = tridentfb_imageblit,
        .fb_sync = tridentfb_sync,
-#endif
 };
 
 static int __devinit trident_pci_probe(struct pci_dev *dev,
@@ -1312,14 +1352,6 @@ static int __devinit trident_pci_probe(struct pci_dev *dev,
 
        chip_id = id->device;
 
-       if (chip_id == CYBERBLADEi1)
-               output("*** Please do use cyblafb, Cyberblade/i1 support "
-                      "will soon be removed from tridentfb!\n");
-
-#ifndef CONFIG_FB_TRIDENT_ACCEL
-       noaccel = 1;
-#endif
-
        /* If PCI id is 0x9660 then further detect chip type */
 
        if (chip_id == TGUI9660) {
@@ -1369,6 +1401,7 @@ static int __devinit trident_pci_probe(struct pci_dev *dev,
                default_par->wait_engine = blade_wait_engine;
                default_par->fill_rect = blade_fill_rect;
                default_par->copy_rect = blade_copy_rect;
+               default_par->image_blit = blade_image_blit;
                tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADE3D;
        } else if (chip3D) {                    /* 3DImage family left */
                default_par->init_accel = image_init_accel;
@@ -1446,6 +1479,32 @@ static int __devinit trident_pci_probe(struct pci_dev *dev,
        } else
                info->flags |= FBINFO_HWACCEL_DISABLED;
 
+       if (is_blade(chip_id) && chip_id != BLADE3D)
+               info->flags |= FBINFO_READS_FAST;
+
+       info->pixmap.addr = kmalloc(4096, GFP_KERNEL);
+       if (!info->pixmap.addr) {
+               err = -ENOMEM;
+               goto out_unmap2;
+       }
+
+       info->pixmap.size = 4096;
+       info->pixmap.buf_align = 4;
+       info->pixmap.scan_align = 1;
+       info->pixmap.access_align = 32;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+       if (default_par->image_blit) {
+               info->flags |= FBINFO_HWACCEL_IMAGEBLIT;
+               info->pixmap.scan_align = 4;
+       }
+
+       if (noaccel) {
+               printk(KERN_DEBUG "disabling acceleration\n");
+               info->flags |= FBINFO_HWACCEL_DISABLED;
+               info->pixmap.scan_align = 1;
+       }
+
        if (!fb_find_mode(&info->var, info,
                          mode_option, NULL, 0, NULL, bpp)) {
                err = -EINVAL;
@@ -1471,6 +1530,7 @@ static int __devinit trident_pci_probe(struct pci_dev *dev,
        return 0;
 
 out_unmap2:
+       kfree(info->pixmap.addr);
        if (info->screen_base)
                iounmap(info->screen_base);
        release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
@@ -1494,6 +1554,8 @@ static void __devexit trident_pci_remove(struct pci_dev *dev)
        release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
        release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
        pci_set_drvdata(dev, NULL);
+       kfree(info->pixmap.addr);
+       fb_dealloc_cmap(&info->cmap);
        framebuffer_release(info);
 }
 
@@ -1594,4 +1656,5 @@ module_exit(tridentfb_exit);
 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("cyblafb");