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 __iomem *dst, int dst_idx,
47 const unsigned long __iomem *src, int src_idx,
50 unsigned long first, last;
51 int shift = dst_idx-src_idx, left, right;
58 shift = dst_idx-src_idx;
59 first = ~0UL >> dst_idx;
60 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
63 // Same alignment for source and dest
65 if (dst_idx+n <= BITS_PER_LONG) {
69 FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
71 // Multiple destination words
75 FB_WRITEL((FB_READL(src) & first) |
76 (FB_READL(dst) & ~first), dst);
79 n -= BITS_PER_LONG-dst_idx;
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++);
96 FB_WRITEL(FB_READL(src++), dst++);
99 FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
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
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);
121 d0 = FB_READL(src++);
123 FB_WRITEL(((d0<<left | d1>>right) & first) |
124 (FB_READL(dst) & ~first), dst);
127 // Multiple destination words
128 d0 = FB_READL(src++);
131 // Single source word
132 FB_WRITEL(((d0 >> right) & first) |
133 (FB_READL(dst) & ~first), dst);
135 n -= BITS_PER_LONG-dst_idx;
138 d1 = FB_READL(src++);
139 FB_WRITEL(((d0<<left | d1>>right) & first) |
140 (FB_READL(dst) & ~first), dst);
143 n -= BITS_PER_LONG-dst_idx;
147 m = n % BITS_PER_LONG;
150 d1 = FB_READL(src++);
151 FB_WRITEL(d0 << left | d1 >> right, dst++);
153 d1 = FB_READL(src++);
154 FB_WRITEL(d0 << left | d1 >> right, dst++);
156 d1 = FB_READL(src++);
157 FB_WRITEL(d0 << left | d1 >> right, dst++);
159 d1 = FB_READL(src++);
160 FB_WRITEL(d0 << left | d1 >> right, dst++);
165 d1 = FB_READL(src++);
166 FB_WRITEL(d0 << left | d1 >> right, dst++);
173 // Single source word
174 FB_WRITEL(((d0 << left) & last) |
175 (FB_READL(dst) & ~last),
180 FB_WRITEL(((d0<<left | d1>>right) &
181 last) | (FB_READL(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;
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)));
216 // Same alignment for source and dest
218 if ((unsigned long)dst_idx+1 >= n) {
222 FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
224 // Multiple destination words
227 FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), 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--);
243 FB_WRITEL(FB_READL(src--), dst--);
247 FB_WRITEL(FB_READL(src--), dst--);
251 FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
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
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);
273 d0 = FB_READL(src--);
275 FB_WRITEL(((d0>>right | d1<<left) & first) |
276 (FB_READL(dst) & ~first), dst);
279 // Multiple destination words
280 d0 = FB_READL(src--);
283 // Single source word
284 FB_WRITEL(((d0 << left) & first) |
285 (FB_READL(dst) & ~first), dst);
290 d1 = FB_READL(src--);
291 FB_WRITEL(((d0>>right | d1<<left) & first) |
292 (FB_READL(dst) & ~first), dst);
299 m = n % BITS_PER_LONG;
302 d1 = FB_READL(src--);
303 FB_WRITEL(d0 >> right | d1 << left, dst--);
305 d1 = FB_READL(src--);
306 FB_WRITEL(d0 >> right | d1 << left, dst--);
308 d1 = FB_READL(src--);
309 FB_WRITEL(d0 >> right | d1 << left, dst--);
311 d1 = FB_READL(src--);
312 FB_WRITEL(d0 >> right | d1 << left, dst--);
317 d1 = FB_READL(src--);
318 FB_WRITEL(d0 >> right | d1 << left, dst--);
325 // Single source word
326 FB_WRITEL(((d0 >> right) & last) |
327 (FB_READL(dst) & ~last),
332 FB_WRITEL(((d0>>right | d1<<left) &
333 last) | (FB_READL(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)
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)
364 /* clip the destination */
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;
385 /* the source must be completely inside the virtual screen */
386 if (sx < 0 || sy < 0 ||
387 (sx + width) > vxres ||
388 (sy + height) > vyres)
391 if ((dy == sy && dx > sx) ||
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);
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);
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");