OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [video/] [cfbcopyarea.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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
 
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
     *  Generic bitwise copy algorithm
44
     */
45
 
46
static void
47
bitcpy(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
                // 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 {
97
                /* Different alignment for source and dest */
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
                        // Single destination word
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
                                // Single source word
113
                                d0 >>= right;
114
                        } else if (src_idx+n <= bits) {
115
                                // Single source word
116
                                d0 <<= left;;
117
                        } else {
118
                                // 2 source words
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
                        // 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++);
133
                        d0 = fb_rev_pixels_in_long(d0, bswapmask);
134
                        // Leading bits
135
                        if (shift > 0) {
136
                                // Single source word
137
                                d1 = d0;
138
                                d0 >>= right;
139
                                dst++;
140
                                n -= bits - dst_idx;
141
                        } else {
142
                                // 2 source words
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
                        // Main chunk
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
                        // Trailing bits
182
                        if (last) {
183
                                if (m <= right) {
184
                                        // Single source word
185
                                        d0 <<= left;
186
                                } else {
187
                                        // 2 source words
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
     *  Generic bitwise copy algorithm, operating backward
202
     */
203
 
204
static void
205
bitcpy_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
                // Same alignment for source and dest
229
 
230
                if ((unsigned long)dst_idx+1 >= n) {
231
                        // Single word
232
                        if (last)
233
                                first &= last;
234
                        FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
235
                } else {
236
                        // Multiple destination words
237
 
238
                        // Leading bits
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
                        // Main chunk
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
                        // Trailing bits
263
                        if (last)
264
                                FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
265
                }
266
        } else {
267
                // Different alignment for source and dest
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
                        // Single destination word
277
                        if (last)
278
                                first &= last;
279
                        d0 = FB_READL(src);
280
                        if (shift < 0) {
281
                                // Single source word
282
                                d0 <<= left;
283
                        } else if (1+(unsigned long)src_idx >= n) {
284
                                // Single source word
285
                                d0 >>= right;
286
                        } else {
287
                                // 2 source words
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
                        // Multiple destination words
296
                        /** We must always remember the last value read, because in case
297
                        SRC and DST overlap bitwise (e.g. when moving just one pixel in
298
                        1bpp), we always collect one full long for DST and that might
299
                        overlap with the current long from SRC. We store this value in
300
                        'd0'. */
301
 
302
                        d0 = FB_READL(src--);
303
                        d0 = fb_rev_pixels_in_long(d0, bswapmask);
304
                        // Leading bits
305
                        if (shift < 0) {
306
                                // Single source word
307
                                d1 = d0;
308
                                d0 <<= left;
309
                        } else {
310
                                // 2 source words
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
                        // Main chunk
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
                        // Trailing bits
349
                        if (last) {
350
                                if (m <= left) {
351
                                        // Single source word
352
                                        d0 >>= right;
353
                                } else {
354
                                        // 2 source words
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
 
367
void 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
        /* if the beginning of the target area might overlap with the end of
381
        the source area, be have to copy the area reverse. */
382
        if ((dy == sy && dx > sx) || (dy > sy)) {
383
                dy += height;
384
                sy += height;
385
                rev_copy = 1;
386
        }
387
 
388
        // split the base of the framebuffer into a long-aligned address and the
389
        // index of the first bit
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
        // add offset of source and target area
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
 
424
EXPORT_SYMBOL(cfb_copyarea);
425
 
426
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
427
MODULE_DESCRIPTION("Generic software accelerated copyarea");
428
MODULE_LICENSE("GPL");
429
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.