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