2 * Generic function for frame buffer with packed pixels of any depth.
4 * Copyright (C) 1999-2005 James Simmons <jsimmons@www.infradead.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 * This is for cfb packed pixels. Iplan and such are incorporated in the
13 * drivers that need them.
17 * Also need to add code to deal with cards endians that are different than
18 * the native cpu endians. I also need to deal with MSB position in the word.
20 * The two functions or copying forward and backward could be split up like
21 * the ones for filling, i.e. in aligned and unaligned versions. This would
22 * help moving some redundant computations and branches out of the loop, too.
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/string.h>
29 #include <linux/slab.h>
30 #include <asm/types.h>
34 #if BITS_PER_LONG == 32
35 # define FB_WRITEL fb_writel
36 # define FB_READL fb_readl
38 # define FB_WRITEL fb_writeq
39 # define FB_READL fb_readq
43 * Generic bitwise copy algorithm
47 bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
48 const unsigned long __iomem *src, int src_idx, int bits,
49 unsigned n, u32 bswapmask)
51 unsigned long first, last;
52 int const shift = dst_idx-src_idx;
55 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
56 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
59 // Same alignment for source and dest
61 if (dst_idx+n <= bits) {
65 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
67 // Multiple destination words
71 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
80 FB_WRITEL(FB_READL(src++), dst++);
81 FB_WRITEL(FB_READL(src++), dst++);
82 FB_WRITEL(FB_READL(src++), dst++);
83 FB_WRITEL(FB_READL(src++), dst++);
84 FB_WRITEL(FB_READL(src++), dst++);
85 FB_WRITEL(FB_READL(src++), dst++);
86 FB_WRITEL(FB_READL(src++), dst++);
87 FB_WRITEL(FB_READL(src++), dst++);
91 FB_WRITEL(FB_READL(src++), dst++);
95 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
98 /* Different alignment for source and dest */
102 right = shift & (bits - 1);
103 left = -shift & (bits - 1);
106 if (dst_idx+n <= bits) {
107 // Single destination word
111 d0 = fb_rev_pixels_in_long(d0, bswapmask);
113 // Single source word
115 } else if (src_idx+n <= bits) {
116 // Single source word
120 d1 = FB_READL(src + 1);
121 d1 = fb_rev_pixels_in_long(d1, bswapmask);
122 d0 = d0<<left | d1>>right;
124 d0 = fb_rev_pixels_in_long(d0, bswapmask);
125 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
127 // Multiple destination words
128 /** We must always remember the last value read, because in case
129 SRC and DST overlap bitwise (e.g. when moving just one pixel in
130 1bpp), we always collect one full long for DST and that might
131 overlap with the current long from SRC. We store this value in
133 d0 = FB_READL(src++);
134 d0 = fb_rev_pixels_in_long(d0, bswapmask);
137 // Single source word
144 d1 = FB_READL(src++);
145 d1 = fb_rev_pixels_in_long(d1, bswapmask);
147 d0 = d0<<left | d1>>right;
151 d0 = fb_rev_pixels_in_long(d0, bswapmask);
152 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
158 while ((n >= 4) && !bswapmask) {
159 d1 = FB_READL(src++);
160 FB_WRITEL(d0 << left | d1 >> right, dst++);
162 d1 = FB_READL(src++);
163 FB_WRITEL(d0 << left | d1 >> right, dst++);
165 d1 = FB_READL(src++);
166 FB_WRITEL(d0 << left | d1 >> right, dst++);
168 d1 = FB_READL(src++);
169 FB_WRITEL(d0 << left | d1 >> right, dst++);
174 d1 = FB_READL(src++);
175 d1 = fb_rev_pixels_in_long(d1, bswapmask);
176 d0 = d0 << left | d1 >> right;
177 d0 = fb_rev_pixels_in_long(d0, bswapmask);
178 FB_WRITEL(d0, dst++);
185 // Single source word
190 d1 = fb_rev_pixels_in_long(d1,
192 d0 = d0<<left | d1>>right;
194 d0 = fb_rev_pixels_in_long(d0, bswapmask);
195 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
202 * Generic bitwise copy algorithm, operating backward
206 bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
207 const unsigned long __iomem *src, int src_idx, int bits,
208 unsigned n, u32 bswapmask)
210 unsigned long first, last;
216 dst_idx += (n-1) % bits;
217 dst += dst_idx >> (ffs(bits) - 1);
219 src_idx += (n-1) % bits;
220 src += src_idx >> (ffs(bits) - 1);
224 shift = dst_idx-src_idx;
226 first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
227 last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
231 // Same alignment for source and dest
233 if ((unsigned long)dst_idx+1 >= n) {
237 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
239 // Multiple destination words
243 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
252 FB_WRITEL(FB_READL(src--), dst--);
253 FB_WRITEL(FB_READL(src--), dst--);
254 FB_WRITEL(FB_READL(src--), dst--);
255 FB_WRITEL(FB_READL(src--), dst--);
256 FB_WRITEL(FB_READL(src--), dst--);
257 FB_WRITEL(FB_READL(src--), dst--);
258 FB_WRITEL(FB_READL(src--), dst--);
259 FB_WRITEL(FB_READL(src--), dst--);
263 FB_WRITEL(FB_READL(src--), dst--);
267 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
270 // Different alignment for source and dest
271 unsigned long d0, d1;
274 int const left = -shift & (bits-1);
275 int const right = shift & (bits-1);
278 if ((unsigned long)dst_idx+1 >= n) {
279 // Single destination word
284 // Single source word
286 } else if (1+(unsigned long)src_idx >= n) {
287 // Single source word
291 d1 = FB_READL(src - 1);
292 d1 = fb_rev_pixels_in_long(d1, bswapmask);
293 d0 = d0>>right | d1<<left;
295 d0 = fb_rev_pixels_in_long(d0, bswapmask);
296 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
298 // Multiple destination words
299 /** We must always remember the last value read, because in case
300 SRC and DST overlap bitwise (e.g. when moving just one pixel in
301 1bpp), we always collect one full long for DST and that might
302 overlap with the current long from SRC. We store this value in
305 d0 = FB_READL(src--);
306 d0 = fb_rev_pixels_in_long(d0, bswapmask);
309 // Single source word
314 d1 = FB_READL(src--);
315 d1 = fb_rev_pixels_in_long(d1, bswapmask);
316 d0 = d0>>right | d1<<left;
318 d0 = fb_rev_pixels_in_long(d0, bswapmask);
319 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
327 while ((n >= 4) && !bswapmask) {
328 d1 = FB_READL(src--);
329 FB_WRITEL(d0 >> right | d1 << left, dst--);
331 d1 = FB_READL(src--);
332 FB_WRITEL(d0 >> right | d1 << left, dst--);
334 d1 = FB_READL(src--);
335 FB_WRITEL(d0 >> right | d1 << left, dst--);
337 d1 = FB_READL(src--);
338 FB_WRITEL(d0 >> right | d1 << left, dst--);
343 d1 = FB_READL(src--);
344 d1 = fb_rev_pixels_in_long(d1, bswapmask);
345 d0 = d0 >> right | d1 << left;
346 d0 = fb_rev_pixels_in_long(d0, bswapmask);
347 FB_WRITEL(d0, dst--);
354 // Single source word
359 d1 = fb_rev_pixels_in_long(d1,
361 d0 = d0>>right | d1<<left;
363 d0 = fb_rev_pixels_in_long(d0, bswapmask);
364 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
370 void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
372 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
373 u32 height = area->height, width = area->width;
374 unsigned long const bits_per_line = p->fix.line_length*8u;
375 unsigned long __iomem *dst = NULL, *src = NULL;
376 int bits = BITS_PER_LONG, bytes = bits >> 3;
377 int dst_idx = 0, src_idx = 0, rev_copy = 0;
378 u32 bswapmask = fb_compute_bswapmask(p);
380 if (p->state != FBINFO_STATE_RUNNING)
383 /* if the beginning of the target area might overlap with the end of
384 the source area, be have to copy the area reverse. */
385 if ((dy == sy && dx > sx) || (dy > sy)) {
391 // split the base of the framebuffer into a long-aligned address and the
392 // index of the first bit
393 dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
394 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
395 // add offset of source and target area
396 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
397 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
399 if (p->fbops->fb_sync)
400 p->fbops->fb_sync(p);
404 dst_idx -= bits_per_line;
405 src_idx -= bits_per_line;
406 dst += dst_idx >> (ffs(bits) - 1);
407 dst_idx &= (bytes - 1);
408 src += src_idx >> (ffs(bits) - 1);
409 src_idx &= (bytes - 1);
410 bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
411 width*p->var.bits_per_pixel, bswapmask);
415 dst += dst_idx >> (ffs(bits) - 1);
416 dst_idx &= (bytes - 1);
417 src += src_idx >> (ffs(bits) - 1);
418 src_idx &= (bytes - 1);
419 bitcpy(p, dst, dst_idx, src, src_idx, bits,
420 width*p->var.bits_per_pixel, bswapmask);
421 dst_idx += bits_per_line;
422 src_idx += bits_per_line;
427 EXPORT_SYMBOL(cfb_copyarea);
429 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
430 MODULE_DESCRIPTION("Generic software accelerated copyarea");
431 MODULE_LICENSE("GPL");