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/module.h>
21 #include <linux/string.h>
23 #include <asm/types.h>
25 #if BITS_PER_LONG == 32
26 # define FB_WRITEL fb_writel
27 # define FB_READL fb_readl
29 # define FB_WRITEL fb_writeq
30 # define FB_READL fb_readq
34 * Compose two values, using a bitmask as decision value
35 * This is equivalent to (a & mask) | (b & ~mask)
38 static inline unsigned long
39 comp(unsigned long a
, unsigned long b
, unsigned long mask
)
41 return ((a
^ b
) & mask
) ^ b
;
45 * Create a pattern with the given pixel's color
48 #if BITS_PER_LONG == 64
49 static inline unsigned long
50 pixel_to_pat( u32 bpp
, u32 pixel
)
54 return 0xfffffffffffffffful
*pixel
;
56 return 0x5555555555555555ul
*pixel
;
58 return 0x1111111111111111ul
*pixel
;
60 return 0x0101010101010101ul
*pixel
;
62 return 0x0001001001001001ul
*pixel
;
64 return 0x0001000100010001ul
*pixel
;
66 return 0x0000000001000001ul
*pixel
;
68 return 0x0000000100000001ul
*pixel
;
70 panic("pixel_to_pat(): unsupported pixelformat\n");
74 static inline unsigned long
75 pixel_to_pat( u32 bpp
, u32 pixel
)
79 return 0xfffffffful
*pixel
;
81 return 0x55555555ul
*pixel
;
83 return 0x11111111ul
*pixel
;
85 return 0x01010101ul
*pixel
;
87 return 0x00001001ul
*pixel
;
89 return 0x00010001ul
*pixel
;
91 return 0x00000001ul
*pixel
;
93 return 0x00000001ul
*pixel
;
95 panic("pixel_to_pat(): unsupported pixelformat\n");
101 * Aligned pattern fill using 32/64-bit memory accesses
105 bitfill_aligned(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
, unsigned n
, int bits
)
107 unsigned long first
, last
;
112 first
= FB_SHIFT_HIGH(~0UL, dst_idx
);
113 last
= ~(FB_SHIFT_HIGH(~0UL, (dst_idx
+n
) % bits
));
115 if (dst_idx
+n
<= bits
) {
119 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
121 // Multiple destination words
125 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
133 FB_WRITEL(pat
, 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
++);
144 FB_WRITEL(pat
, dst
++);
148 FB_WRITEL(comp(pat
, FB_READL(dst
), last
), dst
);
154 * Unaligned generic pattern fill using 32/64-bit memory accesses
155 * The pattern must have been expanded to a full 32/64-bit value
156 * Left/right are the appropriate shifts to convert to the pattern to be
157 * used for the next 32/64-bit word
161 bitfill_unaligned(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
,
162 int left
, int right
, unsigned n
, int bits
)
164 unsigned long first
, last
;
169 first
= FB_SHIFT_HIGH(~0UL, dst_idx
);
170 last
= ~(FB_SHIFT_HIGH(~0UL, (dst_idx
+n
) % bits
));
172 if (dst_idx
+n
<= bits
) {
176 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
178 // Multiple destination words
181 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
183 pat
= pat
<< left
| pat
>> right
;
190 FB_WRITEL(pat
, dst
++);
191 pat
= pat
<< left
| pat
>> right
;
192 FB_WRITEL(pat
, dst
++);
193 pat
= pat
<< left
| pat
>> right
;
194 FB_WRITEL(pat
, dst
++);
195 pat
= pat
<< left
| pat
>> right
;
196 FB_WRITEL(pat
, dst
++);
197 pat
= pat
<< left
| pat
>> right
;
201 FB_WRITEL(pat
, dst
++);
202 pat
= pat
<< left
| pat
>> right
;
207 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
212 * Aligned pattern invert using 32/64-bit memory accesses
215 bitfill_aligned_rev(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
, unsigned n
, int bits
)
217 unsigned long val
= pat
, dat
;
218 unsigned long first
, last
;
223 first
= FB_SHIFT_HIGH(~0UL, dst_idx
);
224 last
= ~(FB_SHIFT_HIGH(~0UL, (dst_idx
+n
) % bits
));
226 if (dst_idx
+n
<= bits
) {
231 FB_WRITEL(comp(dat
^ val
, dat
, first
), dst
);
233 // Multiple destination words
237 FB_WRITEL(comp(dat
^ val
, dat
, first
), dst
);
245 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
247 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
249 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
251 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
253 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
255 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
257 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
259 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
264 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
270 FB_WRITEL(comp(dat
^ val
, dat
, last
), dst
);
277 * Unaligned generic pattern invert using 32/64-bit memory accesses
278 * The pattern must have been expanded to a full 32/64-bit value
279 * Left/right are the appropriate shifts to convert to the pattern to be
280 * used for the next 32/64-bit word
284 bitfill_unaligned_rev(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
,
285 int left
, int right
, unsigned n
, int bits
)
287 unsigned long first
, last
, dat
;
292 first
= FB_SHIFT_HIGH(~0UL, dst_idx
);
293 last
= ~(FB_SHIFT_HIGH(~0UL, (dst_idx
+n
) % bits
));
295 if (dst_idx
+n
<= bits
) {
300 FB_WRITEL(comp(dat
^ pat
, dat
, first
), dst
);
302 // Multiple destination words
307 FB_WRITEL(comp(dat
^ pat
, dat
, first
), dst
);
309 pat
= pat
<< left
| pat
>> right
;
316 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
318 pat
= pat
<< left
| pat
>> right
;
319 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
321 pat
= pat
<< left
| pat
>> right
;
322 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
324 pat
= pat
<< left
| pat
>> right
;
325 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
327 pat
= pat
<< left
| pat
>> right
;
331 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
333 pat
= pat
<< left
| pat
>> right
;
339 FB_WRITEL(comp(dat
^ pat
, dat
, last
), dst
);
344 void cfb_fillrect(struct fb_info
*p
, const struct fb_fillrect
*rect
)
346 unsigned long pat
, fg
;
347 unsigned long width
= rect
->width
, height
= rect
->height
;
348 int bits
= BITS_PER_LONG
, bytes
= bits
>> 3;
349 u32 bpp
= p
->var
.bits_per_pixel
;
350 unsigned long __iomem
*dst
;
353 if (p
->state
!= FBINFO_STATE_RUNNING
)
356 if (p
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
357 p
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
)
358 fg
= ((u32
*) (p
->pseudo_palette
))[rect
->color
];
362 pat
= pixel_to_pat( bpp
, fg
);
364 dst
= (unsigned long __iomem
*)((unsigned long)p
->screen_base
& ~(bytes
-1));
365 dst_idx
= ((unsigned long)p
->screen_base
& (bytes
- 1))*8;
366 dst_idx
+= rect
->dy
*p
->fix
.line_length
*8+rect
->dx
*bpp
;
367 /* FIXME For now we support 1-32 bpp only */
369 if (p
->fbops
->fb_sync
)
370 p
->fbops
->fb_sync(p
);
372 void (*fill_op32
)(unsigned long __iomem
*dst
, int dst_idx
,
373 unsigned long pat
, unsigned n
, int bits
) = NULL
;
377 fill_op32
= bitfill_aligned_rev
;
380 fill_op32
= bitfill_aligned
;
383 printk( KERN_ERR
"cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
384 fill_op32
= bitfill_aligned
;
388 dst
+= dst_idx
>> (ffs(bits
) - 1);
389 dst_idx
&= (bits
- 1);
390 fill_op32(dst
, dst_idx
, pat
, width
*bpp
, bits
);
391 dst_idx
+= p
->fix
.line_length
*8;
396 int rot
= (left
-dst_idx
) % bpp
;
397 void (*fill_op
)(unsigned long __iomem
*dst
, int dst_idx
,
398 unsigned long pat
, int left
, int right
,
399 unsigned n
, int bits
) = NULL
;
401 /* rotate pattern to correct start position */
402 pat
= pat
<< rot
| pat
>> (bpp
-rot
);
407 fill_op
= bitfill_unaligned_rev
;
410 fill_op
= bitfill_unaligned
;
413 printk( KERN_ERR
"cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
414 fill_op
= bitfill_unaligned
;
418 dst
+= dst_idx
>> (ffs(bits
) - 1);
419 dst_idx
&= (bits
- 1);
420 fill_op(dst
, dst_idx
, pat
, left
, right
,
422 r
= (p
->fix
.line_length
*8) % bpp
;
423 pat
= pat
<< (bpp
-r
) | pat
>> r
;
424 dst_idx
+= p
->fix
.line_length
*8;
429 EXPORT_SYMBOL(cfb_fillrect
);
431 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
432 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
433 MODULE_LICENSE("GPL");