Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e4c690e0 authored by Anton Vorontsov's avatar Anton Vorontsov Committed by Linus Torvalds
Browse files

fb: add support for foreign endianness



Add support for the framebuffers with non-native endianness.  This is done via
FBINFO_FOREIGN_ENDIAN flag that will be used by the drivers.  Depending on the
host endianness this flag will be overwritten by FBINFO_BE_MATH internal flag,
or cleared.

Tested to work on MPC8360E-RDK (BE) + Fujitsu MINT framebuffer (LE).

Signed-off-by: default avatarAnton Vorontsov <avorontsov@ru.mvista.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: <Valdis.Kletnieks@vt.edu>
Cc: Clemens Koller <clemens.koller@anagramm.de>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6b745b6f
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -139,6 +139,30 @@ config FB_SYS_IMAGEBLIT
	  blitting. This is used by drivers that don't provide their own
	  (accelerated) version and the framebuffer is in system RAM.

menuconfig FB_FOREIGN_ENDIAN
	bool "Framebuffer foreign endianness support"
	depends on FB
	---help---
	  This menu will let you enable support for the framebuffers with
	  non-native endianness (e.g. Little-Endian framebuffer on a
	  Big-Endian machine). Most probably you don't have such hardware,
	  so it's safe to say "n" here.

choice
	prompt "Choice endianness support"
	depends on FB_FOREIGN_ENDIAN

config FB_BOTH_ENDIAN
	bool "Support for Big- and Little-Endian framebuffers"

config FB_BIG_ENDIAN
	bool "Support for Big-Endian framebuffers only"

config FB_LITTLE_ENDIAN
	bool "Support for Little-Endian framebuffers only"

endchoice

config FB_SYS_FOPS
       tristate
       depends on FB
+13 −10
Original line number Diff line number Diff line
@@ -44,15 +44,16 @@
     */

static void
bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
	int src_idx, int bits, unsigned n, u32 bswapmask)
bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
		const unsigned long __iomem *src, int src_idx, int bits,
		unsigned n, u32 bswapmask)
{
	unsigned long first, last;
	int const shift = dst_idx-src_idx;
	int left, right;

	first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
	last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
	first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
	last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);

	if (!shift) {
		// Same alignment for source and dest
@@ -202,8 +203,9 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
     */

static void
bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
		int src_idx, int bits, unsigned n, u32 bswapmask)
bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
		const unsigned long __iomem *src, int src_idx, int bits,
		unsigned n, u32 bswapmask)
{
	unsigned long first, last;
	int shift;
@@ -221,8 +223,9 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem

	shift = dst_idx-src_idx;

	first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask);
	last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask);
	first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
	last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
					    bswapmask);

	if (!shift) {
		// Same alignment for source and dest
@@ -404,7 +407,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
			dst_idx &= (bytes - 1);
			src += src_idx >> (ffs(bits) - 1);
			src_idx &= (bytes - 1);
			bitcpy_rev(dst, dst_idx, src, src_idx, bits,
			bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
				width*p->var.bits_per_pixel, bswapmask);
		}
	} else {
@@ -413,7 +416,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
			dst_idx &= (bytes - 1);
			src += src_idx >> (ffs(bits) - 1);
			src_idx &= (bytes - 1);
			bitcpy(dst, dst_idx, src, src_idx, bits,
			bitcpy(p, dst, dst_idx, src, src_idx, bits,
				width*p->var.bits_per_pixel, bswapmask);
			dst_idx += bits_per_line;
			src_idx += bits_per_line;
+26 −22
Original line number Diff line number Diff line
@@ -36,16 +36,16 @@
     */

static void
bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
		unsigned n, int bits, u32 bswapmask)
bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
		unsigned long pat, unsigned n, int bits, u32 bswapmask)
{
	unsigned long first, last;

	if (!n)
		return;

	first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
	last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
	first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
	last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);

	if (dst_idx+n <= bits) {
		// Single word
@@ -93,16 +93,16 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
     */

static void
bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
			int left, int right, unsigned n, int bits)
bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
		  unsigned long pat, int left, int right, unsigned n, int bits)
{
	unsigned long first, last;

	if (!n)
		return;

	first = FB_SHIFT_HIGH(~0UL, dst_idx);
	last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
	first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
	last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));

	if (dst_idx+n <= bits) {
		// Single word
@@ -147,8 +147,9 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
     *  Aligned pattern invert using 32/64-bit memory accesses
     */
static void
bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
		unsigned n, int bits, u32 bswapmask)
bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
		    int dst_idx, unsigned long pat, unsigned n, int bits,
		    u32 bswapmask)
{
	unsigned long val = pat, dat;
	unsigned long first, last;
@@ -156,8 +157,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
	if (!n)
		return;

	first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
	last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
	first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
	last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);

	if (dst_idx+n <= bits) {
		// Single word
@@ -217,16 +218,17 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
     */

static void
bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
			int left, int right, unsigned n, int bits)
bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
		      int dst_idx, unsigned long pat, int left, int right,
		      unsigned n, int bits)
{
	unsigned long first, last, dat;

	if (!n)
		return;

	first = FB_SHIFT_HIGH(~0UL, dst_idx);
	last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
	first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
	last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));

	if (dst_idx+n <= bits) {
		// Single word
@@ -306,7 +308,8 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
		p->fbops->fb_sync(p);
	if (!left) {
		u32 bswapmask = fb_compute_bswapmask(p);
		void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
		void (*fill_op32)(struct fb_info *p,
				  unsigned long __iomem *dst, int dst_idx,
		                  unsigned long pat, unsigned n, int bits,
				  u32 bswapmask) = NULL;

@@ -325,16 +328,17 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
		while (height--) {
			dst += dst_idx >> (ffs(bits) - 1);
			dst_idx &= (bits - 1);
			fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask);
			fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
				  bswapmask);
			dst_idx += p->fix.line_length*8;
		}
	} else {
		int right;
		int r;
		int rot = (left-dst_idx) % bpp;
		void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
		                unsigned long pat, int left, int right,
		                unsigned n, int bits) = NULL;
		void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
				int dst_idx, unsigned long pat, int left,
				int right, unsigned n, int bits) = NULL;

		/* rotate pattern to correct start position */
		pat = pat << rot | pat >> (bpp-rot);
@@ -355,7 +359,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
		while (height--) {
			dst += dst_idx >> (ffs(bits) - 1);
			dst_idx &= (bits - 1);
			fill_op(dst, dst_idx, pat, left, right,
			fill_op(p, dst, dst_idx, pat, left, right,
				width*bpp, bits);
			r = (p->fix.line_length*8) % bpp;
			pat = pat << (bpp-r) | pat >> r;
+26 −26
Original line number Diff line number Diff line
@@ -43,30 +43,26 @@
#define DPRINTK(fmt, args...)
#endif

static const u32 cfb_tab8[] = {
#if defined(__BIG_ENDIAN)
static const u32 cfb_tab8_be[] = {
    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
#elif defined(__LITTLE_ENDIAN)
};

static const u32 cfb_tab8_le[] = {
    0x00000000,0xff000000,0x00ff0000,0xffff0000,
    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
#else
#error FIXME: No endianness??
#endif
};

static const u32 cfb_tab16[] = {
#if defined(__BIG_ENDIAN)
static const u32 cfb_tab16_be[] = {
    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
#elif defined(__LITTLE_ENDIAN)
};

static const u32 cfb_tab16_le[] = {
    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
#else
#error FIXME: No endianness??
#endif
};

static const u32 cfb_tab32[] = {
@@ -98,7 +94,8 @@ static inline void color_imageblit(const struct fb_image *image,
		val = 0;
		
		if (start_index) {
			u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
			u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
						start_index, bswapmask);
			val = FB_READL(dst) & start_mask;
			shift = start_index;
		}
@@ -108,20 +105,21 @@ static inline void color_imageblit(const struct fb_image *image,
				color = palette[*src];
			else
				color = *src;
			color <<= FB_LEFT_POS(bpp);
			val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
			color <<= FB_LEFT_POS(p, bpp);
			val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
			if (shift >= null_bits) {
				FB_WRITEL(val, dst++);
	
				val = (shift == null_bits) ? 0 : 
					FB_SHIFT_LOW(color, 32 - shift);
					FB_SHIFT_LOW(p, color, 32 - shift);
			}
			shift += bpp;
			shift &= (32 - 1);
			src++;
		}
		if (shift) {
			u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
			u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
						bswapmask);

			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
		}
@@ -152,8 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
	u32 bswapmask = fb_compute_bswapmask(p);

	dst2 = (u32 __iomem *) dst1;
	fgcolor <<= FB_LEFT_POS(bpp);
	bgcolor <<= FB_LEFT_POS(bpp);
	fgcolor <<= FB_LEFT_POS(p, bpp);
	bgcolor <<= FB_LEFT_POS(p, bpp);

	for (i = image->height; i--; ) {
		shift = val = 0;
@@ -164,7 +162,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *

		/* write leading bits */
		if (start_index) {
			u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
			u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
						start_index, bswapmask);
			val = FB_READL(dst) & start_mask;
			shift = start_index;
		}
@@ -172,13 +171,13 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
		while (j--) {
			l--;
			color = (*s & (1 << l)) ? fgcolor : bgcolor;
			val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
			val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
			
			/* Did the bitshift spill bits to the next long? */
			if (shift >= null_bits) {
				FB_WRITEL(val, dst++);
				val = (shift == null_bits) ? 0 :
					FB_SHIFT_LOW(color,32 - shift);
					FB_SHIFT_LOW(p, color, 32 - shift);
			}
			shift += bpp;
			shift &= (32 - 1);
@@ -187,7 +186,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *

		/* write trailing bits */
 		if (shift) {
			u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
			u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
						bswapmask);

			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
		}
@@ -226,10 +226,10 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *

	switch (bpp) {
	case 8:
		tab = cfb_tab8;
		tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
		break;
	case 16:
		tab = cfb_tab16;
		tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
		break;
	case 32:
	default:
+17 −14
Original line number Diff line number Diff line
@@ -94,41 +94,44 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
	return val;
}

static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index,
					     u32 bswapmask)
{
	u32 mask;

	if (!bswapmask) {
		mask = FB_SHIFT_HIGH(~(u32)0, index);
		mask = FB_SHIFT_HIGH(p, ~(u32)0, index);
	} else {
		mask = 0xff << FB_LEFT_POS(8);
		mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
		mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
		mask = 0xff << FB_LEFT_POS(p, 8);
		mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
		mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
#if defined(__i386__) || defined(__x86_64__)
		/* Shift argument is limited to 0 - 31 on x86 based CPU's */
		if(index + bswapmask < 32)
#endif
			mask |= FB_SHIFT_HIGH(~(u32)0,
			mask |= FB_SHIFT_HIGH(p, ~(u32)0,
					(index + bswapmask) & ~(bswapmask));
	}
	return mask;
}

static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask)
static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p,
							u32 index,
							u32 bswapmask)
{
	unsigned long mask;

	if (!bswapmask) {
		mask = FB_SHIFT_HIGH(~0UL, index);
		mask = FB_SHIFT_HIGH(p, ~0UL, index);
	} else {
		mask = 0xff << FB_LEFT_POS(8);
		mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
		mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
		mask = 0xff << FB_LEFT_POS(p, 8);
		mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
		mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
#if defined(__i386__) || defined(__x86_64__)
		/* Shift argument is limited to 0 - 31 on x86 based CPU's */
		if(index + bswapmask < BITS_PER_LONG)
#endif
			mask |= FB_SHIFT_HIGH(~0UL,
			mask |= FB_SHIFT_HIGH(p, ~0UL,
					(index + bswapmask) & ~(bswapmask));
	}
	return mask;
@@ -158,8 +161,8 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
	return val;
}

#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i))
#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i))
#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i))
#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i))
#define fb_compute_bswapmask(...) 0

#endif  /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
Loading