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