• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/video/
1
2
3#include <linux/module.h>
4#include <linux/kernel.h>
5#include <linux/string.h>
6#include <linux/fb.h>
7#include <asm/types.h>
8#include <asm/io.h>
9#include "fb_draw.h"
10
11#if BITS_PER_LONG == 32
12#  define FB_WRITEL fb_writel
13#  define FB_READL  fb_readl
14#else
15#  define FB_WRITEL fb_writeq
16#  define FB_READL  fb_readq
17#endif
18
19    /*
20     *  Generic bitwise copy algorithm
21     */
22
23static void
24bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
25		const unsigned long __iomem *src, int src_idx, int bits,
26		unsigned n, u32 bswapmask)
27{
28	unsigned long first, last;
29	int const shift = dst_idx-src_idx;
30	int left, right;
31
32	first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
33	last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
34
35	if (!shift) {
36		// Same alignment for source and dest
37
38		if (dst_idx+n <= bits) {
39			// Single word
40			if (last)
41				first &= last;
42			FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
43		} else {
44			// Multiple destination words
45
46			// Leading bits
47			if (first != ~0UL) {
48				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
49				dst++;
50				src++;
51				n -= bits - dst_idx;
52			}
53
54			// Main chunk
55			n /= bits;
56			while (n >= 8) {
57				FB_WRITEL(FB_READL(src++), dst++);
58				FB_WRITEL(FB_READL(src++), dst++);
59				FB_WRITEL(FB_READL(src++), dst++);
60				FB_WRITEL(FB_READL(src++), dst++);
61				FB_WRITEL(FB_READL(src++), dst++);
62				FB_WRITEL(FB_READL(src++), dst++);
63				FB_WRITEL(FB_READL(src++), dst++);
64				FB_WRITEL(FB_READL(src++), dst++);
65				n -= 8;
66			}
67			while (n--)
68				FB_WRITEL(FB_READL(src++), dst++);
69
70			// Trailing bits
71			if (last)
72				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
73		}
74	} else {
75		/* Different alignment for source and dest */
76		unsigned long d0, d1;
77		int m;
78
79		right = shift & (bits - 1);
80		left = -shift & (bits - 1);
81		bswapmask &= shift;
82
83		if (dst_idx+n <= bits) {
84			// Single destination word
85			if (last)
86				first &= last;
87			d0 = FB_READL(src);
88			d0 = fb_rev_pixels_in_long(d0, bswapmask);
89			if (shift > 0) {
90				// Single source word
91				d0 >>= right;
92			} else if (src_idx+n <= bits) {
93				// Single source word
94				d0 <<= left;
95			} else {
96				// 2 source words
97				d1 = FB_READL(src + 1);
98				d1 = fb_rev_pixels_in_long(d1, bswapmask);
99				d0 = d0<<left | d1>>right;
100			}
101			d0 = fb_rev_pixels_in_long(d0, bswapmask);
102			FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
103		} else {
104			// Multiple destination words
105			/** We must always remember the last value read, because in case
106			SRC and DST overlap bitwise (e.g. when moving just one pixel in
107			1bpp), we always collect one full long for DST and that might
108			overlap with the current long from SRC. We store this value in
109			'd0'. */
110			d0 = FB_READL(src++);
111			d0 = fb_rev_pixels_in_long(d0, bswapmask);
112			// Leading bits
113			if (shift > 0) {
114				// Single source word
115				d1 = d0;
116				d0 >>= right;
117				dst++;
118				n -= bits - dst_idx;
119			} else {
120				// 2 source words
121				d1 = FB_READL(src++);
122				d1 = fb_rev_pixels_in_long(d1, bswapmask);
123
124				d0 = d0<<left | d1>>right;
125				dst++;
126				n -= bits - dst_idx;
127			}
128			d0 = fb_rev_pixels_in_long(d0, bswapmask);
129			FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
130			d0 = d1;
131
132			// Main chunk
133			m = n % bits;
134			n /= bits;
135			while ((n >= 4) && !bswapmask) {
136				d1 = FB_READL(src++);
137				FB_WRITEL(d0 << left | d1 >> right, dst++);
138				d0 = d1;
139				d1 = FB_READL(src++);
140				FB_WRITEL(d0 << left | d1 >> right, dst++);
141				d0 = d1;
142				d1 = FB_READL(src++);
143				FB_WRITEL(d0 << left | d1 >> right, dst++);
144				d0 = d1;
145				d1 = FB_READL(src++);
146				FB_WRITEL(d0 << left | d1 >> right, dst++);
147				d0 = d1;
148				n -= 4;
149			}
150			while (n--) {
151				d1 = FB_READL(src++);
152				d1 = fb_rev_pixels_in_long(d1, bswapmask);
153				d0 = d0 << left | d1 >> right;
154				d0 = fb_rev_pixels_in_long(d0, bswapmask);
155				FB_WRITEL(d0, dst++);
156				d0 = d1;
157			}
158
159			// Trailing bits
160			if (last) {
161				if (m <= right) {
162					// Single source word
163					d0 <<= left;
164				} else {
165					// 2 source words
166					d1 = FB_READL(src);
167					d1 = fb_rev_pixels_in_long(d1,
168								bswapmask);
169					d0 = d0<<left | d1>>right;
170				}
171				d0 = fb_rev_pixels_in_long(d0, bswapmask);
172				FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
173			}
174		}
175	}
176}
177
178    /*
179     *  Generic bitwise copy algorithm, operating backward
180     */
181
182static void
183bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
184		const unsigned long __iomem *src, int src_idx, int bits,
185		unsigned n, u32 bswapmask)
186{
187	unsigned long first, last;
188	int shift;
189
190	dst += (n-1)/bits;
191	src += (n-1)/bits;
192	if ((n-1) % bits) {
193		dst_idx += (n-1) % bits;
194		dst += dst_idx >> (ffs(bits) - 1);
195		dst_idx &= bits - 1;
196		src_idx += (n-1) % bits;
197		src += src_idx >> (ffs(bits) - 1);
198		src_idx &= bits - 1;
199	}
200
201	shift = dst_idx-src_idx;
202
203	first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
204	last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
205					    bswapmask);
206
207	if (!shift) {
208		// Same alignment for source and dest
209
210		if ((unsigned long)dst_idx+1 >= n) {
211			// Single word
212			if (last)
213				first &= last;
214			FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
215		} else {
216			// Multiple destination words
217
218			// Leading bits
219			if (first != ~0UL) {
220				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
221				dst--;
222				src--;
223				n -= dst_idx+1;
224			}
225
226			// Main chunk
227			n /= bits;
228			while (n >= 8) {
229				FB_WRITEL(FB_READL(src--), dst--);
230				FB_WRITEL(FB_READL(src--), dst--);
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				n -= 8;
238			}
239			while (n--)
240				FB_WRITEL(FB_READL(src--), dst--);
241
242			// Trailing bits
243			if (last)
244				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
245		}
246	} else {
247		// Different alignment for source and dest
248		unsigned long d0, d1;
249		int m;
250
251		int const left = -shift & (bits-1);
252		int const right = shift & (bits-1);
253		bswapmask &= shift;
254
255		if ((unsigned long)dst_idx+1 >= n) {
256			// Single destination word
257			if (last)
258				first &= last;
259			d0 = FB_READL(src);
260			if (shift < 0) {
261				// Single source word
262				d0 <<= left;
263			} else if (1+(unsigned long)src_idx >= n) {
264				// Single source word
265				d0 >>= right;
266			} else {
267				// 2 source words
268				d1 = FB_READL(src - 1);
269				d1 = fb_rev_pixels_in_long(d1, bswapmask);
270				d0 = d0>>right | d1<<left;
271			}
272			d0 = fb_rev_pixels_in_long(d0, bswapmask);
273			FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
274		} else {
275			// Multiple destination words
276			/** We must always remember the last value read, because in case
277			SRC and DST overlap bitwise (e.g. when moving just one pixel in
278			1bpp), we always collect one full long for DST and that might
279			overlap with the current long from SRC. We store this value in
280			'd0'. */
281
282			d0 = FB_READL(src--);
283			d0 = fb_rev_pixels_in_long(d0, bswapmask);
284			// Leading bits
285			if (shift < 0) {
286				// Single source word
287				d1 = d0;
288				d0 <<= left;
289			} else {
290				// 2 source words
291				d1 = FB_READL(src--);
292				d1 = fb_rev_pixels_in_long(d1, bswapmask);
293				d0 = d0>>right | d1<<left;
294			}
295			d0 = fb_rev_pixels_in_long(d0, bswapmask);
296			FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
297			d0 = d1;
298			dst--;
299			n -= dst_idx+1;
300
301			// Main chunk
302			m = n % bits;
303			n /= bits;
304			while ((n >= 4) && !bswapmask) {
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				d1 = FB_READL(src--);
315				FB_WRITEL(d0 >> right | d1 << left, dst--);
316				d0 = d1;
317				n -= 4;
318			}
319			while (n--) {
320				d1 = FB_READL(src--);
321				d1 = fb_rev_pixels_in_long(d1, bswapmask);
322				d0 = d0 >> right | d1 << left;
323				d0 = fb_rev_pixels_in_long(d0, bswapmask);
324				FB_WRITEL(d0, dst--);
325				d0 = d1;
326			}
327
328			// Trailing bits
329			if (last) {
330				if (m <= left) {
331					// Single source word
332					d0 >>= right;
333				} else {
334					// 2 source words
335					d1 = FB_READL(src);
336					d1 = fb_rev_pixels_in_long(d1,
337								bswapmask);
338					d0 = d0>>right | d1<<left;
339				}
340				d0 = fb_rev_pixels_in_long(d0, bswapmask);
341				FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
342			}
343		}
344	}
345}
346
347void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
348{
349	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
350	u32 height = area->height, width = area->width;
351	unsigned long const bits_per_line = p->fix.line_length*8u;
352	unsigned long __iomem *dst = NULL, *src = NULL;
353	int bits = BITS_PER_LONG, bytes = bits >> 3;
354	int dst_idx = 0, src_idx = 0, rev_copy = 0;
355	u32 bswapmask = fb_compute_bswapmask(p);
356
357	if (p->state != FBINFO_STATE_RUNNING)
358		return;
359
360	/* if the beginning of the target area might overlap with the end of
361	the source area, be have to copy the area reverse. */
362	if ((dy == sy && dx > sx) || (dy > sy)) {
363		dy += height;
364		sy += height;
365		rev_copy = 1;
366	}
367
368	// split the base of the framebuffer into a long-aligned address and the
369	// index of the first bit
370	dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
371	dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
372	// add offset of source and target area
373	dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
374	src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
375
376	if (p->fbops->fb_sync)
377		p->fbops->fb_sync(p);
378
379	if (rev_copy) {
380		while (height--) {
381			dst_idx -= bits_per_line;
382			src_idx -= bits_per_line;
383			dst += dst_idx >> (ffs(bits) - 1);
384			dst_idx &= (bytes - 1);
385			src += src_idx >> (ffs(bits) - 1);
386			src_idx &= (bytes - 1);
387			bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
388				width*p->var.bits_per_pixel, bswapmask);
389		}
390	} else {
391		while (height--) {
392			dst += dst_idx >> (ffs(bits) - 1);
393			dst_idx &= (bytes - 1);
394			src += src_idx >> (ffs(bits) - 1);
395			src_idx &= (bytes - 1);
396			bitcpy(p, dst, dst_idx, src, src_idx, bits,
397				width*p->var.bits_per_pixel, bswapmask);
398			dst_idx += bits_per_line;
399			src_idx += bits_per_line;
400		}
401	}
402}
403
404EXPORT_SYMBOL(cfb_copyarea);
405
406MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
407MODULE_DESCRIPTION("Generic software accelerated copyarea");
408MODULE_LICENSE("GPL");
409