libata pata_via: ACPI checks for 80wire cable
[pv_ops_mirror.git] / drivers / video / cfbcopyarea.c
blob032210f45be37a539831030b63d64c1a5d3df61a
1 /*
2 * Generic function for frame buffer with packed pixels of any depth.
4 * Copyright (C) 1999-2005 James Simmons <jsimmons@www.infradead.org>
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
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.
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.
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"
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
43 * Generic bitwise copy algorithm
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)
50 unsigned long first, last;
51 int const shift = dst_idx-src_idx;
52 int left, right;
54 first = FB_SHIFT_HIGH(~0UL, dst_idx);
55 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
57 if (!shift) {
58 // Same alignment for source and dest
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
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;
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;
89 while (n--)
90 FB_WRITEL(FB_READL(src++), dst++);
92 // Trailing bits
93 if (last)
94 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
96 } else {
97 unsigned long d0, d1;
98 int m;
99 // Different alignment for source and dest
101 right = shift & (bits - 1);
102 left = -shift & (bits - 1);
104 if (dst_idx+n <= bits) {
105 // Single destination word
106 if (last)
107 first &= last;
108 if (shift > 0) {
109 // Single source word
110 FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst);
111 } else if (src_idx+n <= bits) {
112 // Single source word
113 FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst);
114 } else {
115 // 2 source words
116 d0 = FB_READL(src++);
117 d1 = FB_READL(src);
118 FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst);
120 } else {
121 // Multiple destination words
122 /** We must always remember the last value read, because in case
123 SRC and DST overlap bitwise (e.g. when moving just one pixel in
124 1bpp), we always collect one full long for DST and that might
125 overlap with the current long from SRC. We store this value in
126 'd0'. */
127 d0 = FB_READL(src++);
128 // Leading bits
129 if (shift > 0) {
130 // Single source word
131 FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst);
132 dst++;
133 n -= bits - dst_idx;
134 } else {
135 // 2 source words
136 d1 = FB_READL(src++);
137 FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst);
138 d0 = d1;
139 dst++;
140 n -= bits - dst_idx;
143 // Main chunk
144 m = n % bits;
145 n /= bits;
146 while (n >= 4) {
147 d1 = FB_READL(src++);
148 FB_WRITEL(d0 << left | d1 >> right, dst++);
149 d0 = d1;
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 n -= 4;
161 while (n--) {
162 d1 = FB_READL(src++);
163 FB_WRITEL(d0 << left | d1 >> right, dst++);
164 d0 = d1;
167 // Trailing bits
168 if (last) {
169 if (m <= right) {
170 // Single source word
171 FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst);
172 } else {
173 // 2 source words
174 d1 = FB_READL(src);
175 FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst);
183 * Generic bitwise copy algorithm, operating backward
186 static void
187 bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
188 int src_idx, int bits, unsigned n)
190 unsigned long first, last;
191 int shift;
193 dst += (n-1)/bits;
194 src += (n-1)/bits;
195 if ((n-1) % bits) {
196 dst_idx += (n-1) % bits;
197 dst += dst_idx >> (ffs(bits) - 1);
198 dst_idx &= bits - 1;
199 src_idx += (n-1) % bits;
200 src += src_idx >> (ffs(bits) - 1);
201 src_idx &= bits - 1;
204 shift = dst_idx-src_idx;
206 first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
207 last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
209 if (!shift) {
210 // Same alignment for source and dest
212 if ((unsigned long)dst_idx+1 >= n) {
213 // Single word
214 if (last)
215 first &= last;
216 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
217 } else {
218 // Multiple destination words
220 // Leading bits
221 if (first != ~0UL) {
222 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
223 dst--;
224 src--;
225 n -= dst_idx+1;
228 // Main chunk
229 n /= bits;
230 while (n >= 8) {
231 FB_WRITEL(FB_READL(src--), dst--);
232 FB_WRITEL(FB_READL(src--), dst--);
233 FB_WRITEL(FB_READL(src--), dst--);
234 FB_WRITEL(FB_READL(src--), 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 n -= 8;
241 while (n--)
242 FB_WRITEL(FB_READL(src--), dst--);
244 // Trailing bits
245 if (last)
246 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
248 } else {
249 // Different alignment for source and dest
251 int const left = -shift & (bits-1);
252 int const right = shift & (bits-1);
254 if ((unsigned long)dst_idx+1 >= n) {
255 // Single destination word
256 if (last)
257 first &= last;
258 if (shift < 0) {
259 // Single source word
260 FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst);
261 } else if (1+(unsigned long)src_idx >= n) {
262 // Single source word
263 FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst);
264 } else {
265 // 2 source words
266 FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst);
268 } else {
269 // Multiple destination words
270 /** We must always remember the last value read, because in case
271 SRC and DST overlap bitwise (e.g. when moving just one pixel in
272 1bpp), we always collect one full long for DST and that might
273 overlap with the current long from SRC. We store this value in
274 'd0'. */
275 unsigned long d0, d1;
276 int m;
278 d0 = FB_READL(src--);
279 // Leading bits
280 if (shift < 0) {
281 // Single source word
282 FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst);
283 } else {
284 // 2 source words
285 d1 = FB_READL(src--);
286 FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst);
287 d0 = d1;
289 dst--;
290 n -= dst_idx+1;
292 // Main chunk
293 m = n % bits;
294 n /= bits;
295 while (n >= 4) {
296 d1 = FB_READL(src--);
297 FB_WRITEL(d0 >> right | d1 << left, dst--);
298 d0 = d1;
299 d1 = FB_READL(src--);
300 FB_WRITEL(d0 >> right | d1 << left, dst--);
301 d0 = d1;
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 n -= 4;
310 while (n--) {
311 d1 = FB_READL(src--);
312 FB_WRITEL(d0 >> right | d1 << left, dst--);
313 d0 = d1;
316 // Trailing bits
317 if (last) {
318 if (m <= left) {
319 // Single source word
320 FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst);
321 } else {
322 // 2 source words
323 d1 = FB_READL(src);
324 FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst);
331 void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
333 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
334 u32 height = area->height, width = area->width;
335 unsigned long const bits_per_line = p->fix.line_length*8u;
336 unsigned long __iomem *dst = NULL, *src = NULL;
337 int bits = BITS_PER_LONG, bytes = bits >> 3;
338 int dst_idx = 0, src_idx = 0, rev_copy = 0;
340 if (p->state != FBINFO_STATE_RUNNING)
341 return;
343 /* if the beginning of the target area might overlap with the end of
344 the source area, be have to copy the area reverse. */
345 if ((dy == sy && dx > sx) || (dy > sy)) {
346 dy += height;
347 sy += height;
348 rev_copy = 1;
351 // split the base of the framebuffer into a long-aligned address and the
352 // index of the first bit
353 dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
354 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
355 // add offset of source and target area
356 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
357 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
359 if (p->fbops->fb_sync)
360 p->fbops->fb_sync(p);
362 if (rev_copy) {
363 while (height--) {
364 dst_idx -= bits_per_line;
365 src_idx -= bits_per_line;
366 dst += dst_idx >> (ffs(bits) - 1);
367 dst_idx &= (bytes - 1);
368 src += src_idx >> (ffs(bits) - 1);
369 src_idx &= (bytes - 1);
370 bitcpy_rev(dst, dst_idx, src, src_idx, bits,
371 width*p->var.bits_per_pixel);
373 } else {
374 while (height--) {
375 dst += dst_idx >> (ffs(bits) - 1);
376 dst_idx &= (bytes - 1);
377 src += src_idx >> (ffs(bits) - 1);
378 src_idx &= (bytes - 1);
379 bitcpy(dst, dst_idx, src, src_idx, bits,
380 width*p->var.bits_per_pixel);
381 dst_idx += bits_per_line;
382 src_idx += bits_per_line;
387 EXPORT_SYMBOL(cfb_copyarea);
389 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
390 MODULE_DESCRIPTION("Generic software accelerated copyarea");
391 MODULE_LICENSE("GPL");