375 lines · c
1/*2 * Generic fillrect for frame buffers with packed pixels of any depth.3 *4 * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.org)5 *6 * This file is subject to the terms and conditions of the GNU General Public7 * License. See the file COPYING in the main directory of this archive for8 * more details.9 *10 * NOTES:11 *12 * Also need to add code to deal with cards endians that are different than13 * the native cpu endians. I also need to deal with MSB position in the word.14 *15 */16#include <linux/module.h>17#include <linux/string.h>18#include <linux/fb.h>19#include <asm/types.h>20#include "fb_draw.h"21 22#if BITS_PER_LONG == 3223# define FB_WRITEL fb_writel24# define FB_READL fb_readl25#else26# define FB_WRITEL fb_writeq27# define FB_READL fb_readq28#endif29 30 /*31 * Aligned pattern fill using 32/64-bit memory accesses32 */33 34static void35bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,36 unsigned long pat, unsigned n, int bits, u32 bswapmask)37{38 unsigned long first, last;39 40 if (!n)41 return;42 43 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);44 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);45 46 if (dst_idx+n <= bits) {47 // Single word48 if (last)49 first &= last;50 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);51 } else {52 // Multiple destination words53 54 // Leading bits55 if (first!= ~0UL) {56 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);57 dst++;58 n -= bits - dst_idx;59 }60 61 // Main chunk62 n /= bits;63 while (n >= 8) {64 FB_WRITEL(pat, dst++);65 FB_WRITEL(pat, dst++);66 FB_WRITEL(pat, dst++);67 FB_WRITEL(pat, dst++);68 FB_WRITEL(pat, dst++);69 FB_WRITEL(pat, dst++);70 FB_WRITEL(pat, dst++);71 FB_WRITEL(pat, dst++);72 n -= 8;73 }74 while (n--)75 FB_WRITEL(pat, dst++);76 77 // Trailing bits78 if (last)79 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);80 }81}82 83 84 /*85 * Unaligned generic pattern fill using 32/64-bit memory accesses86 * The pattern must have been expanded to a full 32/64-bit value87 * Left/right are the appropriate shifts to convert to the pattern to be88 * used for the next 32/64-bit word89 */90 91static void92bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,93 unsigned long pat, int left, int right, unsigned n, int bits)94{95 unsigned long first, last;96 97 if (!n)98 return;99 100 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);101 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));102 103 if (dst_idx+n <= bits) {104 // Single word105 if (last)106 first &= last;107 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);108 } else {109 // Multiple destination words110 // Leading bits111 if (first) {112 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);113 dst++;114 pat = pat << left | pat >> right;115 n -= bits - dst_idx;116 }117 118 // Main chunk119 n /= bits;120 while (n >= 4) {121 FB_WRITEL(pat, dst++);122 pat = pat << left | pat >> right;123 FB_WRITEL(pat, dst++);124 pat = pat << left | pat >> right;125 FB_WRITEL(pat, dst++);126 pat = pat << left | pat >> right;127 FB_WRITEL(pat, dst++);128 pat = pat << left | pat >> right;129 n -= 4;130 }131 while (n--) {132 FB_WRITEL(pat, dst++);133 pat = pat << left | pat >> right;134 }135 136 // Trailing bits137 if (last)138 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);139 }140}141 142 /*143 * Aligned pattern invert using 32/64-bit memory accesses144 */145static void146bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,147 int dst_idx, unsigned long pat, unsigned n, int bits,148 u32 bswapmask)149{150 unsigned long val = pat, dat;151 unsigned long first, last;152 153 if (!n)154 return;155 156 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);157 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);158 159 if (dst_idx+n <= bits) {160 // Single word161 if (last)162 first &= last;163 dat = FB_READL(dst);164 FB_WRITEL(comp(dat ^ val, dat, first), dst);165 } else {166 // Multiple destination words167 // Leading bits168 if (first!=0UL) {169 dat = FB_READL(dst);170 FB_WRITEL(comp(dat ^ val, dat, first), dst);171 dst++;172 n -= bits - dst_idx;173 }174 175 // Main chunk176 n /= bits;177 while (n >= 8) {178 FB_WRITEL(FB_READL(dst) ^ val, dst);179 dst++;180 FB_WRITEL(FB_READL(dst) ^ val, dst);181 dst++;182 FB_WRITEL(FB_READL(dst) ^ val, dst);183 dst++;184 FB_WRITEL(FB_READL(dst) ^ val, dst);185 dst++;186 FB_WRITEL(FB_READL(dst) ^ val, dst);187 dst++;188 FB_WRITEL(FB_READL(dst) ^ val, dst);189 dst++;190 FB_WRITEL(FB_READL(dst) ^ val, dst);191 dst++;192 FB_WRITEL(FB_READL(dst) ^ val, dst);193 dst++;194 n -= 8;195 }196 while (n--) {197 FB_WRITEL(FB_READL(dst) ^ val, dst);198 dst++;199 }200 // Trailing bits201 if (last) {202 dat = FB_READL(dst);203 FB_WRITEL(comp(dat ^ val, dat, last), dst);204 }205 }206}207 208 209 /*210 * Unaligned generic pattern invert using 32/64-bit memory accesses211 * The pattern must have been expanded to a full 32/64-bit value212 * Left/right are the appropriate shifts to convert to the pattern to be213 * used for the next 32/64-bit word214 */215 216static void217bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,218 int dst_idx, unsigned long pat, int left, int right,219 unsigned n, int bits)220{221 unsigned long first, last, dat;222 223 if (!n)224 return;225 226 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);227 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));228 229 if (dst_idx+n <= bits) {230 // Single word231 if (last)232 first &= last;233 dat = FB_READL(dst);234 FB_WRITEL(comp(dat ^ pat, dat, first), dst);235 } else {236 // Multiple destination words237 238 // Leading bits239 if (first != 0UL) {240 dat = FB_READL(dst);241 FB_WRITEL(comp(dat ^ pat, dat, first), dst);242 dst++;243 pat = pat << left | pat >> right;244 n -= bits - dst_idx;245 }246 247 // Main chunk248 n /= bits;249 while (n >= 4) {250 FB_WRITEL(FB_READL(dst) ^ pat, dst);251 dst++;252 pat = pat << left | pat >> right;253 FB_WRITEL(FB_READL(dst) ^ pat, dst);254 dst++;255 pat = pat << left | pat >> right;256 FB_WRITEL(FB_READL(dst) ^ pat, dst);257 dst++;258 pat = pat << left | pat >> right;259 FB_WRITEL(FB_READL(dst) ^ pat, dst);260 dst++;261 pat = pat << left | pat >> right;262 n -= 4;263 }264 while (n--) {265 FB_WRITEL(FB_READL(dst) ^ pat, dst);266 dst++;267 pat = pat << left | pat >> right;268 }269 270 // Trailing bits271 if (last) {272 dat = FB_READL(dst);273 FB_WRITEL(comp(dat ^ pat, dat, last), dst);274 }275 }276}277 278void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)279{280 unsigned long pat, pat2, fg;281 unsigned long width = rect->width, height = rect->height;282 int bits = BITS_PER_LONG, bytes = bits >> 3;283 u32 bpp = p->var.bits_per_pixel;284 unsigned long __iomem *dst;285 int dst_idx, left;286 287 if (p->state != FBINFO_STATE_RUNNING)288 return;289 290 if (p->flags & FBINFO_VIRTFB)291 fb_warn_once(p, "Framebuffer is not in I/O address space.");292 293 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||294 p->fix.visual == FB_VISUAL_DIRECTCOLOR )295 fg = ((u32 *) (p->pseudo_palette))[rect->color];296 else297 fg = rect->color;298 299 pat = pixel_to_pat(bpp, fg);300 301 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));302 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;303 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;304 /* FIXME For now we support 1-32 bpp only */305 left = bits % bpp;306 if (p->fbops->fb_sync)307 p->fbops->fb_sync(p);308 if (!left) {309 u32 bswapmask = fb_compute_bswapmask(p);310 void (*fill_op32)(struct fb_info *p,311 unsigned long __iomem *dst, int dst_idx,312 unsigned long pat, unsigned n, int bits,313 u32 bswapmask) = NULL;314 315 switch (rect->rop) {316 case ROP_XOR:317 fill_op32 = bitfill_aligned_rev;318 break;319 case ROP_COPY:320 fill_op32 = bitfill_aligned;321 break;322 default:323 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");324 fill_op32 = bitfill_aligned;325 break;326 }327 while (height--) {328 dst += dst_idx >> (ffs(bits) - 1);329 dst_idx &= (bits - 1);330 fill_op32(p, dst, dst_idx, pat, width*bpp, bits,331 bswapmask);332 dst_idx += p->fix.line_length*8;333 }334 } else {335 int right, r;336 void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,337 int dst_idx, unsigned long pat, int left,338 int right, unsigned n, int bits) = NULL;339#ifdef __LITTLE_ENDIAN340 right = left;341 left = bpp - right;342#else343 right = bpp - left;344#endif345 switch (rect->rop) {346 case ROP_XOR:347 fill_op = bitfill_unaligned_rev;348 break;349 case ROP_COPY:350 fill_op = bitfill_unaligned;351 break;352 default:353 printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");354 fill_op = bitfill_unaligned;355 break;356 }357 while (height--) {358 dst += dst_idx / bits;359 dst_idx &= (bits - 1);360 r = dst_idx % bpp;361 /* rotate pattern to the correct start position */362 pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));363 fill_op(p, dst, dst_idx, pat2, left, right,364 width*bpp, bits);365 dst_idx += p->fix.line_length*8;366 }367 }368}369 370EXPORT_SYMBOL(cfb_fillrect);371 372MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");373MODULE_DESCRIPTION("Generic software accelerated fill rectangle");374MODULE_LICENSE("GPL");375