Commit 779121e9f17525769c04a00475fd85600c8c04eb

Authored by Pavel Pisa
Committed by Linus Torvalds
1 parent 3c03ec209a

fbdev: Support for byte-reversed framebuffer formats

Allow generic frame-buffer code to correctly write texts and blit images for
1, 2 and 4 bit per pixel frame-buffer organizations when pixels in bytes are
organized to in opposite order than bytes in long type.

Overhead should be reasonable.  If option is not selected, than compiler
should eliminate completely all overhead.

The feature is disabled at compile time if CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is
not set.

[adaplas]
Convert helper functions to macros if feature is not enabled.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Signed-off-by: Antonino Daplas <adaplas@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 6 changed files with 109 additions and 23 deletions Side-by-side Diff

drivers/video/Kconfig
... ... @@ -103,6 +103,15 @@
103 103 blitting. This is used by drivers that don't provide their own
104 104 (accelerated) version.
105 105  
  106 +config FB_CFB_REV_PIXELS_IN_BYTE
  107 + bool
  108 + depends on FB
  109 + default n
  110 + ---help---
  111 + Allow generic frame-buffer functions to work on displays with 1, 2
  112 + and 4 bits per pixel depths which has opposite order of pixels in
  113 + byte order to bytes in long order.
  114 +
106 115 config FB_SYS_FILLRECT
107 116 tristate
108 117 depends on FB
drivers/video/cfbcopyarea.c
... ... @@ -45,14 +45,14 @@
45 45  
46 46 static void
47 47 bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
48   - int src_idx, int bits, unsigned n)
  48 + int src_idx, int bits, unsigned n, u32 bswapmask)
49 49 {
50 50 unsigned long first, last;
51 51 int const shift = dst_idx-src_idx;
52 52 int left, right;
53 53  
54   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
55   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  54 + first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
  55 + last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
56 56  
57 57 if (!shift) {
58 58 // Same alignment for source and dest
... ... @@ -185,7 +185,7 @@
185 185  
186 186 static void
187 187 bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
188   - int src_idx, int bits, unsigned n)
  188 + int src_idx, int bits, unsigned n, u32 bswapmask)
189 189 {
190 190 unsigned long first, last;
191 191 int shift;
... ... @@ -203,8 +203,8 @@
203 203  
204 204 shift = dst_idx-src_idx;
205 205  
206   - first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
207   - last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
  206 + first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask);
  207 + last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask);
208 208  
209 209 if (!shift) {
210 210 // Same alignment for source and dest
... ... @@ -336,6 +336,7 @@
336 336 unsigned long __iomem *dst = NULL, *src = NULL;
337 337 int bits = BITS_PER_LONG, bytes = bits >> 3;
338 338 int dst_idx = 0, src_idx = 0, rev_copy = 0;
  339 + u32 bswapmask = fb_compute_bswapmask(p);
339 340  
340 341 if (p->state != FBINFO_STATE_RUNNING)
341 342 return;
... ... @@ -368,7 +369,7 @@
368 369 src += src_idx >> (ffs(bits) - 1);
369 370 src_idx &= (bytes - 1);
370 371 bitcpy_rev(dst, dst_idx, src, src_idx, bits,
371   - width*p->var.bits_per_pixel);
  372 + width*p->var.bits_per_pixel, bswapmask);
372 373 }
373 374 } else {
374 375 while (height--) {
... ... @@ -377,7 +378,7 @@
377 378 src += src_idx >> (ffs(bits) - 1);
378 379 src_idx &= (bytes - 1);
379 380 bitcpy(dst, dst_idx, src, src_idx, bits,
380   - width*p->var.bits_per_pixel);
  381 + width*p->var.bits_per_pixel, bswapmask);
381 382 dst_idx += bits_per_line;
382 383 src_idx += bits_per_line;
383 384 }
drivers/video/cfbfillrect.c
... ... @@ -36,15 +36,16 @@
36 36 */
37 37  
38 38 static void
39   -bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
  39 +bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
  40 + unsigned n, int bits, u32 bswapmask)
40 41 {
41 42 unsigned long first, last;
42 43  
43 44 if (!n)
44 45 return;
45 46  
46   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
47   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  47 + first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
  48 + last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
48 49  
49 50 if (dst_idx+n <= bits) {
50 51 // Single word
... ... @@ -146,7 +147,8 @@
146 147 * Aligned pattern invert using 32/64-bit memory accesses
147 148 */
148 149 static void
149   -bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
  150 +bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
  151 + unsigned n, int bits, u32 bswapmask)
150 152 {
151 153 unsigned long val = pat, dat;
152 154 unsigned long first, last;
... ... @@ -154,8 +156,8 @@
154 156 if (!n)
155 157 return;
156 158  
157   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
158   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  159 + first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
  160 + last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
159 161  
160 162 if (dst_idx+n <= bits) {
161 163 // Single word
162 164  
... ... @@ -303,8 +305,10 @@
303 305 if (p->fbops->fb_sync)
304 306 p->fbops->fb_sync(p);
305 307 if (!left) {
  308 + u32 bswapmask = fb_compute_bswapmask(p);
306 309 void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
307   - unsigned long pat, unsigned n, int bits) = NULL;
  310 + unsigned long pat, unsigned n, int bits,
  311 + u32 bswapmask) = NULL;
308 312  
309 313 switch (rect->rop) {
310 314 case ROP_XOR:
... ... @@ -321,7 +325,7 @@
321 325 while (height--) {
322 326 dst += dst_idx >> (ffs(bits) - 1);
323 327 dst_idx &= (bits - 1);
324   - fill_op32(dst, dst_idx, pat, width*bpp, bits);
  328 + fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask);
325 329 dst_idx += p->fix.line_length*8;
326 330 }
327 331 } else {
drivers/video/cfbimgblt.c
... ... @@ -33,6 +33,7 @@
33 33 #include <linux/string.h>
34 34 #include <linux/fb.h>
35 35 #include <asm/types.h>
  36 +#include "fb_draw.h"
36 37  
37 38 #define DEBUG
38 39  
... ... @@ -87,6 +88,7 @@
87 88 u32 null_bits = 32 - bpp;
88 89 u32 *palette = (u32 *) p->pseudo_palette;
89 90 const u8 *src = image->data;
  91 + u32 bswapmask = fb_compute_bswapmask(p);
90 92  
91 93 dst2 = (u32 __iomem *) dst1;
92 94 for (i = image->height; i--; ) {
... ... @@ -96,7 +98,7 @@
96 98 val = 0;
97 99  
98 100 if (start_index) {
99   - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index));
  101 + u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
100 102 val = FB_READL(dst) & start_mask;
101 103 shift = start_index;
102 104 }
... ... @@ -107,7 +109,7 @@
107 109 else
108 110 color = *src;
109 111 color <<= FB_LEFT_POS(bpp);
110   - val |= FB_SHIFT_HIGH(color, shift);
  112 + val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
111 113 if (shift >= null_bits) {
112 114 FB_WRITEL(val, dst++);
113 115  
... ... @@ -119,7 +121,7 @@
119 121 src++;
120 122 }
121 123 if (shift) {
122   - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
  124 + u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
123 125  
124 126 FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
125 127 }
... ... @@ -147,7 +149,8 @@
147 149 u32 spitch = (image->width+7)/8;
148 150 const u8 *src = image->data, *s;
149 151 u32 i, j, l;
150   -
  152 + u32 bswapmask = fb_compute_bswapmask(p);
  153 +
151 154 dst2 = (u32 __iomem *) dst1;
152 155 fgcolor <<= FB_LEFT_POS(bpp);
153 156 bgcolor <<= FB_LEFT_POS(bpp);
... ... @@ -161,7 +164,7 @@
161 164  
162 165 /* write leading bits */
163 166 if (start_index) {
164   - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
  167 + u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
165 168 val = FB_READL(dst) & start_mask;
166 169 shift = start_index;
167 170 }
... ... @@ -169,7 +172,7 @@
169 172 while (j--) {
170 173 l--;
171 174 color = (*s & (1 << l)) ? fgcolor : bgcolor;
172   - val |= FB_SHIFT_HIGH(color, shift);
  175 + val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
173 176  
174 177 /* Did the bitshift spill bits to the next long? */
175 178 if (shift >= null_bits) {
... ... @@ -184,7 +187,7 @@
184 187  
185 188 /* write trailing bits */
186 189 if (shift) {
187   - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
  190 + u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
188 191  
189 192 FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
190 193 }
drivers/video/fb_draw.h
... ... @@ -2,6 +2,7 @@
2 2 #define _FB_DRAW_H
3 3  
4 4 #include <asm/types.h>
  5 +#include <linux/fb.h>
5 6  
6 7 /*
7 8 * Compose two values, using a bitmask as decision value
... ... @@ -69,5 +70,72 @@
69 70 }
70 71 }
71 72 #endif
  73 +
  74 +#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE
  75 +
  76 +static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
  77 +{
  78 + u32 mask;
  79 +
  80 + if (!bswapmask) {
  81 + mask = FB_SHIFT_HIGH(~(u32)0, index);
  82 + } else {
  83 + mask = 0xff << FB_LEFT_POS(8);
  84 + mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
  85 + mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
  86 +#if defined(__i386__) || defined(__x86_64__)
  87 + /* Shift argument is limited to 0 - 31 on x86 based CPU's */
  88 + if(index + bswapmask < 32)
  89 +#endif
  90 + mask |= FB_SHIFT_HIGH(~(u32)0,
  91 + (index + bswapmask) & ~(bswapmask));
  92 + }
  93 + return mask;
  94 +}
  95 +
  96 +static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask)
  97 +{
  98 + unsigned long mask;
  99 +
  100 + if (!bswapmask) {
  101 + mask = FB_SHIFT_HIGH(~0UL, index);
  102 + } else {
  103 + mask = 0xff << FB_LEFT_POS(8);
  104 + mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
  105 + mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
  106 +#if defined(__i386__) || defined(__x86_64__)
  107 + /* Shift argument is limited to 0 - 31 on x86 based CPU's */
  108 + if(index + bswapmask < BITS_PER_LONG)
  109 +#endif
  110 + mask |= FB_SHIFT_HIGH(~0UL,
  111 + (index + bswapmask) & ~(bswapmask));
  112 + }
  113 + return mask;
  114 +}
  115 +
  116 +
  117 +static inline u32 fb_compute_bswapmask(struct fb_info *info)
  118 +{
  119 + u32 bswapmask = 0;
  120 + unsigned bpp = info->var.bits_per_pixel;
  121 +
  122 + if ((bpp < 8) && (info->var.nonstd & FB_NONSTD_REV_PIX_IN_B)) {
  123 + /*
  124 + * Reversed order of pixel layout in bytes
  125 + * works only for 1, 2 and 4 bpp
  126 + */
  127 + bswapmask = 7 - bpp + 1;
  128 + }
  129 + return bswapmask;
  130 +}
  131 +
  132 +#else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
  133 +
  134 +#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i))
  135 +#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i))
  136 +#define fb_compute_bswapmask(...) 0
  137 +
  138 +#endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
  139 +
72 140 #endif /* FB_DRAW_H */
... ... @@ -180,6 +180,7 @@
180 180 };
181 181  
182 182 #define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */
  183 +#define FB_NONSTD_REV_PIX_IN_B 2 /* order of pixels in each byte is reversed */
183 184  
184 185 #define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/
185 186 #define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */