include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / video / cfbcopyarea.c
CommitLineData
1da177e4
LT
1/*
2 * Generic function for frame buffer with packed pixels of any depth.
3 *
4 * Copyright (C) 1999-2005 James Simmons <jsimmons@www.infradead.org>
5 *
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
8 * more details.
9 *
10 * NOTES:
11 *
12 * This is for cfb packed pixels. Iplan and such are incorporated in the
13 * drivers that need them.
14 *
15 * FIXME
16 *
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.
19 *
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.
23 */
24
1da177e4
LT
25#include <linux/module.h>
26#include <linux/kernel.h>
27#include <linux/string.h>
28#include <linux/fb.h>
1da177e4
LT
29#include <asm/types.h>
30#include <asm/io.h>
dc0e6e05 31#include "fb_draw.h"
1da177e4
LT
32
33#if BITS_PER_LONG == 32
34# define FB_WRITEL fb_writel
35# define FB_READL fb_readl
36#else
37# define FB_WRITEL fb_writeq
38# define FB_READL fb_readq
39#endif
40
1da177e4
LT
41 /*
42 * Generic bitwise copy algorithm
43 */
44
45static void
e4c690e0
AV
46bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
47 const unsigned long __iomem *src, int src_idx, int bits,
48 unsigned n, u32 bswapmask)
1da177e4
LT
49{
50 unsigned long first, last;
51 int const shift = dst_idx-src_idx;
52 int left, right;
53
e4c690e0
AV
54 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
55 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
1da177e4
LT
56
57 if (!shift) {
58 // Same alignment for source and dest
59
60 if (dst_idx+n <= bits) {
61 // Single word
62 if (last)
63 first &= last;
64 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
65 } else {
66 // Multiple destination words
67
68 // Leading bits
69 if (first != ~0UL) {
70 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
71 dst++;
72 src++;
73 n -= bits - dst_idx;
74 }
75
76 // Main chunk
77 n /= bits;
78 while (n >= 8) {
79 FB_WRITEL(FB_READL(src++), 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 n -= 8;
88 }
89 while (n--)
90 FB_WRITEL(FB_READL(src++), dst++);
91
92 // Trailing bits
93 if (last)
94 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
95 }
96 } else {
15afdd43 97 /* Different alignment for source and dest */
1da177e4
LT
98 unsigned long d0, d1;
99 int m;
1da177e4
LT
100
101 right = shift & (bits - 1);
102 left = -shift & (bits - 1);
15afdd43 103 bswapmask &= shift;
1da177e4
LT
104
105 if (dst_idx+n <= bits) {
106 // Single destination word
107 if (last)
108 first &= last;
15afdd43
PP
109 d0 = FB_READL(src);
110 d0 = fb_rev_pixels_in_long(d0, bswapmask);
1da177e4
LT
111 if (shift > 0) {
112 // Single source word
15afdd43 113 d0 >>= right;
1da177e4
LT
114 } else if (src_idx+n <= bits) {
115 // Single source word
a419aef8 116 d0 <<= left;
1da177e4
LT
117 } else {
118 // 2 source words
15afdd43
PP
119 d1 = FB_READL(src + 1);
120 d1 = fb_rev_pixels_in_long(d1, bswapmask);
121 d0 = d0<<left | d1>>right;
1da177e4 122 }
15afdd43
PP
123 d0 = fb_rev_pixels_in_long(d0, bswapmask);
124 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
1da177e4
LT
125 } else {
126 // Multiple destination words
127 /** We must always remember the last value read, because in case
128 SRC and DST overlap bitwise (e.g. when moving just one pixel in
129 1bpp), we always collect one full long for DST and that might
130 overlap with the current long from SRC. We store this value in
131 'd0'. */
132 d0 = FB_READL(src++);
15afdd43 133 d0 = fb_rev_pixels_in_long(d0, bswapmask);
1da177e4
LT
134 // Leading bits
135 if (shift > 0) {
136 // Single source word
15afdd43
PP
137 d1 = d0;
138 d0 >>= right;
1da177e4
LT
139 dst++;
140 n -= bits - dst_idx;
141 } else {
142 // 2 source words
143 d1 = FB_READL(src++);
15afdd43
PP
144 d1 = fb_rev_pixels_in_long(d1, bswapmask);
145
146 d0 = d0<<left | d1>>right;
1da177e4
LT
147 dst++;
148 n -= bits - dst_idx;
149 }
15afdd43
PP
150 d0 = fb_rev_pixels_in_long(d0, bswapmask);
151 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
152 d0 = d1;
1da177e4
LT
153
154 // Main chunk
155 m = n % bits;
156 n /= bits;
15afdd43 157 while ((n >= 4) && !bswapmask) {
1da177e4
LT
158 d1 = FB_READL(src++);
159 FB_WRITEL(d0 << left | d1 >> right, dst++);
160 d0 = d1;
161 d1 = FB_READL(src++);
162 FB_WRITEL(d0 << left | d1 >> right, dst++);
163 d0 = d1;
164 d1 = FB_READL(src++);
165 FB_WRITEL(d0 << left | d1 >> right, dst++);
166 d0 = d1;
167 d1 = FB_READL(src++);
168 FB_WRITEL(d0 << left | d1 >> right, dst++);
169 d0 = d1;
170 n -= 4;
171 }
172 while (n--) {
173 d1 = FB_READL(src++);
15afdd43
PP
174 d1 = fb_rev_pixels_in_long(d1, bswapmask);
175 d0 = d0 << left | d1 >> right;
176 d0 = fb_rev_pixels_in_long(d0, bswapmask);
177 FB_WRITEL(d0, dst++);
1da177e4
LT
178 d0 = d1;
179 }
180
181 // Trailing bits
182 if (last) {
183 if (m <= right) {
184 // Single source word
15afdd43 185 d0 <<= left;
1da177e4
LT
186 } else {
187 // 2 source words
188 d1 = FB_READL(src);
15afdd43
PP
189 d1 = fb_rev_pixels_in_long(d1,
190 bswapmask);
191 d0 = d0<<left | d1>>right;
1da177e4 192 }
15afdd43
PP
193 d0 = fb_rev_pixels_in_long(d0, bswapmask);
194 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
1da177e4
LT
195 }
196 }
197 }
198}
199
200 /*
201 * Generic bitwise copy algorithm, operating backward
202 */
203
204static void
e4c690e0
AV
205bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
206 const unsigned long __iomem *src, int src_idx, int bits,
207 unsigned n, u32 bswapmask)
1da177e4
LT
208{
209 unsigned long first, last;
210 int shift;
211
212 dst += (n-1)/bits;
213 src += (n-1)/bits;
214 if ((n-1) % bits) {
215 dst_idx += (n-1) % bits;
216 dst += dst_idx >> (ffs(bits) - 1);
217 dst_idx &= bits - 1;
218 src_idx += (n-1) % bits;
219 src += src_idx >> (ffs(bits) - 1);
220 src_idx &= bits - 1;
221 }
222
223 shift = dst_idx-src_idx;
224
e4c690e0
AV
225 first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
226 last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
227 bswapmask);
1da177e4
LT
228
229 if (!shift) {
230 // Same alignment for source and dest
231
232 if ((unsigned long)dst_idx+1 >= n) {
233 // Single word
234 if (last)
235 first &= last;
236 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
237 } else {
238 // Multiple destination words
239
240 // Leading bits
241 if (first != ~0UL) {
242 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
243 dst--;
244 src--;
245 n -= dst_idx+1;
246 }
247
248 // Main chunk
249 n /= bits;
250 while (n >= 8) {
251 FB_WRITEL(FB_READL(src--), 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 n -= 8;
260 }
261 while (n--)
262 FB_WRITEL(FB_READL(src--), dst--);
263
264 // Trailing bits
265 if (last)
266 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
267 }
268 } else {
269 // Different alignment for source and dest
15afdd43
PP
270 unsigned long d0, d1;
271 int m;
1da177e4
LT
272
273 int const left = -shift & (bits-1);
274 int const right = shift & (bits-1);
15afdd43 275 bswapmask &= shift;
1da177e4
LT
276
277 if ((unsigned long)dst_idx+1 >= n) {
278 // Single destination word
279 if (last)
280 first &= last;
15afdd43 281 d0 = FB_READL(src);
1da177e4
LT
282 if (shift < 0) {
283 // Single source word
15afdd43 284 d0 <<= left;
1da177e4
LT
285 } else if (1+(unsigned long)src_idx >= n) {
286 // Single source word
15afdd43 287 d0 >>= right;
1da177e4
LT
288 } else {
289 // 2 source words
15afdd43
PP
290 d1 = FB_READL(src - 1);
291 d1 = fb_rev_pixels_in_long(d1, bswapmask);
292 d0 = d0>>right | d1<<left;
1da177e4 293 }
15afdd43
PP
294 d0 = fb_rev_pixels_in_long(d0, bswapmask);
295 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
1da177e4
LT
296 } else {
297 // Multiple destination words
298 /** We must always remember the last value read, because in case
299 SRC and DST overlap bitwise (e.g. when moving just one pixel in
300 1bpp), we always collect one full long for DST and that might
301 overlap with the current long from SRC. We store this value in
302 'd0'. */
1da177e4
LT
303
304 d0 = FB_READL(src--);
15afdd43 305 d0 = fb_rev_pixels_in_long(d0, bswapmask);
1da177e4
LT
306 // Leading bits
307 if (shift < 0) {
308 // Single source word
15afdd43
PP
309 d1 = d0;
310 d0 <<= left;
1da177e4
LT
311 } else {
312 // 2 source words
313 d1 = FB_READL(src--);
15afdd43
PP
314 d1 = fb_rev_pixels_in_long(d1, bswapmask);
315 d0 = d0>>right | d1<<left;
1da177e4 316 }
15afdd43
PP
317 d0 = fb_rev_pixels_in_long(d0, bswapmask);
318 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
319 d0 = d1;
1da177e4
LT
320 dst--;
321 n -= dst_idx+1;
322
323 // Main chunk
324 m = n % bits;
325 n /= bits;
15afdd43 326 while ((n >= 4) && !bswapmask) {
1da177e4
LT
327 d1 = FB_READL(src--);
328 FB_WRITEL(d0 >> right | d1 << left, dst--);
329 d0 = d1;
330 d1 = FB_READL(src--);
331 FB_WRITEL(d0 >> right | d1 << left, dst--);
332 d0 = d1;
333 d1 = FB_READL(src--);
334 FB_WRITEL(d0 >> right | d1 << left, dst--);
335 d0 = d1;
336 d1 = FB_READL(src--);
337 FB_WRITEL(d0 >> right | d1 << left, dst--);
338 d0 = d1;
339 n -= 4;
340 }
341 while (n--) {
342 d1 = FB_READL(src--);
15afdd43
PP
343 d1 = fb_rev_pixels_in_long(d1, bswapmask);
344 d0 = d0 >> right | d1 << left;
345 d0 = fb_rev_pixels_in_long(d0, bswapmask);
346 FB_WRITEL(d0, dst--);
1da177e4
LT
347 d0 = d1;
348 }
349
350 // Trailing bits
351 if (last) {
352 if (m <= left) {
353 // Single source word
15afdd43 354 d0 >>= right;
1da177e4
LT
355 } else {
356 // 2 source words
357 d1 = FB_READL(src);
15afdd43
PP
358 d1 = fb_rev_pixels_in_long(d1,
359 bswapmask);
360 d0 = d0>>right | d1<<left;
1da177e4 361 }
15afdd43
PP
362 d0 = fb_rev_pixels_in_long(d0, bswapmask);
363 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
1da177e4
LT
364 }
365 }
366 }
367}
368
369void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
370{
371 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
372 u32 height = area->height, width = area->width;
373 unsigned long const bits_per_line = p->fix.line_length*8u;
374 unsigned long __iomem *dst = NULL, *src = NULL;
375 int bits = BITS_PER_LONG, bytes = bits >> 3;
376 int dst_idx = 0, src_idx = 0, rev_copy = 0;
779121e9 377 u32 bswapmask = fb_compute_bswapmask(p);
1da177e4
LT
378
379 if (p->state != FBINFO_STATE_RUNNING)
380 return;
381
1da177e4
LT
382 /* if the beginning of the target area might overlap with the end of
383 the source area, be have to copy the area reverse. */
384 if ((dy == sy && dx > sx) || (dy > sy)) {
385 dy += height;
386 sy += height;
387 rev_copy = 1;
388 }
389
390 // split the base of the framebuffer into a long-aligned address and the
391 // index of the first bit
392 dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
393 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
394 // add offset of source and target area
395 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
396 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
397
398 if (p->fbops->fb_sync)
399 p->fbops->fb_sync(p);
400
401 if (rev_copy) {
402 while (height--) {
403 dst_idx -= bits_per_line;
404 src_idx -= bits_per_line;
405 dst += dst_idx >> (ffs(bits) - 1);
406 dst_idx &= (bytes - 1);
407 src += src_idx >> (ffs(bits) - 1);
408 src_idx &= (bytes - 1);
e4c690e0 409 bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
779121e9 410 width*p->var.bits_per_pixel, bswapmask);
1da177e4
LT
411 }
412 } else {
413 while (height--) {
414 dst += dst_idx >> (ffs(bits) - 1);
415 dst_idx &= (bytes - 1);
416 src += src_idx >> (ffs(bits) - 1);
417 src_idx &= (bytes - 1);
e4c690e0 418 bitcpy(p, dst, dst_idx, src, src_idx, bits,
779121e9 419 width*p->var.bits_per_pixel, bswapmask);
1da177e4
LT
420 dst_idx += bits_per_line;
421 src_idx += bits_per_line;
422 }
423 }
424}
425
426EXPORT_SYMBOL(cfb_copyarea);
427
428MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
429MODULE_DESCRIPTION("Generic software accelerated copyarea");
430MODULE_LICENSE("GPL");
431