2 * Generic fillrect for frame buffers with packed pixels of any depth.
4 * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.org)
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
12 * The code for depths like 24 that don't have integer number of pixels per
13 * long is broken and needs to be fixed. For now I turned these types of
16 * Also need to add code to deal with cards endians that are different than
17 * the native cpu endians. I also need to deal with MSB position in the word.
20 #include <linux/config.h>
21 #include <linux/module.h>
22 #include <linux/string.h>
24 #include <asm/types.h>
26 #if BITS_PER_LONG == 32
27 # define FB_WRITEL fb_writel
28 # define FB_READL fb_readl
30 # define FB_WRITEL fb_writeq
31 # define FB_READL fb_readq
35 * Compose two values, using a bitmask as decision value
36 * This is equivalent to (a & mask) | (b & ~mask)
39 static inline unsigned long
40 comp(unsigned long a, unsigned long b, unsigned long mask)
42 return ((a ^ b) & mask) ^ b;
46 * Create a pattern with the given pixel's color
49 #if BITS_PER_LONG == 64
50 static inline unsigned long
51 pixel_to_pat( u32 bpp, u32 pixel)
55 return 0xfffffffffffffffful*pixel;
57 return 0x5555555555555555ul*pixel;
59 return 0x1111111111111111ul*pixel;
61 return 0x0101010101010101ul*pixel;
63 return 0x0001001001001001ul*pixel;
65 return 0x0001000100010001ul*pixel;
67 return 0x0000000001000001ul*pixel;
69 return 0x0000000100000001ul*pixel;
71 panic("pixel_to_pat(): unsupported pixelformat\n");
75 static inline unsigned long
76 pixel_to_pat( u32 bpp, u32 pixel)
80 return 0xfffffffful*pixel;
82 return 0x55555555ul*pixel;
84 return 0x11111111ul*pixel;
86 return 0x01010101ul*pixel;
88 return 0x00001001ul*pixel;
90 return 0x00010001ul*pixel;
92 return 0x00000001ul*pixel;
94 return 0x00000001ul*pixel;
96 panic("pixel_to_pat(): unsupported pixelformat\n");
102 * Aligned pattern fill using 32/64-bit memory accesses
106 bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
108 unsigned long first, last;
113 first = FB_SHIFT_HIGH(~0UL, dst_idx);
114 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
116 if (dst_idx+n <= bits) {
120 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
122 // Multiple destination words
126 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
134 FB_WRITEL(pat, dst++);
135 FB_WRITEL(pat, dst++);
136 FB_WRITEL(pat, dst++);
137 FB_WRITEL(pat, dst++);
138 FB_WRITEL(pat, dst++);
139 FB_WRITEL(pat, dst++);
140 FB_WRITEL(pat, dst++);
141 FB_WRITEL(pat, dst++);
145 FB_WRITEL(pat, dst++);
149 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
155 * Unaligned generic pattern fill using 32/64-bit memory accesses
156 * The pattern must have been expanded to a full 32/64-bit value
157 * Left/right are the appropriate shifts to convert to the pattern to be
158 * used for the next 32/64-bit word
162 bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
163 int left, int right, unsigned n, int bits)
165 unsigned long first, last;
170 first = FB_SHIFT_HIGH(~0UL, dst_idx);
171 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
173 if (dst_idx+n <= bits) {
177 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
179 // Multiple destination words
182 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
184 pat = pat << left | pat >> right;
191 FB_WRITEL(pat, dst++);
192 pat = pat << left | pat >> right;
193 FB_WRITEL(pat, dst++);
194 pat = pat << left | pat >> right;
195 FB_WRITEL(pat, dst++);
196 pat = pat << left | pat >> right;
197 FB_WRITEL(pat, dst++);
198 pat = pat << left | pat >> right;
202 FB_WRITEL(pat, dst++);
203 pat = pat << left | pat >> right;
208 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
213 * Aligned pattern invert using 32/64-bit memory accesses
216 bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
218 unsigned long val = pat, dat;
219 unsigned long first, last;
224 first = FB_SHIFT_HIGH(~0UL, dst_idx);
225 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
227 if (dst_idx+n <= bits) {
232 FB_WRITEL(comp(dat ^ val, dat, first), dst);
234 // Multiple destination words
238 FB_WRITEL(comp(dat ^ val, dat, first), dst);
246 FB_WRITEL(FB_READL(dst) ^ val, dst);
248 FB_WRITEL(FB_READL(dst) ^ val, dst);
250 FB_WRITEL(FB_READL(dst) ^ val, dst);
252 FB_WRITEL(FB_READL(dst) ^ val, dst);
254 FB_WRITEL(FB_READL(dst) ^ val, dst);
256 FB_WRITEL(FB_READL(dst) ^ val, dst);
258 FB_WRITEL(FB_READL(dst) ^ val, dst);
260 FB_WRITEL(FB_READL(dst) ^ val, dst);
265 FB_WRITEL(FB_READL(dst) ^ val, dst);
271 FB_WRITEL(comp(dat ^ val, dat, last), dst);
278 * Unaligned generic pattern invert using 32/64-bit memory accesses
279 * The pattern must have been expanded to a full 32/64-bit value
280 * Left/right are the appropriate shifts to convert to the pattern to be
281 * used for the next 32/64-bit word
285 bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
286 int left, int right, unsigned n, int bits)
288 unsigned long first, last, dat;
293 first = FB_SHIFT_HIGH(~0UL, dst_idx);
294 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
296 if (dst_idx+n <= bits) {
301 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
303 // Multiple destination words
308 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
310 pat = pat << left | pat >> right;
317 FB_WRITEL(FB_READL(dst) ^ pat, dst);
319 pat = pat << left | pat >> right;
320 FB_WRITEL(FB_READL(dst) ^ pat, dst);
322 pat = pat << left | pat >> right;
323 FB_WRITEL(FB_READL(dst) ^ pat, dst);
325 pat = pat << left | pat >> right;
326 FB_WRITEL(FB_READL(dst) ^ pat, dst);
328 pat = pat << left | pat >> right;
332 FB_WRITEL(FB_READL(dst) ^ pat, dst);
334 pat = pat << left | pat >> right;
340 FB_WRITEL(comp(dat ^ pat, dat, last), dst);
345 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
347 unsigned long pat, fg;
348 unsigned long width = rect->width, height = rect->height;
349 int bits = BITS_PER_LONG, bytes = bits >> 3;
350 u32 bpp = p->var.bits_per_pixel;
351 unsigned long __iomem *dst;
354 if (p->state != FBINFO_STATE_RUNNING)
357 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
358 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
359 fg = ((u32 *) (p->pseudo_palette))[rect->color];
363 pat = pixel_to_pat( bpp, fg);
365 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
366 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
367 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
368 /* FIXME For now we support 1-32 bpp only */
370 if (p->fbops->fb_sync)
371 p->fbops->fb_sync(p);
373 void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
374 unsigned long pat, unsigned n, int bits) = NULL;
378 fill_op32 = bitfill_aligned_rev;
381 fill_op32 = bitfill_aligned;
384 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
385 fill_op32 = bitfill_aligned;
389 dst += dst_idx >> (ffs(bits) - 1);
390 dst_idx &= (bits - 1);
391 fill_op32(dst, dst_idx, pat, width*bpp, bits);
392 dst_idx += p->fix.line_length*8;
397 int rot = (left-dst_idx) % bpp;
398 void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
399 unsigned long pat, int left, int right,
400 unsigned n, int bits) = NULL;
402 /* rotate pattern to correct start position */
403 pat = pat << rot | pat >> (bpp-rot);
408 fill_op = bitfill_unaligned_rev;
411 fill_op = bitfill_unaligned;
414 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
415 fill_op = bitfill_unaligned;
419 dst += dst_idx >> (ffs(bits) - 1);
420 dst_idx &= (bits - 1);
421 fill_op(dst, dst_idx, pat, left, right,
423 r = (p->fix.line_length*8) % bpp;
424 pat = pat << (bpp-r) | pat >> r;
425 dst_idx += p->fix.line_length*8;
430 EXPORT_SYMBOL(cfb_fillrect);
432 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
433 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
434 MODULE_LICENSE("GPL");