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
12 * This is for cfb packed pixels. Iplan and such are incorporated in the
13 * drivers that need them.
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>
28 #include <linux/slab.h>
29 #include <asm/types.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
40 #define FB_WRITEL fb_writeq
41 #define FB_READL fb_readq
42 #define SHIFT_PER_LONG 6
43 #define BYTES_PER_LONG 8
46 static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
47 int src_idx, unsigned long n)
49 unsigned long first, last;
50 int shift = dst_idx-src_idx, left, right;
57 shift = dst_idx-src_idx;
58 first = ~0UL >> dst_idx;
59 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
62 // Same alignment for source and dest
64 if (dst_idx+n <= BITS_PER_LONG) {
68 FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
70 // Multiple destination words
74 FB_WRITEL((FB_READL(src) & first) |
75 (FB_READL(dst) & ~first), dst);
78 n -= BITS_PER_LONG-dst_idx;
84 FB_WRITEL(FB_READL(src++), dst++);
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++);
95 FB_WRITEL(FB_READL(src++), dst++);
98 FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
101 // Different alignment for source and dest
103 right = shift & (BITS_PER_LONG-1);
104 left = -shift & (BITS_PER_LONG-1);
106 if (dst_idx+n <= BITS_PER_LONG) {
107 // Single destination word
111 // Single source word
112 FB_WRITEL(((FB_READL(src) >> right) & first) |
113 (FB_READL(dst) & ~first), dst);
114 } else if (src_idx+n <= BITS_PER_LONG) {
115 // Single source word
116 FB_WRITEL(((FB_READL(src) << left) & first) |
117 (FB_READL(dst) & ~first), dst);
120 d0 = FB_READL(src++);
122 FB_WRITEL(((d0<<left | d1>>right) & first) |
123 (FB_READL(dst) & ~first), dst);
126 // Multiple destination words
127 d0 = FB_READL(src++);
130 // Single source word
131 FB_WRITEL(((d0 >> right) & first) |
132 (FB_READL(dst) & ~first), dst);
134 n -= BITS_PER_LONG-dst_idx;
137 d1 = FB_READL(src++);
138 FB_WRITEL(((d0<<left | d1>>right) & first) |
139 (FB_READL(dst) & ~first), dst);
142 n -= BITS_PER_LONG-dst_idx;
146 m = n % BITS_PER_LONG;
149 d1 = FB_READL(src++);
150 FB_WRITEL(d0 << left | d1 >> right, dst++);
152 d1 = FB_READL(src++);
153 FB_WRITEL(d0 << left | d1 >> right, dst++);
155 d1 = FB_READL(src++);
156 FB_WRITEL(d0 << left | d1 >> right, dst++);
158 d1 = FB_READL(src++);
159 FB_WRITEL(d0 << left | d1 >> right, dst++);
164 d1 = FB_READL(src++);
165 FB_WRITEL(d0 << left | d1 >> right, dst++);
172 // Single source word
173 FB_WRITEL(((d0 << left) & last) |
174 (FB_READL(dst) & ~last),
179 FB_WRITEL(((d0<<left | d1>>right) &
180 last) | (FB_READL(dst) &
188 static void bitcpy_rev(unsigned long *dst, int dst_idx,
189 const unsigned long *src, int src_idx, unsigned long n)
191 unsigned long first, last;
192 int shift = dst_idx-src_idx, left, right;
193 unsigned long d0, d1;
199 dst += (n-1)/BITS_PER_LONG;
200 src += (n-1)/BITS_PER_LONG;
201 if ((n-1) % BITS_PER_LONG) {
202 dst_idx += (n-1) % BITS_PER_LONG;
203 dst += dst_idx >> SHIFT_PER_LONG;
204 dst_idx &= BITS_PER_LONG-1;
205 src_idx += (n-1) % BITS_PER_LONG;
206 src += src_idx >> SHIFT_PER_LONG;
207 src_idx &= BITS_PER_LONG-1;
210 shift = dst_idx-src_idx;
211 first = ~0UL << (BITS_PER_LONG-1-dst_idx);
212 last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
215 // Same alignment for source and dest
217 if ((unsigned long)dst_idx+1 >= n) {
221 FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
223 // Multiple destination words
226 FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
235 FB_WRITEL(FB_READL(src--), dst--);
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--);
246 FB_WRITEL(FB_READL(src--), dst--);
250 FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
253 // Different alignment for source and dest
255 right = shift & (BITS_PER_LONG-1);
256 left = -shift & (BITS_PER_LONG-1);
258 if ((unsigned long)dst_idx+1 >= n) {
259 // Single destination word
263 // Single source word
264 FB_WRITEL((FB_READL(src) << left & first) |
265 (FB_READL(dst) & ~first), dst);
266 } else if (1+(unsigned long)src_idx >= n) {
267 // Single source word
268 FB_WRITEL(((FB_READL(src) >> right) & first) |
269 (FB_READL(dst) & ~first), dst);
272 d0 = FB_READL(src--);
274 FB_WRITEL(((d0>>right | d1<<left) & first) |
275 (FB_READL(dst) & ~first), dst);
278 // Multiple destination words
279 d0 = FB_READL(src--);
282 // Single source word
283 FB_WRITEL(((d0 << left) & first) |
284 (FB_READL(dst) & ~first), dst);
289 d1 = FB_READL(src--);
290 FB_WRITEL(((d0>>right | d1<<left) & first) |
291 (FB_READL(dst) & ~first), dst);
298 m = n % BITS_PER_LONG;
301 d1 = FB_READL(src--);
302 FB_WRITEL(d0 >> right | d1 << left, dst--);
304 d1 = FB_READL(src--);
305 FB_WRITEL(d0 >> right | d1 << left, dst--);
307 d1 = FB_READL(src--);
308 FB_WRITEL(d0 >> right | d1 << left, dst--);
310 d1 = FB_READL(src--);
311 FB_WRITEL(d0 >> right | d1 << left, dst--);
316 d1 = FB_READL(src--);
317 FB_WRITEL(d0 >> right | d1 << left, dst--);
324 // Single source word
325 FB_WRITEL(((d0 >> right) & last) |
326 (FB_READL(dst) & ~last),
331 FB_WRITEL(((d0>>right | d1<<left) &
332 last) | (FB_READL(dst) &
340 void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
342 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
343 u32 height = area->height, width = area->width;
344 int x2, y2, old_dx, old_dy, vxres, vyres;
345 unsigned long next_line = p->fix.line_length;
346 int dst_idx = 0, src_idx = 0, rev_copy = 0;
347 unsigned long *dst = NULL, *src = NULL;
349 if (p->state != FBINFO_STATE_RUNNING)
352 /* We want rotation but lack hardware to do it for us. */
353 if (!p->fbops->fb_rotate && p->var.rotate) {
356 vxres = p->var.xres_virtual;
357 vyres = p->var.yres_virtual;
359 if (area->dx > vxres || area->sx > vxres ||
360 area->dy > vyres || area->sy > vyres)
363 /* clip the destination */
368 * We could use hardware clipping but on many cards you get around
369 * hardware clipping by writing to framebuffer directly.
371 x2 = area->dx + area->width;
372 y2 = area->dy + area->height;
373 dx = area->dx > 0 ? area->dx : 0;
374 dy = area->dy > 0 ? area->dy : 0;
375 x2 = x2 < vxres ? x2 : vxres;
376 y2 = y2 < vyres ? y2 : vyres;
384 /* the source must be completely inside the virtual screen */
385 if (sx < 0 || sy < 0 ||
386 (sx + width) > vxres ||
387 (sy + height) > vyres)
390 if ((dy == sy && dx > sx) ||
397 dst = src = (unsigned long *)((unsigned long)p->screen_base &
398 ~(BYTES_PER_LONG-1));
399 dst_idx = src_idx = (unsigned long)p->screen_base & (BYTES_PER_LONG-1);
400 dst_idx += dy*next_line*8 + dx*p->var.bits_per_pixel;
401 src_idx += sy*next_line*8 + sx*p->var.bits_per_pixel;
403 if (p->fbops->fb_sync)
404 p->fbops->fb_sync(p);
407 dst_idx -= next_line*8;
408 src_idx -= next_line*8;
409 dst += dst_idx >> SHIFT_PER_LONG;
410 dst_idx &= (BYTES_PER_LONG-1);
411 src += src_idx >> SHIFT_PER_LONG;
412 src_idx &= (BYTES_PER_LONG-1);
413 bitcpy_rev(dst, dst_idx, src, src_idx,
414 width*p->var.bits_per_pixel);
418 dst += dst_idx >> SHIFT_PER_LONG;
419 dst_idx &= (BYTES_PER_LONG-1);
420 src += src_idx >> SHIFT_PER_LONG;
421 src_idx &= (BYTES_PER_LONG-1);
422 bitcpy(dst, dst_idx, src, src_idx,
423 width*p->var.bits_per_pixel);
424 dst_idx += next_line*8;
425 src_idx += next_line*8;
430 EXPORT_SYMBOL(cfb_copyarea);
432 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
433 MODULE_DESCRIPTION("Generic software accelerated copyarea");
434 MODULE_LICENSE("GPL");