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, unsigned n, int bits)
41 unsigned long first, last;
46 first = FB_SHIFT_HIGH(~0UL, dst_idx);
47 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
49 if (dst_idx+n <= bits) {
53 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
55 // Multiple destination words
59 FB_WRITEL(comp(pat, FB_READL(dst), first), 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++);
72 FB_WRITEL(pat, dst++);
73 FB_WRITEL(pat, dst++);
74 FB_WRITEL(pat, dst++);
78 FB_WRITEL(pat, dst++);
82 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
88 * Unaligned generic pattern fill using 32/64-bit memory accesses
89 * The pattern must have been expanded to a full 32/64-bit value
90 * Left/right are the appropriate shifts to convert to the pattern to be
91 * used for the next 32/64-bit word
95 bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
96 int left, int right, unsigned n, int bits)
98 unsigned long first, last;
103 first = FB_SHIFT_HIGH(~0UL, dst_idx);
104 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
106 if (dst_idx+n <= bits) {
110 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
112 // Multiple destination words
115 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
117 pat = pat << left | pat >> right;
124 FB_WRITEL(pat, dst++);
125 pat = pat << left | pat >> right;
126 FB_WRITEL(pat, dst++);
127 pat = pat << left | pat >> right;
128 FB_WRITEL(pat, dst++);
129 pat = pat << left | pat >> right;
130 FB_WRITEL(pat, dst++);
131 pat = pat << left | pat >> right;
135 FB_WRITEL(pat, dst++);
136 pat = pat << left | pat >> right;
141 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
146 * Aligned pattern invert using 32/64-bit memory accesses
149 bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
151 unsigned long val = pat, dat;
152 unsigned long first, last;
157 first = FB_SHIFT_HIGH(~0UL, dst_idx);
158 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
160 if (dst_idx+n <= bits) {
165 FB_WRITEL(comp(dat ^ val, dat, first), dst);
167 // Multiple destination words
171 FB_WRITEL(comp(dat ^ val, dat, first), dst);
179 FB_WRITEL(FB_READL(dst) ^ val, 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);
198 FB_WRITEL(FB_READL(dst) ^ val, dst);
204 FB_WRITEL(comp(dat ^ val, dat, last), dst);
211 * Unaligned generic pattern invert using 32/64-bit memory accesses
212 * The pattern must have been expanded to a full 32/64-bit value
213 * Left/right are the appropriate shifts to convert to the pattern to be
214 * used for the next 32/64-bit word
218 bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
219 int left, int right, unsigned n, int bits)
221 unsigned long first, last, dat;
226 first = FB_SHIFT_HIGH(~0UL, dst_idx);
227 last = ~(FB_SHIFT_HIGH(~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, 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 void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
307 unsigned long pat, unsigned n, int bits) = NULL;
311 fill_op32 = bitfill_aligned_rev;
314 fill_op32 = bitfill_aligned;
317 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
318 fill_op32 = bitfill_aligned;
322 dst += dst_idx >> (ffs(bits) - 1);
323 dst_idx &= (bits - 1);
324 fill_op32(dst, dst_idx, pat, width*bpp, bits);
325 dst_idx += p->fix.line_length*8;
330 int rot = (left-dst_idx) % bpp;
331 void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
332 unsigned long pat, int left, int right,
333 unsigned n, int bits) = NULL;
335 /* rotate pattern to correct start position */
336 pat = pat << rot | pat >> (bpp-rot);
341 fill_op = bitfill_unaligned_rev;
344 fill_op = bitfill_unaligned;
347 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
348 fill_op = bitfill_unaligned;
352 dst += dst_idx >> (ffs(bits) - 1);
353 dst_idx &= (bits - 1);
354 fill_op(dst, dst_idx, pat, left, right,
356 r = (p->fix.line_length*8) % bpp;
357 pat = pat << (bpp-r) | pat >> r;
358 dst_idx += p->fix.line_length*8;
363 EXPORT_SYMBOL(cfb_fillrect);
365 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
366 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
367 MODULE_LICENSE("GPL");