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>
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 * Aligned pattern fill using 32/64-bit memory accesses
39 bitfill_aligned(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
,
40 unsigned n
, int bits
, u32 bswapmask
)
42 unsigned long first
, last
;
47 first
= fb_shifted_pixels_mask_long(dst_idx
, bswapmask
);
48 last
= ~fb_shifted_pixels_mask_long((dst_idx
+n
) % bits
, bswapmask
);
50 if (dst_idx
+n
<= bits
) {
54 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
56 // Multiple destination words
60 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
68 FB_WRITEL(pat
, dst
++);
69 FB_WRITEL(pat
, dst
++);
70 FB_WRITEL(pat
, dst
++);
71 FB_WRITEL(pat
, dst
++);
72 FB_WRITEL(pat
, dst
++);
73 FB_WRITEL(pat
, dst
++);
74 FB_WRITEL(pat
, dst
++);
75 FB_WRITEL(pat
, dst
++);
79 FB_WRITEL(pat
, dst
++);
83 FB_WRITEL(comp(pat
, FB_READL(dst
), last
), dst
);
89 * Unaligned generic pattern fill using 32/64-bit memory accesses
90 * The pattern must have been expanded to a full 32/64-bit value
91 * Left/right are the appropriate shifts to convert to the pattern to be
92 * used for the next 32/64-bit word
96 bitfill_unaligned(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
,
97 int left
, int right
, unsigned n
, int bits
)
99 unsigned long first
, last
;
104 first
= FB_SHIFT_HIGH(~0UL, dst_idx
);
105 last
= ~(FB_SHIFT_HIGH(~0UL, (dst_idx
+n
) % bits
));
107 if (dst_idx
+n
<= bits
) {
111 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
113 // Multiple destination words
116 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
118 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
;
129 FB_WRITEL(pat
, dst
++);
130 pat
= pat
<< left
| pat
>> right
;
131 FB_WRITEL(pat
, dst
++);
132 pat
= pat
<< left
| pat
>> right
;
136 FB_WRITEL(pat
, dst
++);
137 pat
= pat
<< left
| pat
>> right
;
142 FB_WRITEL(comp(pat
, FB_READL(dst
), first
), dst
);
147 * Aligned pattern invert using 32/64-bit memory accesses
150 bitfill_aligned_rev(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
,
151 unsigned n
, int bits
, u32 bswapmask
)
153 unsigned long val
= pat
, dat
;
154 unsigned long first
, last
;
159 first
= fb_shifted_pixels_mask_long(dst_idx
, bswapmask
);
160 last
= ~fb_shifted_pixels_mask_long((dst_idx
+n
) % bits
, bswapmask
);
162 if (dst_idx
+n
<= bits
) {
167 FB_WRITEL(comp(dat
^ val
, dat
, first
), dst
);
169 // Multiple destination words
173 FB_WRITEL(comp(dat
^ val
, dat
, first
), dst
);
181 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
183 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
185 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
187 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
189 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
191 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
193 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
195 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
200 FB_WRITEL(FB_READL(dst
) ^ val
, dst
);
206 FB_WRITEL(comp(dat
^ val
, dat
, last
), dst
);
213 * Unaligned generic pattern invert using 32/64-bit memory accesses
214 * The pattern must have been expanded to a full 32/64-bit value
215 * Left/right are the appropriate shifts to convert to the pattern to be
216 * used for the next 32/64-bit word
220 bitfill_unaligned_rev(unsigned long __iomem
*dst
, int dst_idx
, unsigned long pat
,
221 int left
, int right
, unsigned n
, int bits
)
223 unsigned long first
, last
, dat
;
228 first
= FB_SHIFT_HIGH(~0UL, dst_idx
);
229 last
= ~(FB_SHIFT_HIGH(~0UL, (dst_idx
+n
) % bits
));
231 if (dst_idx
+n
<= bits
) {
236 FB_WRITEL(comp(dat
^ pat
, dat
, first
), dst
);
238 // Multiple destination words
243 FB_WRITEL(comp(dat
^ pat
, dat
, first
), dst
);
245 pat
= pat
<< left
| pat
>> right
;
252 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
254 pat
= pat
<< left
| pat
>> right
;
255 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
257 pat
= pat
<< left
| pat
>> right
;
258 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
260 pat
= pat
<< left
| pat
>> right
;
261 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
263 pat
= pat
<< left
| pat
>> right
;
267 FB_WRITEL(FB_READL(dst
) ^ pat
, dst
);
269 pat
= pat
<< left
| pat
>> right
;
275 FB_WRITEL(comp(dat
^ pat
, dat
, last
), dst
);
280 void cfb_fillrect(struct fb_info
*p
, const struct fb_fillrect
*rect
)
282 unsigned long pat
, fg
;
283 unsigned long width
= rect
->width
, height
= rect
->height
;
284 int bits
= BITS_PER_LONG
, bytes
= bits
>> 3;
285 u32 bpp
= p
->var
.bits_per_pixel
;
286 unsigned long __iomem
*dst
;
289 if (p
->state
!= FBINFO_STATE_RUNNING
)
292 if (p
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
293 p
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
)
294 fg
= ((u32
*) (p
->pseudo_palette
))[rect
->color
];
298 pat
= pixel_to_pat( bpp
, fg
);
300 dst
= (unsigned long __iomem
*)((unsigned long)p
->screen_base
& ~(bytes
-1));
301 dst_idx
= ((unsigned long)p
->screen_base
& (bytes
- 1))*8;
302 dst_idx
+= rect
->dy
*p
->fix
.line_length
*8+rect
->dx
*bpp
;
303 /* FIXME For now we support 1-32 bpp only */
305 if (p
->fbops
->fb_sync
)
306 p
->fbops
->fb_sync(p
);
308 u32 bswapmask
= fb_compute_bswapmask(p
);
309 void (*fill_op32
)(unsigned long __iomem
*dst
, int dst_idx
,
310 unsigned long pat
, unsigned n
, int bits
,
311 u32 bswapmask
) = NULL
;
315 fill_op32
= bitfill_aligned_rev
;
318 fill_op32
= bitfill_aligned
;
321 printk( KERN_ERR
"cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
322 fill_op32
= bitfill_aligned
;
326 dst
+= dst_idx
>> (ffs(bits
) - 1);
327 dst_idx
&= (bits
- 1);
328 fill_op32(dst
, dst_idx
, pat
, width
*bpp
, bits
, bswapmask
);
329 dst_idx
+= p
->fix
.line_length
*8;
334 int rot
= (left
-dst_idx
) % bpp
;
335 void (*fill_op
)(unsigned long __iomem
*dst
, int dst_idx
,
336 unsigned long pat
, int left
, int right
,
337 unsigned n
, int bits
) = NULL
;
339 /* rotate pattern to correct start position */
340 pat
= pat
<< rot
| pat
>> (bpp
-rot
);
345 fill_op
= bitfill_unaligned_rev
;
348 fill_op
= bitfill_unaligned
;
351 printk( KERN_ERR
"cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
352 fill_op
= bitfill_unaligned
;
356 dst
+= dst_idx
>> (ffs(bits
) - 1);
357 dst_idx
&= (bits
- 1);
358 fill_op(dst
, dst_idx
, pat
, left
, right
,
360 r
= (p
->fix
.line_length
*8) % bpp
;
361 pat
= pat
<< (bpp
-r
) | pat
>> r
;
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");