1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/module.h>
26#include <linux/kernel.h>
27#include <linux/string.h>
28#include <linux/fb.h>
29#include <linux/slab.h>
30#include <asm/types.h>
31#include <asm/io.h>
32#include "fb_draw.h"
33
34#if BITS_PER_LONG == 32
35# define FB_WRITEL fb_writel
36# define FB_READL fb_readl
37#else
38# define FB_WRITEL fb_writeq
39# define FB_READL fb_readq
40#endif
41
42
43
44
45
46static void
47bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
48 int src_idx, int bits, unsigned n, u32 bswapmask)
49{
50 unsigned long first, last;
51 int const shift = dst_idx-src_idx;
52 int left, right;
53
54 first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
55 last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
56
57 if (!shift) {
58
59
60 if (dst_idx+n <= bits) {
61
62 if (last)
63 first &= last;
64 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
65 } else {
66
67
68
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
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
93 if (last)
94 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
95 }
96 } else {
97
98 unsigned long d0, d1;
99 int m;
100
101 right = shift & (bits - 1);
102 left = -shift & (bits - 1);
103 bswapmask &= shift;
104
105 if (dst_idx+n <= bits) {
106
107 if (last)
108 first &= last;
109 d0 = FB_READL(src);
110 d0 = fb_rev_pixels_in_long(d0, bswapmask);
111 if (shift > 0) {
112
113 d0 >>= right;
114 } else if (src_idx+n <= bits) {
115
116 d0 <<= left;;
117 } else {
118
119 d1 = FB_READL(src + 1);
120 d1 = fb_rev_pixels_in_long(d1, bswapmask);
121 d0 = d0<<left | d1>>right;
122 }
123 d0 = fb_rev_pixels_in_long(d0, bswapmask);
124 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
125 } else {
126
127
128
129
130
131
132 d0 = FB_READL(src++);
133 d0 = fb_rev_pixels_in_long(d0, bswapmask);
134
135 if (shift > 0) {
136
137 d1 = d0;
138 d0 >>= right;
139 dst++;
140 n -= bits - dst_idx;
141 } else {
142
143 d1 = FB_READL(src++);
144 d1 = fb_rev_pixels_in_long(d1, bswapmask);
145
146 d0 = d0<<left | d1>>right;
147 dst++;
148 n -= bits - dst_idx;
149 }
150 d0 = fb_rev_pixels_in_long(d0, bswapmask);
151 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
152 d0 = d1;
153
154
155 m = n % bits;
156 n /= bits;
157 while ((n >= 4) && !bswapmask) {
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++);
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++);
178 d0 = d1;
179 }
180
181
182 if (last) {
183 if (m <= right) {
184
185 d0 <<= left;
186 } else {
187
188 d1 = FB_READL(src);
189 d1 = fb_rev_pixels_in_long(d1,
190 bswapmask);
191 d0 = d0<<left | d1>>right;
192 }
193 d0 = fb_rev_pixels_in_long(d0, bswapmask);
194 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
195 }
196 }
197 }
198}
199
200
201
202
203
204static void
205bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
206 int src_idx, int bits, unsigned n, u32 bswapmask)
207{
208 unsigned long first, last;
209 int shift;
210
211 dst += (n-1)/bits;
212 src += (n-1)/bits;
213 if ((n-1) % bits) {
214 dst_idx += (n-1) % bits;
215 dst += dst_idx >> (ffs(bits) - 1);
216 dst_idx &= bits - 1;
217 src_idx += (n-1) % bits;
218 src += src_idx >> (ffs(bits) - 1);
219 src_idx &= bits - 1;
220 }
221
222 shift = dst_idx-src_idx;
223
224 first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask);
225 last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask);
226
227 if (!shift) {
228
229
230 if ((unsigned long)dst_idx+1 >= n) {
231
232 if (last)
233 first &= last;
234 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
235 } else {
236
237
238
239 if (first != ~0UL) {
240 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
241 dst--;
242 src--;
243 n -= dst_idx+1;
244 }
245
246
247 n /= bits;
248 while (n >= 8) {
249 FB_WRITEL(FB_READL(src--), dst--);
250 FB_WRITEL(FB_READL(src--), dst--);
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 n -= 8;
258 }
259 while (n--)
260 FB_WRITEL(FB_READL(src--), dst--);
261
262
263 if (last)
264 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
265 }
266 } else {
267
268 unsigned long d0, d1;
269 int m;
270
271 int const left = -shift & (bits-1);
272 int const right = shift & (bits-1);
273 bswapmask &= shift;
274
275 if ((unsigned long)dst_idx+1 >= n) {
276
277 if (last)
278 first &= last;
279 d0 = FB_READL(src);
280 if (shift < 0) {
281
282 d0 <<= left;
283 } else if (1+(unsigned long)src_idx >= n) {
284
285 d0 >>= right;
286 } else {
287
288 d1 = FB_READL(src - 1);
289 d1 = fb_rev_pixels_in_long(d1, bswapmask);
290 d0 = d0>>right | d1<<left;
291 }
292 d0 = fb_rev_pixels_in_long(d0, bswapmask);
293 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
294 } else {
295
296
297
298
299
300
301
302 d0 = FB_READL(src--);
303 d0 = fb_rev_pixels_in_long(d0, bswapmask);
304
305 if (shift < 0) {
306
307 d1 = d0;
308 d0 <<= left;
309 } else {
310
311 d1 = FB_READL(src--);
312 d1 = fb_rev_pixels_in_long(d1, bswapmask);
313 d0 = d0>>right | d1<<left;
314 }
315 d0 = fb_rev_pixels_in_long(d0, bswapmask);
316 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
317 d0 = d1;
318 dst--;
319 n -= dst_idx+1;
320
321
322 m = n % bits;
323 n /= bits;
324 while ((n >= 4) && !bswapmask) {
325 d1 = FB_READL(src--);
326 FB_WRITEL(d0 >> right | d1 << left, dst--);
327 d0 = d1;
328 d1 = FB_READL(src--);
329 FB_WRITEL(d0 >> right | d1 << left, dst--);
330 d0 = d1;
331 d1 = FB_READL(src--);
332 FB_WRITEL(d0 >> right | d1 << left, dst--);
333 d0 = d1;
334 d1 = FB_READL(src--);
335 FB_WRITEL(d0 >> right | d1 << left, dst--);
336 d0 = d1;
337 n -= 4;
338 }
339 while (n--) {
340 d1 = FB_READL(src--);
341 d1 = fb_rev_pixels_in_long(d1, bswapmask);
342 d0 = d0 >> right | d1 << left;
343 d0 = fb_rev_pixels_in_long(d0, bswapmask);
344 FB_WRITEL(d0, dst--);
345 d0 = d1;
346 }
347
348
349 if (last) {
350 if (m <= left) {
351
352 d0 >>= right;
353 } else {
354
355 d1 = FB_READL(src);
356 d1 = fb_rev_pixels_in_long(d1,
357 bswapmask);
358 d0 = d0>>right | d1<<left;
359 }
360 d0 = fb_rev_pixels_in_long(d0, bswapmask);
361 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
362 }
363 }
364 }
365}
366
367void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
368{
369 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
370 u32 height = area->height, width = area->width;
371 unsigned long const bits_per_line = p->fix.line_length*8u;
372 unsigned long __iomem *dst = NULL, *src = NULL;
373 int bits = BITS_PER_LONG, bytes = bits >> 3;
374 int dst_idx = 0, src_idx = 0, rev_copy = 0;
375 u32 bswapmask = fb_compute_bswapmask(p);
376
377 if (p->state != FBINFO_STATE_RUNNING)
378 return;
379
380
381
382 if ((dy == sy && dx > sx) || (dy > sy)) {
383 dy += height;
384 sy += height;
385 rev_copy = 1;
386 }
387
388
389
390 dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
391 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
392
393 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
394 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
395
396 if (p->fbops->fb_sync)
397 p->fbops->fb_sync(p);
398
399 if (rev_copy) {
400 while (height--) {
401 dst_idx -= bits_per_line;
402 src_idx -= bits_per_line;
403 dst += dst_idx >> (ffs(bits) - 1);
404 dst_idx &= (bytes - 1);
405 src += src_idx >> (ffs(bits) - 1);
406 src_idx &= (bytes - 1);
407 bitcpy_rev(dst, dst_idx, src, src_idx, bits,
408 width*p->var.bits_per_pixel, bswapmask);
409 }
410 } else {
411 while (height--) {
412 dst += dst_idx >> (ffs(bits) - 1);
413 dst_idx &= (bytes - 1);
414 src += src_idx >> (ffs(bits) - 1);
415 src_idx &= (bytes - 1);
416 bitcpy(dst, dst_idx, src, src_idx, bits,
417 width*p->var.bits_per_pixel, bswapmask);
418 dst_idx += bits_per_line;
419 src_idx += bits_per_line;
420 }
421 }
422}
423
424EXPORT_SYMBOL(cfb_copyarea);
425
426MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
427MODULE_DESCRIPTION("Generic software accelerated copyarea");
428MODULE_LICENSE("GPL");
429
430