2 * Generic Bit Block Transfer for frame buffers located in system RAM with
3 * packed pixels of any depth.
5 * Based almost entirely from cfbcopyarea.c (which is based almost entirely
6 * on Geert Uytterhoeven's copyarea routine)
8 * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net>
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file COPYING in the main directory of this archive for
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/string.h>
19 #include <linux/slab.h>
20 #include <asm/types.h>
24 * Compose two values, using a bitmask as decision value
25 * This is equivalent to (a & mask) | (b & ~mask)
28 static inline unsigned long
29 comp(unsigned long a, unsigned long b, unsigned long mask)
31 return ((a ^ b) & mask) ^ b;
35 * Generic bitwise copy algorithm
39 bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
40 int src_idx, int bits, unsigned n)
42 unsigned long first, last;
43 int const shift = dst_idx-src_idx;
46 first = FB_SHIFT_HIGH(~0UL, dst_idx);
47 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
50 /* Same alignment for source and dest */
51 if (dst_idx+n <= bits) {
55 *dst = comp(*src, *dst, first);
57 /* Multiple destination words */
60 *dst = comp(*src, *dst, first);
84 *dst = comp(*src, *dst, last);
90 /* Different alignment for source and dest */
91 right = shift & (bits - 1);
92 left = -shift & (bits - 1);
94 if (dst_idx+n <= bits) {
95 /* Single destination word */
99 /* Single source word */
100 *dst = comp(*src >> right, *dst, first);
101 } else if (src_idx+n <= bits) {
102 /* Single source word */
103 *dst = comp(*src << left, *dst, first);
108 *dst = comp(d0 << left | d1 >> right, *dst,
112 /* Multiple destination words */
113 /** We must always remember the last value read,
114 because in case SRC and DST overlap bitwise (e.g.
115 when moving just one pixel in 1bpp), we always
116 collect one full long for DST and that might
117 overlap with the current long from SRC. We store
118 this value in 'd0'. */
122 /* Single source word */
123 *dst = comp(d0 >> right, *dst, first);
129 *dst = comp(d0 << left | *dst >> right, *dst, first);
140 *dst++ = d0 << left | d1 >> right;
143 *dst++ = d0 << left | d1 >> right;
146 *dst++ = d0 << left | d1 >> right;
149 *dst++ = d0 << left | d1 >> right;
155 *dst++ = d0 << left | d1 >> right;
162 /* Single source word */
163 *dst = comp(d0 << left, *dst, last);
167 *dst = comp(d0 << left | d1 >> right,
176 * Generic bitwise copy algorithm, operating backward
180 bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src,
181 int src_idx, int bits, unsigned n)
183 unsigned long first, last;
189 dst_idx += (n-1) % bits;
190 dst += dst_idx >> (ffs(bits) - 1);
192 src_idx += (n-1) % bits;
193 src += src_idx >> (ffs(bits) - 1);
197 shift = dst_idx-src_idx;
199 first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
200 last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
203 /* Same alignment for source and dest */
204 if ((unsigned long)dst_idx+1 >= n) {
208 *dst = comp(*src, *dst, first);
210 /* Multiple destination words */
214 *dst = comp(*src, *dst, first);
237 *dst = comp(*src, *dst, last);
240 /* Different alignment for source and dest */
242 int const left = -shift & (bits-1);
243 int const right = shift & (bits-1);
245 if ((unsigned long)dst_idx+1 >= n) {
246 /* Single destination word */
250 /* Single source word */
251 *dst = comp(*src << left, *dst, first);
252 } else if (1+(unsigned long)src_idx >= n) {
253 /* Single source word */
254 *dst = comp(*src >> right, *dst, first);
257 *dst = comp(*src >> right | *(src-1) << left,
261 /* Multiple destination words */
262 /** We must always remember the last value read,
263 because in case SRC and DST overlap bitwise (e.g.
264 when moving just one pixel in 1bpp), we always
265 collect one full long for DST and that might
266 overlap with the current long from SRC. We store
267 this value in 'd0'. */
268 unsigned long d0, d1;
274 /* Single source word */
275 *dst = comp(d0 << left, *dst, first);
279 *dst = comp(d0 >> right | d1 << left, *dst,
291 *dst-- = d0 >> right | d1 << left;
294 *dst-- = d0 >> right | d1 << left;
297 *dst-- = d0 >> right | d1 << left;
300 *dst-- = d0 >> right | d1 << left;
306 *dst-- = d0 >> right | d1 << left;
313 /* Single source word */
314 *dst = comp(d0 >> right, *dst, last);
318 *dst = comp(d0 >> right | d1 << left,
326 void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
328 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
329 u32 height = area->height, width = area->width;
330 unsigned long const bits_per_line = p->fix.line_length*8u;
331 unsigned long *dst = NULL, *src = NULL;
332 int bits = BITS_PER_LONG, bytes = bits >> 3;
333 int dst_idx = 0, src_idx = 0, rev_copy = 0;
335 if (p->state != FBINFO_STATE_RUNNING)
338 /* if the beginning of the target area might overlap with the end of
339 the source area, be have to copy the area reverse. */
340 if ((dy == sy && dx > sx) || (dy > sy)) {
346 /* split the base of the framebuffer into a long-aligned address and
347 the index of the first bit */
348 dst = src = (unsigned long *)((unsigned long)p->screen_base &
350 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
351 /* add offset of source and target area */
352 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
353 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
355 if (p->fbops->fb_sync)
356 p->fbops->fb_sync(p);
360 dst_idx -= bits_per_line;
361 src_idx -= bits_per_line;
362 dst += dst_idx >> (ffs(bits) - 1);
363 dst_idx &= (bytes - 1);
364 src += src_idx >> (ffs(bits) - 1);
365 src_idx &= (bytes - 1);
366 bitcpy_rev(dst, dst_idx, src, src_idx, bits,
367 width*p->var.bits_per_pixel);
371 dst += dst_idx >> (ffs(bits) - 1);
372 dst_idx &= (bytes - 1);
373 src += src_idx >> (ffs(bits) - 1);
374 src_idx &= (bytes - 1);
375 bitcpy(dst, dst_idx, src, src_idx, bits,
376 width*p->var.bits_per_pixel);
377 dst_idx += bits_per_line;
378 src_idx += bits_per_line;
383 EXPORT_SYMBOL(sys_copyarea);
385 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
386 MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
387 MODULE_LICENSE("GPL");