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
= ~0UL >> dst_idx
;
114 last
= ~(~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
= ~0UL >> dst_idx
;
171 last
= ~(~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
= ~0UL >> dst_idx
;
225 last
= ~(~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
= ~0UL >> dst_idx
;
294 last
= ~(~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");