Commit 15afdd43 authored by Pavel Pisa's avatar Pavel Pisa Committed by Linus Torvalds

fbdev: copyarea function taught to fully support swapped pixel order in byte

This correct case, when source and destination X coordinates difference is n
multiple of pixels in byte.  This is probably rare case, but this case should
supported for completeness.

Reorganization of FB_READL and FB_WRITEL calls results in code size decrease
for normal build without swapping support and size with support enabled is
reasonable too.

[adaplas]
Add missing fb_rev_pixels_in_long() prototype.
Signed-off-by: default avatarPavel Pisa <pisa@cmp.felk.cvut.cz>
Signed-off-by: default avatarAntonino Daplas <adaplas@gmail.com>
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent c3ca34f9
...@@ -94,29 +94,34 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src ...@@ -94,29 +94,34 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
} }
} else { } else {
/* Different alignment for source and dest */
unsigned long d0, d1; unsigned long d0, d1;
int m; int m;
// Different alignment for source and dest
right = shift & (bits - 1); right = shift & (bits - 1);
left = -shift & (bits - 1); left = -shift & (bits - 1);
bswapmask &= shift;
if (dst_idx+n <= bits) { if (dst_idx+n <= bits) {
// Single destination word // Single destination word
if (last) if (last)
first &= last; first &= last;
d0 = FB_READL(src);
d0 = fb_rev_pixels_in_long(d0, bswapmask);
if (shift > 0) { if (shift > 0) {
// Single source word // Single source word
FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst); d0 >>= right;
} else if (src_idx+n <= bits) { } else if (src_idx+n <= bits) {
// Single source word // Single source word
FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst); d0 <<= left;;
} else { } else {
// 2 source words // 2 source words
d0 = FB_READL(src++); d1 = FB_READL(src + 1);
d1 = FB_READL(src); d1 = fb_rev_pixels_in_long(d1, bswapmask);
FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); d0 = d0<<left | d1>>right;
} }
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
} else { } else {
// Multiple destination words // Multiple destination words
/** We must always remember the last value read, because in case /** We must always remember the last value read, because in case
...@@ -125,25 +130,31 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src ...@@ -125,25 +130,31 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
overlap with the current long from SRC. We store this value in overlap with the current long from SRC. We store this value in
'd0'. */ 'd0'. */
d0 = FB_READL(src++); d0 = FB_READL(src++);
d0 = fb_rev_pixels_in_long(d0, bswapmask);
// Leading bits // Leading bits
if (shift > 0) { if (shift > 0) {
// Single source word // Single source word
FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst); d1 = d0;
d0 >>= right;
dst++; dst++;
n -= bits - dst_idx; n -= bits - dst_idx;
} else { } else {
// 2 source words // 2 source words
d1 = FB_READL(src++); d1 = FB_READL(src++);
FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d1;
d0 = d0<<left | d1>>right;
dst++; dst++;
n -= bits - dst_idx; n -= bits - dst_idx;
} }
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
d0 = d1;
// Main chunk // Main chunk
m = n % bits; m = n % bits;
n /= bits; n /= bits;
while (n >= 4) { while ((n >= 4) && !bswapmask) {
d1 = FB_READL(src++); d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++); FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1; d0 = d1;
...@@ -160,7 +171,10 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src ...@@ -160,7 +171,10 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
} }
while (n--) { while (n--) {
d1 = FB_READL(src++); d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++); d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d0 << left | d1 >> right;
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(d0, dst++);
d0 = d1; d0 = d1;
} }
...@@ -168,12 +182,16 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src ...@@ -168,12 +182,16 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
if (last) { if (last) {
if (m <= right) { if (m <= right) {
// Single source word // Single source word
FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst); d0 <<= left;
} else { } else {
// 2 source words // 2 source words
d1 = FB_READL(src); d1 = FB_READL(src);
FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst); d1 = fb_rev_pixels_in_long(d1,
bswapmask);
d0 = d0<<left | d1>>right;
} }
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
} }
} }
} }
...@@ -247,24 +265,32 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem ...@@ -247,24 +265,32 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
} }
} else { } else {
// Different alignment for source and dest // Different alignment for source and dest
unsigned long d0, d1;
int m;
int const left = -shift & (bits-1); int const left = -shift & (bits-1);
int const right = shift & (bits-1); int const right = shift & (bits-1);
bswapmask &= shift;
if ((unsigned long)dst_idx+1 >= n) { if ((unsigned long)dst_idx+1 >= n) {
// Single destination word // Single destination word
if (last) if (last)
first &= last; first &= last;
d0 = FB_READL(src);
if (shift < 0) { if (shift < 0) {
// Single source word // Single source word
FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst); d0 <<= left;
} else if (1+(unsigned long)src_idx >= n) { } else if (1+(unsigned long)src_idx >= n) {
// Single source word // Single source word
FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst); d0 >>= right;
} else { } else {
// 2 source words // 2 source words
FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst); d1 = FB_READL(src - 1);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d0>>right | d1<<left;
} }
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
} else { } else {
// Multiple destination words // Multiple destination words
/** We must always remember the last value read, because in case /** We must always remember the last value read, because in case
...@@ -272,27 +298,30 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem ...@@ -272,27 +298,30 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
1bpp), we always collect one full long for DST and that might 1bpp), we always collect one full long for DST and that might
overlap with the current long from SRC. We store this value in overlap with the current long from SRC. We store this value in
'd0'. */ 'd0'. */
unsigned long d0, d1;
int m;
d0 = FB_READL(src--); d0 = FB_READL(src--);
d0 = fb_rev_pixels_in_long(d0, bswapmask);
// Leading bits // Leading bits
if (shift < 0) { if (shift < 0) {
// Single source word // Single source word
FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst); d1 = d0;
d0 <<= left;
} else { } else {
// 2 source words // 2 source words
d1 = FB_READL(src--); d1 = FB_READL(src--);
FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst); d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d1; d0 = d0>>right | d1<<left;
} }
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
d0 = d1;
dst--; dst--;
n -= dst_idx+1; n -= dst_idx+1;
// Main chunk // Main chunk
m = n % bits; m = n % bits;
n /= bits; n /= bits;
while (n >= 4) { while ((n >= 4) && !bswapmask) {
d1 = FB_READL(src--); d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--); FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1; d0 = d1;
...@@ -309,7 +338,10 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem ...@@ -309,7 +338,10 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
} }
while (n--) { while (n--) {
d1 = FB_READL(src--); d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--); d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d0 >> right | d1 << left;
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(d0, dst--);
d0 = d1; d0 = d1;
} }
...@@ -317,12 +349,16 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem ...@@ -317,12 +349,16 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
if (last) { if (last) {
if (m <= left) { if (m <= left) {
// Single source word // Single source word
FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst); d0 >>= right;
} else { } else {
// 2 source words // 2 source words
d1 = FB_READL(src); d1 = FB_READL(src);
FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst); d1 = fb_rev_pixels_in_long(d1,
bswapmask);
d0 = d0>>right | d1<<left;
} }
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
} }
} }
} }
......
...@@ -72,6 +72,26 @@ pixel_to_pat( u32 bpp, u32 pixel) ...@@ -72,6 +72,26 @@ pixel_to_pat( u32 bpp, u32 pixel)
#endif #endif
#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE #ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE
#if BITS_PER_LONG == 64
#define REV_PIXELS_MASK1 0x5555555555555555ul
#define REV_PIXELS_MASK2 0x3333333333333333ul
#define REV_PIXELS_MASK4 0x0f0f0f0f0f0f0f0ful
#else
#define REV_PIXELS_MASK1 0x55555555ul
#define REV_PIXELS_MASK2 0x33333333ul
#define REV_PIXELS_MASK4 0x0f0f0f0ful
#endif
static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
u32 bswapmask)
{
if (bswapmask & 1)
val = comp(val >> 1, val << 1, REV_PIXELS_MASK1);
if (bswapmask & 2)
val = comp(val >> 2, val << 2, REV_PIXELS_MASK2);
if (bswapmask & 3)
val = comp(val >> 4, val << 4, REV_PIXELS_MASK4);
}
static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
{ {
...@@ -131,6 +151,12 @@ static inline u32 fb_compute_bswapmask(struct fb_info *info) ...@@ -131,6 +151,12 @@ static inline u32 fb_compute_bswapmask(struct fb_info *info)
#else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ #else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
u32 bswapmask)
{
return val;
}
#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i)) #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_long(i, b) FB_SHIFT_HIGH(~0UL, (i))
#define fb_compute_bswapmask(...) 0 #define fb_compute_bswapmask(...) 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment