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, int dst_idx,
47 const unsigned long __iomem *src, int src_idx, int bits,
48 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(p, dst_idx, bswapmask);
55 last = ~fb_shifted_pixels_mask_long(p, (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(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)
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
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);
228
229 if (!shift) {
230
231
232 if ((unsigned long)dst_idx+1 >= n) {
233
234 if (last)
235 first &= last;
236 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
237 } else {
238
239
240
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
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
265 if (last)
266 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
267 }
268 } else {
269
270 unsigned long d0, d1;
271 int m;
272
273 int const left = -shift & (bits-1);
274 int const right = shift & (bits-1);
275 bswapmask &= shift;
276
277 if ((unsigned long)dst_idx+1 >= n) {
278
279 if (last)
280 first &= last;
281 d0 = FB_READL(src);
282 if (shift < 0) {
283
284 d0 <<= left;
285 } else if (1+(unsigned long)src_idx >= n) {
286
287 d0 >>= right;
288 } else {
289
290 d1 = FB_READL(src - 1);
291 d1 = fb_rev_pixels_in_long(d1, bswapmask);
292 d0 = d0>>right | d1<<left;
293 }
294 d0 = fb_rev_pixels_in_long(d0, bswapmask);
295 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
296 } else {
297
298
299
300
301
302
303
304 d0 = FB_READL(src--);
305 d0 = fb_rev_pixels_in_long(d0, bswapmask);
306
307 if (shift < 0) {
308
309 d1 = d0;
310 d0 <<= left;
311 } else {
312
313 d1 = FB_READL(src--);
314 d1 = fb_rev_pixels_in_long(d1, bswapmask);
315 d0 = d0>>right | d1<<left;
316 }
317 d0 = fb_rev_pixels_in_long(d0, bswapmask);
318 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
319 d0 = d1;
320 dst--;
321 n -= dst_idx+1;
322
323
324 m = n % bits;
325 n /= bits;
326 while ((n >= 4) && !bswapmask) {
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--);
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--);
347 d0 = d1;
348 }
349
350
351 if (last) {
352 if (m <= left) {
353
354 d0 >>= right;
355 } else {
356
357 d1 = FB_READL(src);
358 d1 = fb_rev_pixels_in_long(d1,
359 bswapmask);
360 d0 = d0>>right | d1<<left;
361 }
362 d0 = fb_rev_pixels_in_long(d0, bswapmask);
363 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
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;
377 u32 bswapmask = fb_compute_bswapmask(p);
378
379 if (p->state != FBINFO_STATE_RUNNING)
380 return;
381
382
383
384 if ((dy == sy && dx > sx) || (dy > sy)) {
385 dy += height;
386 sy += height;
387 rev_copy = 1;
388 }
389
390
391
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
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);
409 bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
410 width*p->var.bits_per_pixel, bswapmask);
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);
418 bitcpy(p, dst, dst_idx, src, src_idx, bits,
419 width*p->var.bits_per_pixel, bswapmask);
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
432