radeonfb: fix problem with color expansion & alignment
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 1 Dec 2008 21:13:58 +0000 (13:13 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 2 Dec 2008 03:55:24 +0000 (19:55 -0800)
The engine on some radeon variants locks up if color expansion is called
for non aligned source data.  This patch enables a feature of the core
fbdev to request aligned input pixmaps and uses the HW clipping engine to
clip the output to the requested size

Addresses http://bugzilla.kernel.org/show_bug.cgi?id=11875

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Tested-by: James Cloos <cloos@jhcloos.com>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/video/aty/radeon_accel.c
drivers/video/aty/radeon_base.c

index 8718f7349d6b8961eb1ed90d3ce8ea13b75a5853..a547e5d4c8bfee248e1722a285237aee93b49cf1 100644 (file)
@@ -174,12 +174,12 @@ static void radeonfb_prim_imageblit(struct radeonfb_info *rinfo,
                                    const struct fb_image *image,
                                    u32 fg, u32 bg)
 {
-       unsigned int src_bytes, dwords;
+       unsigned int dwords;
        u32 *bits;
 
        radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache,
                          rinfo->dp_gui_mc_base |
-                         GMC_BRUSH_NONE |
+                         GMC_BRUSH_NONE | GMC_DST_CLIP_LEAVE |
                          GMC_SRC_DATATYPE_MONO_FG_BG |
                          ROP3_S |
                          GMC_BYTE_ORDER_MSB_TO_LSB |
@@ -189,9 +189,6 @@ static void radeonfb_prim_imageblit(struct radeonfb_info *rinfo,
        radeonfb_set_creg(rinfo, DP_SRC_FRGD_CLR, &rinfo->dp_src_fg_cache, fg);
        radeonfb_set_creg(rinfo, DP_SRC_BKGD_CLR, &rinfo->dp_src_bg_cache, bg);
 
-       radeon_fifo_wait(rinfo, 1);
-       OUTREG(DST_Y_X, (image->dy << 16) | image->dx);
-
        /* Ensure the dst cache is flushed and the engine idle before
         * issuing the operation.
         *
@@ -205,13 +202,19 @@ static void radeonfb_prim_imageblit(struct radeonfb_info *rinfo,
 
        /* X here pads width to a multiple of 32 and uses the clipper to
         * adjust the result. Is that really necessary ? Things seem to
-        * work ok for me without that and the doco doesn't seem to imply
+        * work ok for me without that and the doco doesn't seem to imply]
         * there is such a restriction.
         */
-       OUTREG(DST_WIDTH_HEIGHT, (image->width << 16) | image->height);
+       radeon_fifo_wait(rinfo, 4);
+       OUTREG(SC_TOP_LEFT, (image->dy << 16) | image->dx);
+       OUTREG(SC_BOTTOM_RIGHT, ((image->dy + image->height) << 16) |
+              (image->dx + image->width));
+       OUTREG(DST_Y_X, (image->dy << 16) | image->dx);
+
+       OUTREG(DST_HEIGHT_WIDTH, (image->height << 16) | ((image->width + 31) & ~31));
 
-       src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
-       dwords = (src_bytes + 3) / 4;
+       dwords = (image->width + 31) >> 5;
+       dwords *= image->height;
        bits = (u32*)(image->data);
 
        while(dwords >= 8) {
index 9a5821c65ebf22fd2d492ee3972002bb2f5cc651..b3ffe8205d2b738b7b567fa80820d2f71c662c25 100644 (file)
@@ -1875,6 +1875,7 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
        info->fbops = &radeonfb_ops;
        info->screen_base = rinfo->fb_base;
        info->screen_size = rinfo->mapped_vram;
+
        /* Fill fix common fields */
        strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
         info->fix.smem_start = rinfo->fb_base_phys;
@@ -1889,8 +1890,25 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
         info->fix.mmio_len = RADEON_REGSIZE;
        info->fix.accel = FB_ACCEL_ATI_RADEON;
 
+       /* Allocate colormap */
        fb_alloc_cmap(&info->cmap, 256, 0);
 
+       /* Setup pixmap used for acceleration */
+#define PIXMAP_SIZE    (2048 * 4)
+
+       info->pixmap.addr = kmalloc(PIXMAP_SIZE, GFP_KERNEL);
+       if (!info->pixmap.addr) {
+               printk(KERN_ERR "radeonfb: Failed to allocate pixmap !\n");
+               noaccel = 1;
+               goto bail;
+       }
+       info->pixmap.size = PIXMAP_SIZE;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+       info->pixmap.scan_align = 4;
+       info->pixmap.buf_align = 4;
+       info->pixmap.access_align = 32;
+
+bail:
        if (noaccel)
                info->flags |= FBINFO_HWACCEL_DISABLED;