Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  Generic fillrect for frame buffers with packed pixels of any depth.
0003  *
0004  *      Copyright (C)  2000 James Simmons (jsimmons@linux-fbdev.org)
0005  *
0006  *  This file is subject to the terms and conditions of the GNU General Public
0007  *  License.  See the file COPYING in the main directory of this archive for
0008  *  more details.
0009  *
0010  * NOTES:
0011  *
0012  *  Also need to add code to deal with cards endians that are different than
0013  *  the native cpu endians. I also need to deal with MSB position in the word.
0014  *
0015  */
0016 #include <linux/module.h>
0017 #include <linux/string.h>
0018 #include <linux/fb.h>
0019 #include <asm/types.h>
0020 #include "fb_draw.h"
0021 
0022 #if BITS_PER_LONG == 32
0023 #  define FB_WRITEL fb_writel
0024 #  define FB_READL  fb_readl
0025 #else
0026 #  define FB_WRITEL fb_writeq
0027 #  define FB_READL  fb_readq
0028 #endif
0029 
0030     /*
0031      *  Aligned pattern fill using 32/64-bit memory accesses
0032      */
0033 
0034 static void
0035 bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
0036         unsigned long pat, unsigned n, int bits, u32 bswapmask)
0037 {
0038     unsigned long first, last;
0039 
0040     if (!n)
0041         return;
0042 
0043     first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
0044     last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
0045 
0046     if (dst_idx+n <= bits) {
0047         // Single word
0048         if (last)
0049             first &= last;
0050         FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
0051     } else {
0052         // Multiple destination words
0053 
0054         // Leading bits
0055         if (first!= ~0UL) {
0056             FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
0057             dst++;
0058             n -= bits - dst_idx;
0059         }
0060 
0061         // Main chunk
0062         n /= bits;
0063         while (n >= 8) {
0064             FB_WRITEL(pat, dst++);
0065             FB_WRITEL(pat, dst++);
0066             FB_WRITEL(pat, dst++);
0067             FB_WRITEL(pat, dst++);
0068             FB_WRITEL(pat, dst++);
0069             FB_WRITEL(pat, dst++);
0070             FB_WRITEL(pat, dst++);
0071             FB_WRITEL(pat, dst++);
0072             n -= 8;
0073         }
0074         while (n--)
0075             FB_WRITEL(pat, dst++);
0076 
0077         // Trailing bits
0078         if (last)
0079             FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
0080     }
0081 }
0082 
0083 
0084     /*
0085      *  Unaligned generic pattern fill using 32/64-bit memory accesses
0086      *  The pattern must have been expanded to a full 32/64-bit value
0087      *  Left/right are the appropriate shifts to convert to the pattern to be
0088      *  used for the next 32/64-bit word
0089      */
0090 
0091 static void
0092 bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
0093           unsigned long pat, int left, int right, unsigned n, int bits)
0094 {
0095     unsigned long first, last;
0096 
0097     if (!n)
0098         return;
0099 
0100     first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
0101     last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
0102 
0103     if (dst_idx+n <= bits) {
0104         // Single word
0105         if (last)
0106             first &= last;
0107         FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
0108     } else {
0109         // Multiple destination words
0110         // Leading bits
0111         if (first) {
0112             FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
0113             dst++;
0114             pat = pat << left | pat >> right;
0115             n -= bits - dst_idx;
0116         }
0117 
0118         // Main chunk
0119         n /= bits;
0120         while (n >= 4) {
0121             FB_WRITEL(pat, dst++);
0122             pat = pat << left | pat >> right;
0123             FB_WRITEL(pat, dst++);
0124             pat = pat << left | pat >> right;
0125             FB_WRITEL(pat, dst++);
0126             pat = pat << left | pat >> right;
0127             FB_WRITEL(pat, dst++);
0128             pat = pat << left | pat >> right;
0129             n -= 4;
0130         }
0131         while (n--) {
0132             FB_WRITEL(pat, dst++);
0133             pat = pat << left | pat >> right;
0134         }
0135 
0136         // Trailing bits
0137         if (last)
0138             FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
0139     }
0140 }
0141 
0142     /*
0143      *  Aligned pattern invert using 32/64-bit memory accesses
0144      */
0145 static void
0146 bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
0147             int dst_idx, unsigned long pat, unsigned n, int bits,
0148             u32 bswapmask)
0149 {
0150     unsigned long val = pat, dat;
0151     unsigned long first, last;
0152 
0153     if (!n)
0154         return;
0155 
0156     first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
0157     last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
0158 
0159     if (dst_idx+n <= bits) {
0160         // Single word
0161         if (last)
0162             first &= last;
0163         dat = FB_READL(dst);
0164         FB_WRITEL(comp(dat ^ val, dat, first), dst);
0165     } else {
0166         // Multiple destination words
0167         // Leading bits
0168         if (first!=0UL) {
0169             dat = FB_READL(dst);
0170             FB_WRITEL(comp(dat ^ val, dat, first), dst);
0171             dst++;
0172             n -= bits - dst_idx;
0173         }
0174 
0175         // Main chunk
0176         n /= bits;
0177         while (n >= 8) {
0178             FB_WRITEL(FB_READL(dst) ^ val, dst);
0179             dst++;
0180             FB_WRITEL(FB_READL(dst) ^ val, dst);
0181             dst++;
0182             FB_WRITEL(FB_READL(dst) ^ val, dst);
0183             dst++;
0184             FB_WRITEL(FB_READL(dst) ^ val, dst);
0185             dst++;
0186             FB_WRITEL(FB_READL(dst) ^ val, dst);
0187             dst++;
0188             FB_WRITEL(FB_READL(dst) ^ val, dst);
0189             dst++;
0190             FB_WRITEL(FB_READL(dst) ^ val, dst);
0191             dst++;
0192             FB_WRITEL(FB_READL(dst) ^ val, dst);
0193             dst++;
0194             n -= 8;
0195         }
0196         while (n--) {
0197             FB_WRITEL(FB_READL(dst) ^ val, dst);
0198             dst++;
0199         }
0200         // Trailing bits
0201         if (last) {
0202             dat = FB_READL(dst);
0203             FB_WRITEL(comp(dat ^ val, dat, last), dst);
0204         }
0205     }
0206 }
0207 
0208 
0209     /*
0210      *  Unaligned generic pattern invert using 32/64-bit memory accesses
0211      *  The pattern must have been expanded to a full 32/64-bit value
0212      *  Left/right are the appropriate shifts to convert to the pattern to be
0213      *  used for the next 32/64-bit word
0214      */
0215 
0216 static void
0217 bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
0218               int dst_idx, unsigned long pat, int left, int right,
0219               unsigned n, int bits)
0220 {
0221     unsigned long first, last, dat;
0222 
0223     if (!n)
0224         return;
0225 
0226     first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
0227     last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
0228 
0229     if (dst_idx+n <= bits) {
0230         // Single word
0231         if (last)
0232             first &= last;
0233         dat = FB_READL(dst);
0234         FB_WRITEL(comp(dat ^ pat, dat, first), dst);
0235     } else {
0236         // Multiple destination words
0237 
0238         // Leading bits
0239         if (first != 0UL) {
0240             dat = FB_READL(dst);
0241             FB_WRITEL(comp(dat ^ pat, dat, first), dst);
0242             dst++;
0243             pat = pat << left | pat >> right;
0244             n -= bits - dst_idx;
0245         }
0246 
0247         // Main chunk
0248         n /= bits;
0249         while (n >= 4) {
0250             FB_WRITEL(FB_READL(dst) ^ pat, dst);
0251             dst++;
0252             pat = pat << left | pat >> right;
0253             FB_WRITEL(FB_READL(dst) ^ pat, dst);
0254             dst++;
0255             pat = pat << left | pat >> right;
0256             FB_WRITEL(FB_READL(dst) ^ pat, dst);
0257             dst++;
0258             pat = pat << left | pat >> right;
0259             FB_WRITEL(FB_READL(dst) ^ pat, dst);
0260             dst++;
0261             pat = pat << left | pat >> right;
0262             n -= 4;
0263         }
0264         while (n--) {
0265             FB_WRITEL(FB_READL(dst) ^ pat, dst);
0266             dst++;
0267             pat = pat << left | pat >> right;
0268         }
0269 
0270         // Trailing bits
0271         if (last) {
0272             dat = FB_READL(dst);
0273             FB_WRITEL(comp(dat ^ pat, dat, last), dst);
0274         }
0275     }
0276 }
0277 
0278 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
0279 {
0280     unsigned long pat, pat2, fg;
0281     unsigned long width = rect->width, height = rect->height;
0282     int bits = BITS_PER_LONG, bytes = bits >> 3;
0283     u32 bpp = p->var.bits_per_pixel;
0284     unsigned long __iomem *dst;
0285     int dst_idx, left;
0286 
0287     if (p->state != FBINFO_STATE_RUNNING)
0288         return;
0289 
0290     if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
0291         p->fix.visual == FB_VISUAL_DIRECTCOLOR )
0292         fg = ((u32 *) (p->pseudo_palette))[rect->color];
0293     else
0294         fg = rect->color;
0295 
0296     pat = pixel_to_pat(bpp, fg);
0297 
0298     dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
0299     dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
0300     dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
0301     /* FIXME For now we support 1-32 bpp only */
0302     left = bits % bpp;
0303     if (p->fbops->fb_sync)
0304         p->fbops->fb_sync(p);
0305     if (!left) {
0306         u32 bswapmask = fb_compute_bswapmask(p);
0307         void (*fill_op32)(struct fb_info *p,
0308                   unsigned long __iomem *dst, int dst_idx,
0309                           unsigned long pat, unsigned n, int bits,
0310                   u32 bswapmask) = NULL;
0311 
0312         switch (rect->rop) {
0313         case ROP_XOR:
0314             fill_op32 = bitfill_aligned_rev;
0315             break;
0316         case ROP_COPY:
0317             fill_op32 = bitfill_aligned;
0318             break;
0319         default:
0320             printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
0321             fill_op32 = bitfill_aligned;
0322             break;
0323         }
0324         while (height--) {
0325             dst += dst_idx >> (ffs(bits) - 1);
0326             dst_idx &= (bits - 1);
0327             fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
0328                   bswapmask);
0329             dst_idx += p->fix.line_length*8;
0330         }
0331     } else {
0332         int right, r;
0333         void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
0334                 int dst_idx, unsigned long pat, int left,
0335                 int right, unsigned n, int bits) = NULL;
0336 #ifdef __LITTLE_ENDIAN
0337         right = left;
0338         left = bpp - right;
0339 #else
0340         right = bpp - left;
0341 #endif
0342         switch (rect->rop) {
0343         case ROP_XOR:
0344             fill_op = bitfill_unaligned_rev;
0345             break;
0346         case ROP_COPY:
0347             fill_op = bitfill_unaligned;
0348             break;
0349         default:
0350             printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
0351             fill_op = bitfill_unaligned;
0352             break;
0353         }
0354         while (height--) {
0355             dst += dst_idx / bits;
0356             dst_idx &= (bits - 1);
0357             r = dst_idx % bpp;
0358             /* rotate pattern to the correct start position */
0359             pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
0360             fill_op(p, dst, dst_idx, pat2, left, right,
0361                 width*bpp, bits);
0362             dst_idx += p->fix.line_length*8;
0363         }
0364     }
0365 }
0366 
0367 EXPORT_SYMBOL(cfb_fillrect);
0368 
0369 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
0370 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
0371 MODULE_LICENSE("GPL");