MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / video / cfbcopyarea.c
blobb4b286a4cfb12e61d9b3821df21d0dcfdfb577bd
1 /*
2 * Generic function for frame buffer with packed pixels of any depth.
4 * Copyright (C) June 1999 James Simmons
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.
10 * NOTES:
12 * This is for cfb packed pixels. Iplan and such are incorporated in the
13 * drivers that need them.
15 * FIXME
16 * The code for 24 bit is horrible. It copies byte by byte size instead of
17 * longs like the other sizes. Needs to be optimized.
19 * Also need to add code to deal with cards endians that are different than
20 * the native cpu endians. I also need to deal with MSB position in the word.
23 #include <linux/config.h>
24 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/string.h>
27 #include <linux/fb.h>
28 #include <linux/slab.h>
29 #include <asm/types.h>
30 #include <asm/io.h>
32 #define LONG_MASK (BITS_PER_LONG - 1)
34 #if BITS_PER_LONG == 32
35 #define FB_WRITEL fb_writel
36 #define FB_READL fb_readl
37 #define SHIFT_PER_LONG 5
38 #define BYTES_PER_LONG 4
39 #else
40 #define FB_WRITEL fb_writeq
41 #define FB_READL fb_readq
42 #define SHIFT_PER_LONG 6
43 #define BYTES_PER_LONG 8
44 #endif
46 static void bitcpy(unsigned long __iomem *dst, int dst_idx,
47 const unsigned long __iomem *src, int src_idx,
48 unsigned long n)
50 unsigned long first, last;
51 int shift = dst_idx-src_idx, left, right;
52 unsigned long d0, d1;
53 int m;
55 if (!n)
56 return;
58 shift = dst_idx-src_idx;
59 first = ~0UL >> dst_idx;
60 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
62 if (!shift) {
63 // Same alignment for source and dest
65 if (dst_idx+n <= BITS_PER_LONG) {
66 // Single word
67 if (last)
68 first &= last;
69 FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
70 } else {
71 // Multiple destination words
72 // Leading bits
73 if (first) {
75 FB_WRITEL((FB_READL(src) & first) |
76 (FB_READL(dst) & ~first), dst);
77 dst++;
78 src++;
79 n -= BITS_PER_LONG-dst_idx;
82 // Main chunk
83 n /= BITS_PER_LONG;
84 while (n >= 8) {
85 FB_WRITEL(FB_READL(src++), dst++);
86 FB_WRITEL(FB_READL(src++), dst++);
87 FB_WRITEL(FB_READL(src++), dst++);
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 n -= 8;
95 while (n--)
96 FB_WRITEL(FB_READL(src++), dst++);
97 // Trailing bits
98 if (last)
99 FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
101 } else {
102 // Different alignment for source and dest
104 right = shift & (BITS_PER_LONG-1);
105 left = -shift & (BITS_PER_LONG-1);
107 if (dst_idx+n <= BITS_PER_LONG) {
108 // Single destination word
109 if (last)
110 first &= last;
111 if (shift > 0) {
112 // Single source word
113 FB_WRITEL(((FB_READL(src) >> right) & first) |
114 (FB_READL(dst) & ~first), dst);
115 } else if (src_idx+n <= BITS_PER_LONG) {
116 // Single source word
117 FB_WRITEL(((FB_READL(src) << left) & first) |
118 (FB_READL(dst) & ~first), dst);
119 } else {
120 // 2 source words
121 d0 = FB_READL(src++);
122 d1 = FB_READL(src);
123 FB_WRITEL(((d0<<left | d1>>right) & first) |
124 (FB_READL(dst) & ~first), dst);
126 } else {
127 // Multiple destination words
128 d0 = FB_READL(src++);
129 // Leading bits
130 if (shift > 0) {
131 // Single source word
132 FB_WRITEL(((d0 >> right) & first) |
133 (FB_READL(dst) & ~first), dst);
134 dst++;
135 n -= BITS_PER_LONG-dst_idx;
136 } else {
137 // 2 source words
138 d1 = FB_READL(src++);
139 FB_WRITEL(((d0<<left | d1>>right) & first) |
140 (FB_READL(dst) & ~first), dst);
141 d0 = d1;
142 dst++;
143 n -= BITS_PER_LONG-dst_idx;
146 // Main chunk
147 m = n % BITS_PER_LONG;
148 n /= BITS_PER_LONG;
149 while (n >= 4) {
150 d1 = FB_READL(src++);
151 FB_WRITEL(d0 << left | d1 >> right, dst++);
152 d0 = d1;
153 d1 = FB_READL(src++);
154 FB_WRITEL(d0 << left | d1 >> right, dst++);
155 d0 = d1;
156 d1 = FB_READL(src++);
157 FB_WRITEL(d0 << left | d1 >> right, dst++);
158 d0 = d1;
159 d1 = FB_READL(src++);
160 FB_WRITEL(d0 << left | d1 >> right, dst++);
161 d0 = d1;
162 n -= 4;
164 while (n--) {
165 d1 = FB_READL(src++);
166 FB_WRITEL(d0 << left | d1 >> right, dst++);
167 d0 = d1;
170 // Trailing bits
171 if (last) {
172 if (m <= right) {
173 // Single source word
174 FB_WRITEL(((d0 << left) & last) |
175 (FB_READL(dst) & ~last),
176 dst);
177 } else {
178 // 2 source words
179 d1 = FB_READL(src);
180 FB_WRITEL(((d0<<left | d1>>right) &
181 last) | (FB_READL(dst) &
182 ~last), dst);
189 static void bitcpy_rev(unsigned long __iomem *dst, int dst_idx,
190 const unsigned long __iomem *src, int src_idx, unsigned long n)
192 unsigned long first, last;
193 int shift = dst_idx-src_idx, left, right;
194 unsigned long d0, d1;
195 int m;
197 if (!n)
198 return;
200 dst += (n-1)/BITS_PER_LONG;
201 src += (n-1)/BITS_PER_LONG;
202 if ((n-1) % BITS_PER_LONG) {
203 dst_idx += (n-1) % BITS_PER_LONG;
204 dst += dst_idx >> SHIFT_PER_LONG;
205 dst_idx &= BITS_PER_LONG-1;
206 src_idx += (n-1) % BITS_PER_LONG;
207 src += src_idx >> SHIFT_PER_LONG;
208 src_idx &= BITS_PER_LONG-1;
211 shift = dst_idx-src_idx;
212 first = ~0UL << (BITS_PER_LONG-1-dst_idx);
213 last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
215 if (!shift) {
216 // Same alignment for source and dest
218 if ((unsigned long)dst_idx+1 >= n) {
219 // Single word
220 if (last)
221 first &= last;
222 FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
223 } else {
224 // Multiple destination words
225 // Leading bits
226 if (first) {
227 FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
228 dst--;
229 src--;
230 n -= dst_idx+1;
233 // Main chunk
234 n /= BITS_PER_LONG;
235 while (n >= 8) {
236 FB_WRITEL(FB_READL(src--), dst--);
237 FB_WRITEL(FB_READL(src--), dst--);
238 FB_WRITEL(FB_READL(src--), dst--);
239 FB_WRITEL(FB_READL(src--), dst--);
240 FB_WRITEL(FB_READL(src--), dst--);
241 FB_WRITEL(FB_READL(src--), dst--);
242 FB_WRITEL(FB_READL(src--), dst--);
243 FB_WRITEL(FB_READL(src--), dst--);
244 n -= 8;
246 while (n--)
247 FB_WRITEL(FB_READL(src--), dst--);
249 // Trailing bits
250 if (last)
251 FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
253 } else {
254 // Different alignment for source and dest
256 right = shift & (BITS_PER_LONG-1);
257 left = -shift & (BITS_PER_LONG-1);
259 if ((unsigned long)dst_idx+1 >= n) {
260 // Single destination word
261 if (last)
262 first &= last;
263 if (shift < 0) {
264 // Single source word
265 FB_WRITEL((FB_READL(src) << left & first) |
266 (FB_READL(dst) & ~first), dst);
267 } else if (1+(unsigned long)src_idx >= n) {
268 // Single source word
269 FB_WRITEL(((FB_READL(src) >> right) & first) |
270 (FB_READL(dst) & ~first), dst);
271 } else {
272 // 2 source words
273 d0 = FB_READL(src--);
274 d1 = FB_READL(src);
275 FB_WRITEL(((d0>>right | d1<<left) & first) |
276 (FB_READL(dst) & ~first), dst);
278 } else {
279 // Multiple destination words
280 d0 = FB_READL(src--);
281 // Leading bits
282 if (shift < 0) {
283 // Single source word
284 FB_WRITEL(((d0 << left) & first) |
285 (FB_READL(dst) & ~first), dst);
286 dst--;
287 n -= dst_idx+1;
288 } else {
289 // 2 source words
290 d1 = FB_READL(src--);
291 FB_WRITEL(((d0>>right | d1<<left) & first) |
292 (FB_READL(dst) & ~first), dst);
293 d0 = d1;
294 dst--;
295 n -= dst_idx+1;
298 // Main chunk
299 m = n % BITS_PER_LONG;
300 n /= BITS_PER_LONG;
301 while (n >= 4) {
302 d1 = FB_READL(src--);
303 FB_WRITEL(d0 >> right | d1 << left, dst--);
304 d0 = d1;
305 d1 = FB_READL(src--);
306 FB_WRITEL(d0 >> right | d1 << left, dst--);
307 d0 = d1;
308 d1 = FB_READL(src--);
309 FB_WRITEL(d0 >> right | d1 << left, dst--);
310 d0 = d1;
311 d1 = FB_READL(src--);
312 FB_WRITEL(d0 >> right | d1 << left, dst--);
313 d0 = d1;
314 n -= 4;
316 while (n--) {
317 d1 = FB_READL(src--);
318 FB_WRITEL(d0 >> right | d1 << left, dst--);
319 d0 = d1;
322 // Trailing bits
323 if (last) {
324 if (m <= left) {
325 // Single source word
326 FB_WRITEL(((d0 >> right) & last) |
327 (FB_READL(dst) & ~last),
328 dst);
329 } else {
330 // 2 source words
331 d1 = FB_READL(src);
332 FB_WRITEL(((d0>>right | d1<<left) &
333 last) | (FB_READL(dst) &
334 ~last), dst);
341 void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
343 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
344 u32 height = area->height, width = area->width;
345 int x2, y2, old_dx, old_dy, vxres, vyres;
346 unsigned long next_line = p->fix.line_length;
347 int dst_idx = 0, src_idx = 0, rev_copy = 0;
348 unsigned long __iomem *dst = NULL, *src = NULL;
350 if (p->state != FBINFO_STATE_RUNNING)
351 return;
353 /* We want rotation but lack hardware to do it for us. */
354 if (!p->fbops->fb_rotate && p->var.rotate) {
357 vxres = p->var.xres_virtual;
358 vyres = p->var.yres_virtual;
360 if (area->dx > vxres || area->sx > vxres ||
361 area->dy > vyres || area->sy > vyres)
362 return;
364 /* clip the destination */
365 old_dx = area->dx;
366 old_dy = area->dy;
369 * We could use hardware clipping but on many cards you get around
370 * hardware clipping by writing to framebuffer directly.
372 x2 = area->dx + area->width;
373 y2 = area->dy + area->height;
374 dx = area->dx > 0 ? area->dx : 0;
375 dy = area->dy > 0 ? area->dy : 0;
376 x2 = x2 < vxres ? x2 : vxres;
377 y2 = y2 < vyres ? y2 : vyres;
378 width = x2 - dx;
379 height = y2 - dy;
381 /* update sx1,sy1 */
382 sx += (dx - old_dx);
383 sy += (dy - old_dy);
385 /* the source must be completely inside the virtual screen */
386 if (sx < 0 || sy < 0 ||
387 (sx + width) > vxres ||
388 (sy + height) > vyres)
389 return;
391 if ((dy == sy && dx > sx) ||
392 (dy > sy)) {
393 dy += height;
394 sy += height;
395 rev_copy = 1;
398 dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base &
399 ~(BYTES_PER_LONG-1));
400 dst_idx = src_idx = (unsigned long)p->screen_base & (BYTES_PER_LONG-1);
401 dst_idx += dy*next_line*8 + dx*p->var.bits_per_pixel;
402 src_idx += sy*next_line*8 + sx*p->var.bits_per_pixel;
404 if (p->fbops->fb_sync)
405 p->fbops->fb_sync(p);
406 if (rev_copy) {
407 while (height--) {
408 dst_idx -= next_line*8;
409 src_idx -= next_line*8;
410 dst += dst_idx >> SHIFT_PER_LONG;
411 dst_idx &= (BYTES_PER_LONG-1);
412 src += src_idx >> SHIFT_PER_LONG;
413 src_idx &= (BYTES_PER_LONG-1);
414 bitcpy_rev(dst, dst_idx, src, src_idx,
415 width*p->var.bits_per_pixel);
417 } else {
418 while (height--) {
419 dst += dst_idx >> SHIFT_PER_LONG;
420 dst_idx &= (BYTES_PER_LONG-1);
421 src += src_idx >> SHIFT_PER_LONG;
422 src_idx &= (BYTES_PER_LONG-1);
423 bitcpy(dst, dst_idx, src, src_idx,
424 width*p->var.bits_per_pixel);
425 dst_idx += next_line*8;
426 src_idx += next_line*8;
431 EXPORT_SYMBOL(cfb_copyarea);
433 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
434 MODULE_DESCRIPTION("Generic software accelerated copyarea");
435 MODULE_LICENSE("GPL");