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
29 #define BYTES_PER_LONG 4
30 #define SHIFT_PER_LONG 5
32 #define FB_WRITEL fb_writeq
33 #define FB_READL fb_readq
34 #define BYTES_PER_LONG 8
35 #define SHIFT_PER_LONG 6
38 #define EXP1(x) 0xffffffffU*x
39 #define EXP2(x) 0x55555555U*x
40 #define EXP4(x) 0x11111111U*0x ## x
44 static const u32 bpp1tab
[2] = {
48 static const u32 bpp2tab
[4] = {
49 EXP2(0), EXP2(1), EXP2(2), EXP2(3)
52 static const u32 bpp4tab
[16] = {
53 EXP4(0), EXP4(1), EXP4(2), EXP4(3), EXP4(4), EXP4(5), EXP4(6), EXP4(7),
54 EXP4(8), EXP4(9), EXP4(a
), EXP4(b
), EXP4(c
), EXP4(d
), EXP4(e
), EXP4(f
)
58 * Compose two values, using a bitmask as decision value
59 * This is equivalent to (a & mask) | (b & ~mask)
62 static inline unsigned long comp(unsigned long a
, unsigned long b
,
65 return ((a
^ b
) & mask
) ^ b
;
68 static inline u32
pixel_to_pat32(const struct fb_info
*p
, pixel_t pixel
)
72 switch (p
->var
.bits_per_pixel
) {
98 * Expand a pixel value to a generic 32/64-bit pattern and rotate it to
99 * the correct start position
102 static inline unsigned long pixel_to_pat(const struct fb_info
*p
,
103 pixel_t pixel
, int left
)
105 unsigned long pat
= pixel
;
106 u32 bpp
= p
->var
.bits_per_pixel
;
109 /* expand pixel value */
110 for (i
= bpp
; i
< BITS_PER_LONG
; i
*= 2)
113 /* rotate pattern to correct start position */
114 pat
= pat
<< left
| pat
>> (bpp
-left
);
119 * Unaligned 32-bit pattern fill using 32/64-bit memory accesses
122 void bitfill32(unsigned long __iomem
*dst
, int dst_idx
, u32 pat
, u32 n
)
124 unsigned long val
= pat
;
125 unsigned long first
, last
;
130 #if BITS_PER_LONG == 64
134 first
= ~0UL >> dst_idx
;
135 last
= ~(~0UL >> ((dst_idx
+n
) % BITS_PER_LONG
));
137 if (dst_idx
+n
<= BITS_PER_LONG
) {
141 FB_WRITEL(comp(val
, FB_READL(dst
), first
), dst
);
143 // Multiple destination words
146 FB_WRITEL(comp(val
, FB_READL(dst
), first
), dst
);
148 n
-= BITS_PER_LONG
-dst_idx
;
154 FB_WRITEL(val
, dst
++);
155 FB_WRITEL(val
, dst
++);
156 FB_WRITEL(val
, dst
++);
157 FB_WRITEL(val
, dst
++);
158 FB_WRITEL(val
, dst
++);
159 FB_WRITEL(val
, dst
++);
160 FB_WRITEL(val
, dst
++);
161 FB_WRITEL(val
, dst
++);
165 FB_WRITEL(val
, dst
++);
169 FB_WRITEL(comp(val
, FB_READL(dst
), first
), dst
);
175 * Unaligned generic pattern fill using 32/64-bit memory accesses
176 * The pattern must have been expanded to a full 32/64-bit value
177 * Left/right are the appropriate shifts to convert to the pattern to be
178 * used for the next 32/64-bit word
181 void bitfill(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
, int left
,
184 unsigned long first
, last
;
189 first
= ~0UL >> dst_idx
;
190 last
= ~(~0UL >> ((dst_idx
+n
) % BITS_PER_LONG
));
192 if (dst_idx
+n
<= BITS_PER_LONG
) {
196 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
198 // Multiple destination words
201 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
203 pat
= pat
<< left
| pat
>> right
;
204 n
-= BITS_PER_LONG
-dst_idx
;
210 FB_WRITEL(pat
, dst
++);
211 pat
= pat
<< left
| pat
>> right
;
212 FB_WRITEL(pat
, dst
++);
213 pat
= pat
<< left
| pat
>> right
;
214 FB_WRITEL(pat
, dst
++);
215 pat
= pat
<< left
| pat
>> right
;
216 FB_WRITEL(pat
, dst
++);
217 pat
= pat
<< left
| pat
>> right
;
221 FB_WRITEL(pat
, dst
++);
222 pat
= pat
<< left
| pat
>> right
;
227 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
231 void bitfill32_rev(unsigned long __iomem
*dst
, int dst_idx
, u32 pat
, u32 n
)
233 unsigned long val
= pat
, dat
;
234 unsigned long first
, last
;
239 #if BITS_PER_LONG == 64
243 first
= ~0UL >> dst_idx
;
244 last
= ~(~0UL >> ((dst_idx
+n
) % BITS_PER_LONG
));
246 if (dst_idx
+n
<= BITS_PER_LONG
) {
251 FB_WRITEL(comp(dat
^ val
, dat
, first
), dst
);
253 // Multiple destination words
257 FB_WRITEL(comp(dat
^ val
, dat
, first
), dst
);
259 n
-= BITS_PER_LONG
-dst_idx
;
265 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
267 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
269 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
271 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
273 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
275 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
277 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
279 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
284 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
290 FB_WRITEL(comp(dat
^ val
, dat
, first
), dst
);
297 * Unaligned generic pattern fill using 32/64-bit memory accesses
298 * The pattern must have been expanded to a full 32/64-bit value
299 * Left/right are the appropriate shifts to convert to the pattern to be
300 * used for the next 32/64-bit word
303 void bitfill_rev(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
, int left
,
306 unsigned long first
, last
, dat
;
311 first
= ~0UL >> dst_idx
;
312 last
= ~(~0UL >> ((dst_idx
+n
) % BITS_PER_LONG
));
314 if (dst_idx
+n
<= BITS_PER_LONG
) {
319 FB_WRITEL(comp(dat
^ pat
, dat
, first
), dst
);
321 // Multiple destination words
325 FB_WRITEL(comp(dat
^ pat
, dat
, first
), dst
);
327 pat
= pat
<< left
| pat
>> right
;
328 n
-= BITS_PER_LONG
-dst_idx
;
334 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
336 pat
= pat
<< left
| pat
>> right
;
337 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
339 pat
= pat
<< left
| pat
>> right
;
340 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
342 pat
= pat
<< left
| pat
>> right
;
343 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
345 pat
= pat
<< left
| pat
>> right
;
349 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
351 pat
= pat
<< left
| pat
>> right
;
357 FB_WRITEL(comp(dat
^ pat
, dat
, first
), dst
);
362 void cfb_fillrect(struct fb_info
*p
, const struct fb_fillrect
*rect
)
364 u32 bpp
= p
->var
.bits_per_pixel
;
365 unsigned long x2
, y2
, vxres
, vyres
;
366 unsigned long height
, width
, fg
;
367 unsigned long __iomem
*dst
;
370 if (p
->state
!= FBINFO_STATE_RUNNING
)
373 /* We want rotation but lack hardware to do it for us. */
374 if (!p
->fbops
->fb_rotate
&& p
->var
.rotate
) {
377 vxres
= p
->var
.xres_virtual
;
378 vyres
= p
->var
.yres_virtual
;
380 if (!rect
->width
|| !rect
->height
||
381 rect
->dx
> vxres
|| rect
->dy
> vyres
)
384 /* We could use hardware clipping but on many cards you get around
385 * hardware clipping by writing to framebuffer directly. */
387 x2
= rect
->dx
+ rect
->width
;
388 y2
= rect
->dy
+ rect
->height
;
389 x2
= x2
< vxres
? x2
: vxres
;
390 y2
= y2
< vyres
? y2
: vyres
;
391 width
= x2
- rect
->dx
;
392 height
= y2
- rect
->dy
;
394 if (p
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
395 p
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
)
396 fg
= ((u32
*) (p
->pseudo_palette
))[rect
->color
];
400 dst
= (unsigned long __iomem
*)((unsigned long)p
->screen_base
&
401 ~(BYTES_PER_LONG
-1));
402 dst_idx
= ((unsigned long)p
->screen_base
& (BYTES_PER_LONG
-1))*8;
403 dst_idx
+= rect
->dy
*p
->fix
.line_length
*8+rect
->dx
*bpp
;
404 /* FIXME For now we support 1-32 bpp only */
405 left
= BITS_PER_LONG
% bpp
;
406 if (p
->fbops
->fb_sync
)
407 p
->fbops
->fb_sync(p
);
409 u32 pat
= pixel_to_pat32(p
, fg
);
410 void (*fill_op32
)(unsigned long __iomem
*dst
, int dst_idx
, u32 pat
,
415 fill_op32
= bitfill32_rev
;
419 fill_op32
= bitfill32
;
423 dst
+= dst_idx
>> SHIFT_PER_LONG
;
424 dst_idx
&= (BITS_PER_LONG
-1);
425 fill_op32(dst
, dst_idx
, pat
, width
*bpp
);
426 dst_idx
+= p
->fix
.line_length
*8;
429 unsigned long pat
= pixel_to_pat(p
, fg
, (left
-dst_idx
) % bpp
);
430 int right
= bpp
-left
;
432 void (*fill_op
)(unsigned long __iomem
*dst
, int dst_idx
,
433 unsigned long pat
, int left
, int right
,
438 fill_op
= bitfill_rev
;
446 dst
+= dst_idx
>> SHIFT_PER_LONG
;
447 dst_idx
&= (BITS_PER_LONG
-1);
448 fill_op(dst
, dst_idx
, pat
, left
, right
,
450 r
= (p
->fix
.line_length
*8) % bpp
;
451 pat
= pat
<< (bpp
-r
) | pat
>> r
;
452 dst_idx
+= p
->fix
.line_length
*8;
457 EXPORT_SYMBOL(cfb_fillrect
);
459 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
460 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
461 MODULE_LICENSE("GPL");