brintos

brintos / linux-shallow public Read only

0
0
Text · 11.4 KiB · a271f57 Raw
441 lines · c
1/*2 *  Generic function for frame buffer with packed pixels of any depth.3 *4 *      Copyright (C)  1999-2005 James Simmons <jsimmons@www.infradead.org>5 *6 *  This file is subject to the terms and conditions of the GNU General Public7 *  License.  See the file COPYING in the main directory of this archive for8 *  more details.9 *10 * NOTES:11 *12 *  This is for cfb packed pixels. Iplan and such are incorporated in the13 *  drivers that need them.14 *15 *  FIXME16 *17 *  Also need to add code to deal with cards endians that are different than18 *  the native cpu endians. I also need to deal with MSB position in the word.19 *20 *  The two functions or copying forward and backward could be split up like21 *  the ones for filling, i.e. in aligned and unaligned versions. This would22 *  help moving some redundant computations and branches out of the loop, too.23 */24 25#include <linux/module.h>26#include <linux/kernel.h>27#include <linux/string.h>28#include <linux/fb.h>29#include <asm/types.h>30#include <asm/io.h>31#include "fb_draw.h"32 33#if BITS_PER_LONG == 3234#  define FB_WRITEL fb_writel35#  define FB_READL  fb_readl36#else37#  define FB_WRITEL fb_writeq38#  define FB_READL  fb_readq39#endif40 41    /*42     *  Generic bitwise copy algorithm43     */44 45static void46bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,47		const unsigned long __iomem *src, unsigned src_idx, int bits,48		unsigned n, u32 bswapmask)49{50	unsigned long first, last;51	int const shift = dst_idx-src_idx;52 53#if 054	/*55	 * If you suspect bug in this function, compare it with this simple56	 * memmove implementation.57	 */58	memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,59		(char *)src + ((src_idx & (bits - 1))) / 8, n / 8);60	return;61#endif62 63	first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);64	last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);65 66	if (!shift) {67		// Same alignment for source and dest68 69		if (dst_idx+n <= bits) {70			// Single word71			if (last)72				first &= last;73			FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);74		} else {75			// Multiple destination words76 77			// Leading bits78			if (first != ~0UL) {79				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);80				dst++;81				src++;82				n -= bits - dst_idx;83			}84 85			// Main chunk86			n /= bits;87			while (n >= 8) {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++);93				FB_WRITEL(FB_READL(src++), dst++);94				FB_WRITEL(FB_READL(src++), dst++);95				FB_WRITEL(FB_READL(src++), dst++);96				n -= 8;97			}98			while (n--)99				FB_WRITEL(FB_READL(src++), dst++);100 101			// Trailing bits102			if (last)103				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);104		}105	} else {106		/* Different alignment for source and dest */107		unsigned long d0, d1;108		int m;109 110		int const left = shift & (bits - 1);111		int const right = -shift & (bits - 1);112 113		if (dst_idx+n <= bits) {114			// Single destination word115			if (last)116				first &= last;117			d0 = FB_READL(src);118			d0 = fb_rev_pixels_in_long(d0, bswapmask);119			if (shift > 0) {120				// Single source word121				d0 <<= left;122			} else if (src_idx+n <= bits) {123				// Single source word124				d0 >>= right;125			} else {126				// 2 source words127				d1 = FB_READL(src + 1);128				d1 = fb_rev_pixels_in_long(d1, bswapmask);129				d0 = d0 >> right | d1 << left;130			}131			d0 = fb_rev_pixels_in_long(d0, bswapmask);132			FB_WRITEL(comp(d0, FB_READL(dst), first), dst);133		} else {134			// Multiple destination words135			/** We must always remember the last value read, because in case136			SRC and DST overlap bitwise (e.g. when moving just one pixel in137			1bpp), we always collect one full long for DST and that might138			overlap with the current long from SRC. We store this value in139			'd0'. */140			d0 = FB_READL(src++);141			d0 = fb_rev_pixels_in_long(d0, bswapmask);142			// Leading bits143			if (shift > 0) {144				// Single source word145				d1 = d0;146				d0 <<= left;147				n -= bits - dst_idx;148			} else {149				// 2 source words150				d1 = FB_READL(src++);151				d1 = fb_rev_pixels_in_long(d1, bswapmask);152 153				d0 = d0 >> right | d1 << left;154				n -= bits - dst_idx;155			}156			d0 = fb_rev_pixels_in_long(d0, bswapmask);157			FB_WRITEL(comp(d0, FB_READL(dst), first), dst);158			d0 = d1;159			dst++;160 161			// Main chunk162			m = n % bits;163			n /= bits;164			while ((n >= 4) && !bswapmask) {165				d1 = FB_READL(src++);166				FB_WRITEL(d0 >> right | d1 << left, dst++);167				d0 = d1;168				d1 = FB_READL(src++);169				FB_WRITEL(d0 >> right | d1 << left, dst++);170				d0 = d1;171				d1 = FB_READL(src++);172				FB_WRITEL(d0 >> right | d1 << left, dst++);173				d0 = d1;174				d1 = FB_READL(src++);175				FB_WRITEL(d0 >> right | d1 << left, dst++);176				d0 = d1;177				n -= 4;178			}179			while (n--) {180				d1 = FB_READL(src++);181				d1 = fb_rev_pixels_in_long(d1, bswapmask);182				d0 = d0 >> right | d1 << left;183				d0 = fb_rev_pixels_in_long(d0, bswapmask);184				FB_WRITEL(d0, dst++);185				d0 = d1;186			}187 188			// Trailing bits189			if (m) {190				if (m <= bits - right) {191					// Single source word192					d0 >>= right;193				} else {194					// 2 source words195					d1 = FB_READL(src);196					d1 = fb_rev_pixels_in_long(d1,197								bswapmask);198					d0 = d0 >> right | d1 << left;199				}200				d0 = fb_rev_pixels_in_long(d0, bswapmask);201				FB_WRITEL(comp(d0, FB_READL(dst), last), dst);202			}203		}204	}205}206 207    /*208     *  Generic bitwise copy algorithm, operating backward209     */210 211static void212bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,213		const unsigned long __iomem *src, unsigned src_idx, int bits,214		unsigned n, u32 bswapmask)215{216	unsigned long first, last;217	int shift;218 219#if 0220	/*221	 * If you suspect bug in this function, compare it with this simple222	 * memmove implementation.223	 */224	memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,225		(char *)src + ((src_idx & (bits - 1))) / 8, n / 8);226	return;227#endif228 229	dst += (dst_idx + n - 1) / bits;230	src += (src_idx + n - 1) / bits;231	dst_idx = (dst_idx + n - 1) % bits;232	src_idx = (src_idx + n - 1) % bits;233 234	shift = dst_idx-src_idx;235 236	first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask);237	last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask);238 239	if (!shift) {240		// Same alignment for source and dest241 242		if ((unsigned long)dst_idx+1 >= n) {243			// Single word244			if (first)245				last &= first;246			FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);247		} else {248			// Multiple destination words249 250			// Leading bits251			if (first) {252				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);253				dst--;254				src--;255				n -= dst_idx+1;256			}257 258			// Main chunk259			n /= bits;260			while (n >= 8) {261				FB_WRITEL(FB_READL(src--), dst--);262				FB_WRITEL(FB_READL(src--), dst--);263				FB_WRITEL(FB_READL(src--), dst--);264				FB_WRITEL(FB_READL(src--), dst--);265				FB_WRITEL(FB_READL(src--), dst--);266				FB_WRITEL(FB_READL(src--), dst--);267				FB_WRITEL(FB_READL(src--), dst--);268				FB_WRITEL(FB_READL(src--), dst--);269				n -= 8;270			}271			while (n--)272				FB_WRITEL(FB_READL(src--), dst--);273 274			// Trailing bits275			if (last != -1UL)276				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);277		}278	} else {279		// Different alignment for source and dest280		unsigned long d0, d1;281		int m;282 283		int const left = shift & (bits-1);284		int const right = -shift & (bits-1);285 286		if ((unsigned long)dst_idx+1 >= n) {287			// Single destination word288			if (first)289				last &= first;290			d0 = FB_READL(src);291			if (shift < 0) {292				// Single source word293				d0 >>= right;294			} else if (1+(unsigned long)src_idx >= n) {295				// Single source word296				d0 <<= left;297			} else {298				// 2 source words299				d1 = FB_READL(src - 1);300				d1 = fb_rev_pixels_in_long(d1, bswapmask);301				d0 = d0 << left | d1 >> right;302			}303			d0 = fb_rev_pixels_in_long(d0, bswapmask);304			FB_WRITEL(comp(d0, FB_READL(dst), last), dst);305		} else {306			// Multiple destination words307			/** We must always remember the last value read, because in case308			SRC and DST overlap bitwise (e.g. when moving just one pixel in309			1bpp), we always collect one full long for DST and that might310			overlap with the current long from SRC. We store this value in311			'd0'. */312 313			d0 = FB_READL(src--);314			d0 = fb_rev_pixels_in_long(d0, bswapmask);315			// Leading bits316			if (shift < 0) {317				// Single source word318				d1 = d0;319				d0 >>= right;320			} else {321				// 2 source words322				d1 = FB_READL(src--);323				d1 = fb_rev_pixels_in_long(d1, bswapmask);324				d0 = d0 << left | d1 >> right;325			}326			d0 = fb_rev_pixels_in_long(d0, bswapmask);327			if (!first)328				FB_WRITEL(d0, dst);329			else330				FB_WRITEL(comp(d0, FB_READL(dst), first), dst);331			d0 = d1;332			dst--;333			n -= dst_idx+1;334 335			// Main chunk336			m = n % bits;337			n /= bits;338			while ((n >= 4) && !bswapmask) {339				d1 = FB_READL(src--);340				FB_WRITEL(d0 << left | d1 >> right, dst--);341				d0 = d1;342				d1 = FB_READL(src--);343				FB_WRITEL(d0 << left | d1 >> right, dst--);344				d0 = d1;345				d1 = FB_READL(src--);346				FB_WRITEL(d0 << left | d1 >> right, dst--);347				d0 = d1;348				d1 = FB_READL(src--);349				FB_WRITEL(d0 << left | d1 >> right, dst--);350				d0 = d1;351				n -= 4;352			}353			while (n--) {354				d1 = FB_READL(src--);355				d1 = fb_rev_pixels_in_long(d1, bswapmask);356				d0 = d0 << left | d1 >> right;357				d0 = fb_rev_pixels_in_long(d0, bswapmask);358				FB_WRITEL(d0, dst--);359				d0 = d1;360			}361 362			// Trailing bits363			if (m) {364				if (m <= bits - left) {365					// Single source word366					d0 <<= left;367				} else {368					// 2 source words369					d1 = FB_READL(src);370					d1 = fb_rev_pixels_in_long(d1,371								bswapmask);372					d0 = d0 << left | d1 >> right;373				}374				d0 = fb_rev_pixels_in_long(d0, bswapmask);375				FB_WRITEL(comp(d0, FB_READL(dst), last), dst);376			}377		}378	}379}380 381void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)382{383	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;384	u32 height = area->height, width = area->width;385	unsigned int const bits_per_line = p->fix.line_length * 8u;386	unsigned long __iomem *base = NULL;387	int bits = BITS_PER_LONG, bytes = bits >> 3;388	unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;389	u32 bswapmask = fb_compute_bswapmask(p);390 391	if (p->state != FBINFO_STATE_RUNNING)392		return;393 394	if (p->flags & FBINFO_VIRTFB)395		fb_warn_once(p, "Framebuffer is not in I/O address space.");396 397	/* if the beginning of the target area might overlap with the end of398	the source area, be have to copy the area reverse. */399	if ((dy == sy && dx > sx) || (dy > sy)) {400		dy += height;401		sy += height;402		rev_copy = 1;403	}404 405	// split the base of the framebuffer into a long-aligned address and the406	// index of the first bit407	base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));408	dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));409	// add offset of source and target area410	dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;411	src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;412 413	if (p->fbops->fb_sync)414		p->fbops->fb_sync(p);415 416	if (rev_copy) {417		while (height--) {418			dst_idx -= bits_per_line;419			src_idx -= bits_per_line;420			bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,421				base + (src_idx / bits), src_idx % bits, bits,422				width*p->var.bits_per_pixel, bswapmask);423		}424	} else {425		while (height--) {426			bitcpy(p, base + (dst_idx / bits), dst_idx % bits,427				base + (src_idx / bits), src_idx % bits, bits,428				width*p->var.bits_per_pixel, bswapmask);429			dst_idx += bits_per_line;430			src_idx += bits_per_line;431		}432	}433}434 435EXPORT_SYMBOL(cfb_copyarea);436 437MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");438MODULE_DESCRIPTION("Generic software accelerated copyarea");439MODULE_LICENSE("GPL");440 441