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 * Also need to add code to deal with cards endians that are different than
13 * the native cpu endians. I also need to deal with MSB position in the word.
16 #include <linux/module.h>
17 #include <linux/string.h>
19 #include <asm/types.h>
22 #if BITS_PER_LONG == 32
23 # define FB_WRITEL fb_writel
24 # define FB_READL fb_readl
26 # define FB_WRITEL fb_writeq
27 # define FB_READL fb_readq
31 * Aligned pattern fill using 32/64-bit memory accesses
35 bitfill_aligned(struct fb_info
*p
, unsigned long __iomem
*dst
, int dst_idx
,
36 unsigned long pat
, unsigned n
, int bits
, u32 bswapmask
)
38 unsigned long first
, last
;
43 first
= fb_shifted_pixels_mask_long(p
, dst_idx
, bswapmask
);
44 last
= ~fb_shifted_pixels_mask_long(p
, (dst_idx
+n
) % bits
, bswapmask
);
46 if (dst_idx
+n
<= bits
) {
50 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
52 // Multiple destination words
56 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
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
++);
75 FB_WRITEL(pat
, dst
++);
79 FB_WRITEL(comp(pat
, FB_READL(dst
), last
), dst
);
85 * Unaligned generic pattern fill using 32/64-bit memory accesses
86 * The pattern must have been expanded to a full 32/64-bit value
87 * Left/right are the appropriate shifts to convert to the pattern to be
88 * used for the next 32/64-bit word
92 bitfill_unaligned(struct fb_info
*p
, unsigned long __iomem
*dst
, int dst_idx
,
93 unsigned long pat
, int left
, int right
, unsigned n
, int bits
)
95 unsigned long first
, last
;
100 first
= FB_SHIFT_HIGH(p
, ~0UL, dst_idx
);
101 last
= ~(FB_SHIFT_HIGH(p
, ~0UL, (dst_idx
+n
) % bits
));
103 if (dst_idx
+n
<= bits
) {
107 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
109 // Multiple destination words
112 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
114 pat
= pat
<< left
| pat
>> right
;
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
;
132 FB_WRITEL(pat
, dst
++);
133 pat
= pat
<< left
| pat
>> right
;
138 FB_WRITEL(comp(pat
, FB_READL(dst
), last
), dst
);
143 * Aligned pattern invert using 32/64-bit memory accesses
146 bitfill_aligned_rev(struct fb_info
*p
, unsigned long __iomem
*dst
,
147 int dst_idx
, unsigned long pat
, unsigned n
, int bits
,
150 unsigned long val
= pat
, dat
;
151 unsigned long first
, last
;
156 first
= fb_shifted_pixels_mask_long(p
, dst_idx
, bswapmask
);
157 last
= ~fb_shifted_pixels_mask_long(p
, (dst_idx
+n
) % bits
, bswapmask
);
159 if (dst_idx
+n
<= bits
) {
164 FB_WRITEL(comp(dat
^ val
, dat
, first
), dst
);
166 // Multiple destination words
170 FB_WRITEL(comp(dat
^ val
, dat
, first
), dst
);
178 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
180 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
182 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
184 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
186 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
188 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
190 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
192 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
197 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
203 FB_WRITEL(comp(dat
^ val
, dat
, last
), dst
);
210 * Unaligned generic pattern invert using 32/64-bit memory accesses
211 * The pattern must have been expanded to a full 32/64-bit value
212 * Left/right are the appropriate shifts to convert to the pattern to be
213 * used for the next 32/64-bit word
217 bitfill_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
)
221 unsigned long first
, last
, dat
;
226 first
= FB_SHIFT_HIGH(p
, ~0UL, dst_idx
);
227 last
= ~(FB_SHIFT_HIGH(p
, ~0UL, (dst_idx
+n
) % bits
));
229 if (dst_idx
+n
<= bits
) {
234 FB_WRITEL(comp(dat
^ pat
, dat
, first
), dst
);
236 // Multiple destination words
241 FB_WRITEL(comp(dat
^ pat
, dat
, first
), dst
);
243 pat
= pat
<< left
| pat
>> right
;
250 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
252 pat
= pat
<< left
| pat
>> right
;
253 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
255 pat
= pat
<< left
| pat
>> right
;
256 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
258 pat
= pat
<< left
| pat
>> right
;
259 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
261 pat
= pat
<< left
| pat
>> right
;
265 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
267 pat
= pat
<< left
| pat
>> right
;
273 FB_WRITEL(comp(dat
^ pat
, dat
, last
), dst
);
278 void cfb_fillrect(struct fb_info
*p
, const struct fb_fillrect
*rect
)
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
;
287 if (p
->state
!= FBINFO_STATE_RUNNING
)
290 if (p
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
291 p
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
)
292 fg
= ((u32
*) (p
->pseudo_palette
))[rect
->color
];
296 pat
= pixel_to_pat(bpp
, fg
);
298 dst
= (unsigned long __iomem
*)((unsigned long)p
->screen_base
& ~(bytes
-1));
299 dst_idx
= ((unsigned long)p
->screen_base
& (bytes
- 1))*8;
300 dst_idx
+= rect
->dy
*p
->fix
.line_length
*8+rect
->dx
*bpp
;
301 /* FIXME For now we support 1-32 bpp only */
303 if (p
->fbops
->fb_sync
)
304 p
->fbops
->fb_sync(p
);
306 u32 bswapmask
= fb_compute_bswapmask(p
);
307 void (*fill_op32
)(struct fb_info
*p
,
308 unsigned long __iomem
*dst
, int dst_idx
,
309 unsigned long pat
, unsigned n
, int bits
,
310 u32 bswapmask
) = NULL
;
314 fill_op32
= bitfill_aligned_rev
;
317 fill_op32
= bitfill_aligned
;
320 printk( KERN_ERR
"cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
321 fill_op32
= bitfill_aligned
;
325 dst
+= dst_idx
>> (ffs(bits
) - 1);
326 dst_idx
&= (bits
- 1);
327 fill_op32(p
, dst
, dst_idx
, pat
, width
*bpp
, bits
,
329 dst_idx
+= p
->fix
.line_length
*8;
333 void (*fill_op
)(struct fb_info
*p
, unsigned long __iomem
*dst
,
334 int dst_idx
, unsigned long pat
, int left
,
335 int right
, unsigned n
, int bits
) = NULL
;
336 #ifdef __LITTLE_ENDIAN
344 fill_op
= bitfill_unaligned_rev
;
347 fill_op
= bitfill_unaligned
;
350 printk(KERN_ERR
"cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
351 fill_op
= bitfill_unaligned
;
355 dst
+= dst_idx
/ bits
;
356 dst_idx
&= (bits
- 1);
358 /* rotate pattern to the correct start position */
359 pat2
= le_long_to_cpu(rolx(cpu_to_le_long(pat
), r
, bpp
));
360 fill_op(p
, dst
, dst_idx
, pat2
, left
, right
,
362 dst_idx
+= p
->fix
.line_length
*8;
367 EXPORT_SYMBOL(cfb_fillrect
);
369 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
370 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
371 MODULE_LICENSE("GPL");