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");