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");