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(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
40 unsigned long pat, unsigned n, int bits, u32 bswapmask)
42 unsigned long first, last;
47 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
48 last = ~fb_shifted_pixels_mask_long(p, (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(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
97 unsigned long pat, int left, int right, unsigned n, int bits)
99 unsigned long first, last;
104 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
105 last = ~(FB_SHIFT_HIGH(p, ~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(struct fb_info *p, unsigned long __iomem *dst,
151 int dst_idx, unsigned long pat, unsigned n, int bits,
154 unsigned long val = pat, dat;
155 unsigned long first, last;
160 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
161 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
163 if (dst_idx+n <= bits) {
168 FB_WRITEL(comp(dat ^ val, dat, first), dst);
170 // Multiple destination words
174 FB_WRITEL(comp(dat ^ val, dat, first), 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);
194 FB_WRITEL(FB_READL(dst) ^ val, dst);
196 FB_WRITEL(FB_READL(dst) ^ val, dst);
201 FB_WRITEL(FB_READL(dst) ^ val, dst);
207 FB_WRITEL(comp(dat ^ val, dat, last), dst);
214 * Unaligned generic pattern invert using 32/64-bit memory accesses
215 * The pattern must have been expanded to a full 32/64-bit value
216 * Left/right are the appropriate shifts to convert to the pattern to be
217 * used for the next 32/64-bit word
221 bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
222 int dst_idx, unsigned long pat, int left, int right,
223 unsigned n, int bits)
225 unsigned long first, last, dat;
230 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
231 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
233 if (dst_idx+n <= bits) {
238 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
240 // Multiple destination words
245 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
247 pat = pat << left | pat >> right;
254 FB_WRITEL(FB_READL(dst) ^ pat, dst);
256 pat = pat << left | pat >> right;
257 FB_WRITEL(FB_READL(dst) ^ pat, dst);
259 pat = pat << left | pat >> right;
260 FB_WRITEL(FB_READL(dst) ^ pat, dst);
262 pat = pat << left | pat >> right;
263 FB_WRITEL(FB_READL(dst) ^ pat, dst);
265 pat = pat << left | pat >> right;
269 FB_WRITEL(FB_READL(dst) ^ pat, dst);
271 pat = pat << left | pat >> right;
277 FB_WRITEL(comp(dat ^ pat, dat, last), dst);
282 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
284 unsigned long pat, fg;
285 unsigned long width = rect->width, height = rect->height;
286 int bits = BITS_PER_LONG, bytes = bits >> 3;
287 u32 bpp = p->var.bits_per_pixel;
288 unsigned long __iomem *dst;
291 if (p->state != FBINFO_STATE_RUNNING)
294 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
295 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
296 fg = ((u32 *) (p->pseudo_palette))[rect->color];
300 pat = pixel_to_pat( bpp, fg);
302 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
303 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
304 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
305 /* FIXME For now we support 1-32 bpp only */
307 if (p->fbops->fb_sync)
308 p->fbops->fb_sync(p);
310 u32 bswapmask = fb_compute_bswapmask(p);
311 void (*fill_op32)(struct fb_info *p,
312 unsigned long __iomem *dst, int dst_idx,
313 unsigned long pat, unsigned n, int bits,
314 u32 bswapmask) = NULL;
318 fill_op32 = bitfill_aligned_rev;
321 fill_op32 = bitfill_aligned;
324 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
325 fill_op32 = bitfill_aligned;
329 dst += dst_idx >> (ffs(bits) - 1);
330 dst_idx &= (bits - 1);
331 fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
333 dst_idx += p->fix.line_length*8;
338 int rot = (left-dst_idx) % bpp;
339 void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
340 int dst_idx, unsigned long pat, int left,
341 int right, unsigned n, int bits) = NULL;
343 /* rotate pattern to correct start position */
344 pat = pat << rot | pat >> (bpp-rot);
349 fill_op = bitfill_unaligned_rev;
352 fill_op = bitfill_unaligned;
355 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
356 fill_op = bitfill_unaligned;
360 dst += dst_idx >> (ffs(bits) - 1);
361 dst_idx &= (bits - 1);
362 fill_op(p, dst, dst_idx, pat, left, right,
364 r = (p->fix.line_length*8) % bpp;
365 pat = pat << (bpp-r) | pat >> r;
366 dst_idx += p->fix.line_length*8;
371 EXPORT_SYMBOL(cfb_fillrect);
373 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
374 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
375 MODULE_LICENSE("GPL");