Commit e4c690e061b909127ab0f12e929f82f3f39ec953

Authored by Anton Vorontsov
Committed by Linus Torvalds
1 parent 6b745b6fd0

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: Anton 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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 10 changed files with 228 additions and 140 deletions Side-by-side Diff

drivers/video/Kconfig
... ... @@ -139,6 +139,30 @@
139 139 blitting. This is used by drivers that don't provide their own
140 140 (accelerated) version and the framebuffer is in system RAM.
141 141  
  142 +menuconfig FB_FOREIGN_ENDIAN
  143 + bool "Framebuffer foreign endianness support"
  144 + depends on FB
  145 + ---help---
  146 + This menu will let you enable support for the framebuffers with
  147 + non-native endianness (e.g. Little-Endian framebuffer on a
  148 + Big-Endian machine). Most probably you don't have such hardware,
  149 + so it's safe to say "n" here.
  150 +
  151 +choice
  152 + prompt "Choice endianness support"
  153 + depends on FB_FOREIGN_ENDIAN
  154 +
  155 +config FB_BOTH_ENDIAN
  156 + bool "Support for Big- and Little-Endian framebuffers"
  157 +
  158 +config FB_BIG_ENDIAN
  159 + bool "Support for Big-Endian framebuffers only"
  160 +
  161 +config FB_LITTLE_ENDIAN
  162 + bool "Support for Little-Endian framebuffers only"
  163 +
  164 +endchoice
  165 +
142 166 config FB_SYS_FOPS
143 167 tristate
144 168 depends on FB
drivers/video/cfbcopyarea.c
... ... @@ -44,15 +44,16 @@
44 44 */
45 45  
46 46 static void
47   -bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
48   - int src_idx, int bits, unsigned n, u32 bswapmask)
  47 +bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
  48 + const unsigned long __iomem *src, int src_idx, int bits,
  49 + unsigned n, u32 bswapmask)
49 50 {
50 51 unsigned long first, last;
51 52 int const shift = dst_idx-src_idx;
52 53 int left, right;
53 54  
54   - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
55   - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
  55 + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
  56 + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
56 57  
57 58 if (!shift) {
58 59 // Same alignment for source and dest
... ... @@ -202,8 +203,9 @@
202 203 */
203 204  
204 205 static void
205   -bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
206   - int src_idx, int bits, unsigned n, u32 bswapmask)
  206 +bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
  207 + const unsigned long __iomem *src, int src_idx, int bits,
  208 + unsigned n, u32 bswapmask)
207 209 {
208 210 unsigned long first, last;
209 211 int shift;
... ... @@ -221,8 +223,9 @@
221 223  
222 224 shift = dst_idx-src_idx;
223 225  
224   - first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask);
225   - last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask);
  226 + first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
  227 + last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
  228 + bswapmask);
226 229  
227 230 if (!shift) {
228 231 // Same alignment for source and dest
... ... @@ -404,7 +407,7 @@
404 407 dst_idx &= (bytes - 1);
405 408 src += src_idx >> (ffs(bits) - 1);
406 409 src_idx &= (bytes - 1);
407   - bitcpy_rev(dst, dst_idx, src, src_idx, bits,
  410 + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
408 411 width*p->var.bits_per_pixel, bswapmask);
409 412 }
410 413 } else {
... ... @@ -413,7 +416,7 @@
413 416 dst_idx &= (bytes - 1);
414 417 src += src_idx >> (ffs(bits) - 1);
415 418 src_idx &= (bytes - 1);
416   - bitcpy(dst, dst_idx, src, src_idx, bits,
  419 + bitcpy(p, dst, dst_idx, src, src_idx, bits,
417 420 width*p->var.bits_per_pixel, bswapmask);
418 421 dst_idx += bits_per_line;
419 422 src_idx += bits_per_line;
drivers/video/cfbfillrect.c
... ... @@ -36,16 +36,16 @@
36 36 */
37 37  
38 38 static void
39   -bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
40   - unsigned n, int bits, u32 bswapmask)
  39 +bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
  40 + unsigned long pat, unsigned n, int bits, u32 bswapmask)
41 41 {
42 42 unsigned long first, last;
43 43  
44 44 if (!n)
45 45 return;
46 46  
47   - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
48   - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
  47 + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
  48 + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
49 49  
50 50 if (dst_idx+n <= bits) {
51 51 // Single word
52 52  
... ... @@ -93,16 +93,16 @@
93 93 */
94 94  
95 95 static void
96   -bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
97   - int left, int right, unsigned n, int bits)
  96 +bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
  97 + unsigned long pat, int left, int right, unsigned n, int bits)
98 98 {
99 99 unsigned long first, last;
100 100  
101 101 if (!n)
102 102 return;
103 103  
104   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
105   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  104 + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  105 + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
106 106  
107 107 if (dst_idx+n <= bits) {
108 108 // Single word
... ... @@ -147,8 +147,9 @@
147 147 * Aligned pattern invert using 32/64-bit memory accesses
148 148 */
149 149 static void
150   -bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
151   - unsigned n, int bits, u32 bswapmask)
  150 +bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
  151 + int dst_idx, unsigned long pat, unsigned n, int bits,
  152 + u32 bswapmask)
152 153 {
153 154 unsigned long val = pat, dat;
154 155 unsigned long first, last;
... ... @@ -156,8 +157,8 @@
156 157 if (!n)
157 158 return;
158 159  
159   - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
160   - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
  160 + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
  161 + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
161 162  
162 163 if (dst_idx+n <= bits) {
163 164 // Single word
164 165  
... ... @@ -217,16 +218,17 @@
217 218 */
218 219  
219 220 static void
220   -bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
221   - int left, int right, unsigned n, int bits)
  221 +bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
  222 + int dst_idx, unsigned long pat, int left, int right,
  223 + unsigned n, int bits)
222 224 {
223 225 unsigned long first, last, dat;
224 226  
225 227 if (!n)
226 228 return;
227 229  
228   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
229   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  230 + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  231 + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
230 232  
231 233 if (dst_idx+n <= bits) {
232 234 // Single word
... ... @@ -306,7 +308,8 @@
306 308 p->fbops->fb_sync(p);
307 309 if (!left) {
308 310 u32 bswapmask = fb_compute_bswapmask(p);
309   - void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
  311 + void (*fill_op32)(struct fb_info *p,
  312 + unsigned long __iomem *dst, int dst_idx,
310 313 unsigned long pat, unsigned n, int bits,
311 314 u32 bswapmask) = NULL;
312 315  
313 316  
... ... @@ -325,16 +328,17 @@
325 328 while (height--) {
326 329 dst += dst_idx >> (ffs(bits) - 1);
327 330 dst_idx &= (bits - 1);
328   - fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask);
  331 + fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
  332 + bswapmask);
329 333 dst_idx += p->fix.line_length*8;
330 334 }
331 335 } else {
332 336 int right;
333 337 int r;
334 338 int rot = (left-dst_idx) % bpp;
335   - void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
336   - unsigned long pat, int left, int right,
337   - unsigned n, int bits) = NULL;
  339 + void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
  340 + int dst_idx, unsigned long pat, int left,
  341 + int right, unsigned n, int bits) = NULL;
338 342  
339 343 /* rotate pattern to correct start position */
340 344 pat = pat << rot | pat >> (bpp-rot);
... ... @@ -355,7 +359,7 @@
355 359 while (height--) {
356 360 dst += dst_idx >> (ffs(bits) - 1);
357 361 dst_idx &= (bits - 1);
358   - fill_op(dst, dst_idx, pat, left, right,
  362 + fill_op(p, dst, dst_idx, pat, left, right,
359 363 width*bpp, bits);
360 364 r = (p->fix.line_length*8) % bpp;
361 365 pat = pat << (bpp-r) | pat >> r;
drivers/video/cfbimgblt.c
... ... @@ -43,30 +43,26 @@
43 43 #define DPRINTK(fmt, args...)
44 44 #endif
45 45  
46   -static const u32 cfb_tab8[] = {
47   -#if defined(__BIG_ENDIAN)
  46 +static const u32 cfb_tab8_be[] = {
48 47 0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
49 48 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
50 49 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
51 50 0xffff0000,0xffff00ff,0xffffff00,0xffffffff
52   -#elif defined(__LITTLE_ENDIAN)
  51 +};
  52 +
  53 +static const u32 cfb_tab8_le[] = {
53 54 0x00000000,0xff000000,0x00ff0000,0xffff0000,
54 55 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
55 56 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
56 57 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
57   -#else
58   -#error FIXME: No endianness??
59   -#endif
60 58 };
61 59  
62   -static const u32 cfb_tab16[] = {
63   -#if defined(__BIG_ENDIAN)
  60 +static const u32 cfb_tab16_be[] = {
64 61 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
65   -#elif defined(__LITTLE_ENDIAN)
  62 +};
  63 +
  64 +static const u32 cfb_tab16_le[] = {
66 65 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
67   -#else
68   -#error FIXME: No endianness??
69   -#endif
70 66 };
71 67  
72 68 static const u32 cfb_tab32[] = {
... ... @@ -98,7 +94,8 @@
98 94 val = 0;
99 95  
100 96 if (start_index) {
101   - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
  97 + u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
  98 + start_index, bswapmask);
102 99 val = FB_READL(dst) & start_mask;
103 100 shift = start_index;
104 101 }
105 102  
106 103  
... ... @@ -108,20 +105,21 @@
108 105 color = palette[*src];
109 106 else
110 107 color = *src;
111   - color <<= FB_LEFT_POS(bpp);
112   - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
  108 + color <<= FB_LEFT_POS(p, bpp);
  109 + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
113 110 if (shift >= null_bits) {
114 111 FB_WRITEL(val, dst++);
115 112  
116 113 val = (shift == null_bits) ? 0 :
117   - FB_SHIFT_LOW(color, 32 - shift);
  114 + FB_SHIFT_LOW(p, color, 32 - shift);
118 115 }
119 116 shift += bpp;
120 117 shift &= (32 - 1);
121 118 src++;
122 119 }
123 120 if (shift) {
124   - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
  121 + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
  122 + bswapmask);
125 123  
126 124 FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
127 125 }
... ... @@ -152,8 +150,8 @@
152 150 u32 bswapmask = fb_compute_bswapmask(p);
153 151  
154 152 dst2 = (u32 __iomem *) dst1;
155   - fgcolor <<= FB_LEFT_POS(bpp);
156   - bgcolor <<= FB_LEFT_POS(bpp);
  153 + fgcolor <<= FB_LEFT_POS(p, bpp);
  154 + bgcolor <<= FB_LEFT_POS(p, bpp);
157 155  
158 156 for (i = image->height; i--; ) {
159 157 shift = val = 0;
... ... @@ -164,7 +162,8 @@
164 162  
165 163 /* write leading bits */
166 164 if (start_index) {
167   - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
  165 + u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
  166 + start_index, bswapmask);
168 167 val = FB_READL(dst) & start_mask;
169 168 shift = start_index;
170 169 }
171 170  
... ... @@ -172,13 +171,13 @@
172 171 while (j--) {
173 172 l--;
174 173 color = (*s & (1 << l)) ? fgcolor : bgcolor;
175   - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
  174 + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
176 175  
177 176 /* Did the bitshift spill bits to the next long? */
178 177 if (shift >= null_bits) {
179 178 FB_WRITEL(val, dst++);
180 179 val = (shift == null_bits) ? 0 :
181   - FB_SHIFT_LOW(color,32 - shift);
  180 + FB_SHIFT_LOW(p, color, 32 - shift);
182 181 }
183 182 shift += bpp;
184 183 shift &= (32 - 1);
... ... @@ -187,7 +186,8 @@
187 186  
188 187 /* write trailing bits */
189 188 if (shift) {
190   - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
  189 + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
  190 + bswapmask);
191 191  
192 192 FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
193 193 }
194 194  
195 195  
... ... @@ -223,13 +223,13 @@
223 223 u32 __iomem *dst;
224 224 const u32 *tab = NULL;
225 225 int i, j, k;
226   -
  226 +
227 227 switch (bpp) {
228 228 case 8:
229   - tab = cfb_tab8;
  229 + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
230 230 break;
231 231 case 16:
232   - tab = cfb_tab16;
  232 + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
233 233 break;
234 234 case 32:
235 235 default:
drivers/video/fb_draw.h
... ... @@ -94,41 +94,44 @@
94 94 return val;
95 95 }
96 96  
97   -static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
  97 +static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index,
  98 + u32 bswapmask)
98 99 {
99 100 u32 mask;
100 101  
101 102 if (!bswapmask) {
102   - mask = FB_SHIFT_HIGH(~(u32)0, index);
  103 + mask = FB_SHIFT_HIGH(p, ~(u32)0, index);
103 104 } else {
104   - mask = 0xff << FB_LEFT_POS(8);
105   - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
106   - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
  105 + mask = 0xff << FB_LEFT_POS(p, 8);
  106 + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
  107 + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
107 108 #if defined(__i386__) || defined(__x86_64__)
108 109 /* Shift argument is limited to 0 - 31 on x86 based CPU's */
109 110 if(index + bswapmask < 32)
110 111 #endif
111   - mask |= FB_SHIFT_HIGH(~(u32)0,
  112 + mask |= FB_SHIFT_HIGH(p, ~(u32)0,
112 113 (index + bswapmask) & ~(bswapmask));
113 114 }
114 115 return mask;
115 116 }
116 117  
117   -static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask)
  118 +static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p,
  119 + u32 index,
  120 + u32 bswapmask)
118 121 {
119 122 unsigned long mask;
120 123  
121 124 if (!bswapmask) {
122   - mask = FB_SHIFT_HIGH(~0UL, index);
  125 + mask = FB_SHIFT_HIGH(p, ~0UL, index);
123 126 } else {
124   - mask = 0xff << FB_LEFT_POS(8);
125   - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
126   - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
  127 + mask = 0xff << FB_LEFT_POS(p, 8);
  128 + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
  129 + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
127 130 #if defined(__i386__) || defined(__x86_64__)
128 131 /* Shift argument is limited to 0 - 31 on x86 based CPU's */
129 132 if(index + bswapmask < BITS_PER_LONG)
130 133 #endif
131   - mask |= FB_SHIFT_HIGH(~0UL,
  134 + mask |= FB_SHIFT_HIGH(p, ~0UL,
132 135 (index + bswapmask) & ~(bswapmask));
133 136 }
134 137 return mask;
... ... @@ -158,8 +161,8 @@
158 161 return val;
159 162 }
160 163  
161   -#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i))
162   -#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i))
  164 +#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i))
  165 +#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i))
163 166 #define fb_compute_bswapmask(...) 0
164 167  
165 168 #endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
drivers/video/fbmem.c
... ... @@ -1352,6 +1352,32 @@
1352 1352  
1353 1353 struct class *fb_class;
1354 1354 EXPORT_SYMBOL(fb_class);
  1355 +
  1356 +static int fb_check_foreignness(struct fb_info *fi)
  1357 +{
  1358 + const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
  1359 +
  1360 + fi->flags &= ~FBINFO_FOREIGN_ENDIAN;
  1361 +
  1362 +#ifdef __BIG_ENDIAN
  1363 + fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH;
  1364 +#else
  1365 + fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0;
  1366 +#endif /* __BIG_ENDIAN */
  1367 +
  1368 + if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) {
  1369 + pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to "
  1370 + "support this framebuffer\n", fi->fix.id);
  1371 + return -ENOSYS;
  1372 + } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) {
  1373 + pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to "
  1374 + "support this framebuffer\n", fi->fix.id);
  1375 + return -ENOSYS;
  1376 + }
  1377 +
  1378 + return 0;
  1379 +}
  1380 +
1355 1381 /**
1356 1382 * register_framebuffer - registers a frame buffer device
1357 1383 * @fb_info: frame buffer info structure
... ... @@ -1371,6 +1397,10 @@
1371 1397  
1372 1398 if (num_registered_fb == FB_MAX)
1373 1399 return -ENXIO;
  1400 +
  1401 + if (fb_check_foreignness(fb_info))
  1402 + return -ENOSYS;
  1403 +
1374 1404 num_registered_fb++;
1375 1405 for (i = 0 ; i < FB_MAX; i++)
1376 1406 if (!registered_fb[i])
drivers/video/syscopyarea.c
... ... @@ -26,15 +26,15 @@
26 26 */
27 27  
28 28 static void
29   -bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
30   - int src_idx, int bits, unsigned n)
  29 +bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
  30 + const unsigned long *src, int src_idx, int bits, unsigned n)
31 31 {
32 32 unsigned long first, last;
33 33 int const shift = dst_idx-src_idx;
34 34 int left, right;
35 35  
36   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
37   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  36 + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  37 + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
38 38  
39 39 if (!shift) {
40 40 /* Same alignment for source and dest */
... ... @@ -167,8 +167,8 @@
167 167 */
168 168  
169 169 static void
170   -bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src,
171   - int src_idx, int bits, unsigned n)
  170 +bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
  171 + const unsigned long *src, int src_idx, int bits, unsigned n)
172 172 {
173 173 unsigned long first, last;
174 174 int shift;
... ... @@ -186,8 +186,8 @@
186 186  
187 187 shift = dst_idx-src_idx;
188 188  
189   - first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
190   - last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
  189 + first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx);
  190 + last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits)));
191 191  
192 192 if (!shift) {
193 193 /* Same alignment for source and dest */
... ... @@ -353,7 +353,7 @@
353 353 dst_idx &= (bytes - 1);
354 354 src += src_idx >> (ffs(bits) - 1);
355 355 src_idx &= (bytes - 1);
356   - bitcpy_rev(dst, dst_idx, src, src_idx, bits,
  356 + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
357 357 width*p->var.bits_per_pixel);
358 358 }
359 359 } else {
... ... @@ -362,7 +362,7 @@
362 362 dst_idx &= (bytes - 1);
363 363 src += src_idx >> (ffs(bits) - 1);
364 364 src_idx &= (bytes - 1);
365   - bitcpy(dst, dst_idx, src, src_idx, bits,
  365 + bitcpy(p, dst, dst_idx, src, src_idx, bits,
366 366 width*p->var.bits_per_pixel);
367 367 dst_idx += bits_per_line;
368 368 src_idx += bits_per_line;
drivers/video/sysfillrect.c
... ... @@ -22,16 +22,16 @@
22 22 */
23 23  
24 24 static void
25   -bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat,
26   - unsigned n, int bits)
  25 +bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx,
  26 + unsigned long pat, unsigned n, int bits)
27 27 {
28 28 unsigned long first, last;
29 29  
30 30 if (!n)
31 31 return;
32 32  
33   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
34   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  33 + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  34 + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
35 35  
36 36 if (dst_idx+n <= bits) {
37 37 /* Single word */
38 38  
... ... @@ -78,16 +78,16 @@
78 78 */
79 79  
80 80 static void
81   -bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat,
82   - int left, int right, unsigned n, int bits)
  81 +bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
  82 + unsigned long pat, int left, int right, unsigned n, int bits)
83 83 {
84 84 unsigned long first, last;
85 85  
86 86 if (!n)
87 87 return;
88 88  
89   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
90   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  89 + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  90 + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
91 91  
92 92 if (dst_idx+n <= bits) {
93 93 /* Single word */
... ... @@ -132,8 +132,8 @@
132 132 * Aligned pattern invert using 32/64-bit memory accesses
133 133 */
134 134 static void
135   -bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
136   - unsigned n, int bits)
  135 +bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
  136 + unsigned long pat, unsigned n, int bits)
137 137 {
138 138 unsigned long val = pat;
139 139 unsigned long first, last;
... ... @@ -141,8 +141,8 @@
141 141 if (!n)
142 142 return;
143 143  
144   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
145   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  144 + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  145 + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
146 146  
147 147 if (dst_idx+n <= bits) {
148 148 /* Single word */
149 149  
... ... @@ -188,16 +188,17 @@
188 188 */
189 189  
190 190 static void
191   -bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
192   - int left, int right, unsigned n, int bits)
  191 +bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
  192 + unsigned long pat, int left, int right, unsigned n,
  193 + int bits)
193 194 {
194 195 unsigned long first, last;
195 196  
196 197 if (!n)
197 198 return;
198 199  
199   - first = FB_SHIFT_HIGH(~0UL, dst_idx);
200   - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  200 + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  201 + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
201 202  
202 203 if (dst_idx+n <= bits) {
203 204 /* Single word */
... ... @@ -267,9 +268,9 @@
267 268 if (p->fbops->fb_sync)
268 269 p->fbops->fb_sync(p);
269 270 if (!left) {
270   - void (*fill_op32)(unsigned long *dst, int dst_idx,
271   - unsigned long pat, unsigned n, int bits) =
272   - NULL;
  271 + void (*fill_op32)(struct fb_info *p, unsigned long *dst,
  272 + int dst_idx, unsigned long pat, unsigned n,
  273 + int bits) = NULL;
273 274  
274 275 switch (rect->rop) {
275 276 case ROP_XOR:
276 277  
... ... @@ -287,16 +288,16 @@
287 288 while (height--) {
288 289 dst += dst_idx >> (ffs(bits) - 1);
289 290 dst_idx &= (bits - 1);
290   - fill_op32(dst, dst_idx, pat, width*bpp, bits);
  291 + fill_op32(p, dst, dst_idx, pat, width*bpp, bits);
291 292 dst_idx += p->fix.line_length*8;
292 293 }
293 294 } else {
294 295 int right;
295 296 int r;
296 297 int rot = (left-dst_idx) % bpp;
297   - void (*fill_op)(unsigned long *dst, int dst_idx,
298   - unsigned long pat, int left, int right,
299   - unsigned n, int bits) = NULL;
  298 + void (*fill_op)(struct fb_info *p, unsigned long *dst,
  299 + int dst_idx, unsigned long pat, int left,
  300 + int right, unsigned n, int bits) = NULL;
300 301  
301 302 /* rotate pattern to correct start position */
302 303 pat = pat << rot | pat >> (bpp-rot);
... ... @@ -318,7 +319,7 @@
318 319 while (height--) {
319 320 dst += dst_idx >> (ffs(bits) - 1);
320 321 dst_idx &= (bits - 1);
321   - fill_op(dst, dst_idx, pat, left, right,
  322 + fill_op(p, dst, dst_idx, pat, left, right,
322 323 width*bpp, bits);
323 324 r = (p->fix.line_length*8) % bpp;
324 325 pat = pat << (bpp-r) | pat >> r;
drivers/video/sysimgblt.c
... ... @@ -23,30 +23,26 @@
23 23 #define DPRINTK(fmt, args...)
24 24 #endif
25 25  
26   -static const u32 cfb_tab8[] = {
27   -#if defined(__BIG_ENDIAN)
  26 +static const u32 cfb_tab8_be[] = {
28 27 0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
29 28 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
30 29 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
31 30 0xffff0000,0xffff00ff,0xffffff00,0xffffffff
32   -#elif defined(__LITTLE_ENDIAN)
  31 +};
  32 +
  33 +static const u32 cfb_tab8_le[] = {
33 34 0x00000000,0xff000000,0x00ff0000,0xffff0000,
34 35 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
35 36 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
36 37 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
37   -#else
38   -#error FIXME: No endianness??
39   -#endif
40 38 };
41 39  
42   -static const u32 cfb_tab16[] = {
43   -#if defined(__BIG_ENDIAN)
  40 +static const u32 cfb_tab16_be[] = {
44 41 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
45   -#elif defined(__LITTLE_ENDIAN)
  42 +};
  43 +
  44 +static const u32 cfb_tab16_le[] = {
46 45 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
47   -#else
48   -#error FIXME: No endianness??
49   -#endif
50 46 };
51 47  
52 48 static const u32 cfb_tab32[] = {
... ... @@ -72,7 +68,7 @@
72 68 val = 0;
73 69  
74 70 if (start_index) {
75   - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,
  71 + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
76 72 start_index));
77 73 val = *dst & start_mask;
78 74 shift = start_index;
79 75  
80 76  
... ... @@ -83,20 +79,20 @@
83 79 color = palette[*src];
84 80 else
85 81 color = *src;
86   - color <<= FB_LEFT_POS(bpp);
87   - val |= FB_SHIFT_HIGH(color, shift);
  82 + color <<= FB_LEFT_POS(p, bpp);
  83 + val |= FB_SHIFT_HIGH(p, color, shift);
88 84 if (shift >= null_bits) {
89 85 *dst++ = val;
90 86  
91 87 val = (shift == null_bits) ? 0 :
92   - FB_SHIFT_LOW(color, 32 - shift);
  88 + FB_SHIFT_LOW(p, color, 32 - shift);
93 89 }
94 90 shift += bpp;
95 91 shift &= (32 - 1);
96 92 src++;
97 93 }
98 94 if (shift) {
99   - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
  95 + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
100 96  
101 97 *dst &= end_mask;
102 98 *dst |= val;
... ... @@ -125,8 +121,8 @@
125 121 u32 i, j, l;
126 122  
127 123 dst2 = dst1;
128   - fgcolor <<= FB_LEFT_POS(bpp);
129   - bgcolor <<= FB_LEFT_POS(bpp);
  124 + fgcolor <<= FB_LEFT_POS(p, bpp);
  125 + bgcolor <<= FB_LEFT_POS(p, bpp);
130 126  
131 127 for (i = image->height; i--; ) {
132 128 shift = val = 0;
... ... @@ -137,7 +133,8 @@
137 133  
138 134 /* write leading bits */
139 135 if (start_index) {
140   - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
  136 + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
  137 + start_index));
141 138 val = *dst & start_mask;
142 139 shift = start_index;
143 140 }
144 141  
... ... @@ -145,13 +142,13 @@
145 142 while (j--) {
146 143 l--;
147 144 color = (*s & (1 << l)) ? fgcolor : bgcolor;
148   - val |= FB_SHIFT_HIGH(color, shift);
  145 + val |= FB_SHIFT_HIGH(p, color, shift);
149 146  
150 147 /* Did the bitshift spill bits to the next long? */
151 148 if (shift >= null_bits) {
152 149 *dst++ = val;
153 150 val = (shift == null_bits) ? 0 :
154   - FB_SHIFT_LOW(color,32 - shift);
  151 + FB_SHIFT_LOW(p, color, 32 - shift);
155 152 }
156 153 shift += bpp;
157 154 shift &= (32 - 1);
... ... @@ -160,7 +157,7 @@
160 157  
161 158 /* write trailing bits */
162 159 if (shift) {
163   - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
  160 + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
164 161  
165 162 *dst &= end_mask;
166 163 *dst |= val;
167 164  
... ... @@ -199,10 +196,10 @@
199 196  
200 197 switch (bpp) {
201 198 case 8:
202   - tab = cfb_tab8;
  199 + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
203 200 break;
204 201 case 16:
205   - tab = cfb_tab16;
  202 + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
206 203 break;
207 204 case 32:
208 205 default:
... ... @@ -791,6 +791,17 @@
791 791 */
792 792 #define FBINFO_MISC_ALWAYS_SETPAR 0x40000
793 793  
  794 +/*
  795 + * Host and GPU endianness differ.
  796 + */
  797 +#define FBINFO_FOREIGN_ENDIAN 0x100000
  798 +/*
  799 + * Big endian math. This is the same flags as above, but with different
  800 + * meaning, it is set by the fb subsystem depending FOREIGN_ENDIAN flag
  801 + * and host endianness. Drivers should not use this flag.
  802 + */
  803 +#define FBINFO_BE_MATH 0x100000
  804 +
794 805 struct fb_info {
795 806 int node;
796 807 int flags;
... ... @@ -899,15 +910,11 @@
899 910  
900 911 #endif
901 912  
902   -#if defined (__BIG_ENDIAN)
903   -#define FB_LEFT_POS(bpp) (32 - bpp)
904   -#define FB_SHIFT_HIGH(val, bits) ((val) >> (bits))
905   -#define FB_SHIFT_LOW(val, bits) ((val) << (bits))
906   -#else
907   -#define FB_LEFT_POS(bpp) (0)
908   -#define FB_SHIFT_HIGH(val, bits) ((val) << (bits))
909   -#define FB_SHIFT_LOW(val, bits) ((val) >> (bits))
910   -#endif
  913 +#define FB_LEFT_POS(p, bpp) (fb_be_math(p) ? (32 - (bpp)) : 0)
  914 +#define FB_SHIFT_HIGH(p, val, bits) (fb_be_math(p) ? (val) >> (bits) : \
  915 + (val) << (bits))
  916 +#define FB_SHIFT_LOW(p, val, bits) (fb_be_math(p) ? (val) << (bits) : \
  917 + (val) >> (bits))
911 918  
912 919 /*
913 920 * `Generic' versions of the frame buffer device operations
... ... @@ -969,6 +976,25 @@
969 976 extern void fb_deferred_io_cleanup(struct fb_info *info);
970 977 extern int fb_deferred_io_fsync(struct file *file, struct dentry *dentry,
971 978 int datasync);
  979 +
  980 +static inline bool fb_be_math(struct fb_info *info)
  981 +{
  982 +#ifdef CONFIG_FB_FOREIGN_ENDIAN
  983 +#if defined(CONFIG_FB_BOTH_ENDIAN)
  984 + return info->flags & FBINFO_BE_MATH;
  985 +#elif defined(CONFIG_FB_BIG_ENDIAN)
  986 + return true;
  987 +#elif defined(CONFIG_FB_LITTLE_ENDIAN)
  988 + return false;
  989 +#endif /* CONFIG_FB_BOTH_ENDIAN */
  990 +#else
  991 +#ifdef __BIG_ENDIAN
  992 + return true;
  993 +#else
  994 + return false;
  995 +#endif /* __BIG_ENDIAN */
  996 +#endif /* CONFIG_FB_FOREIGN_ENDIAN */
  997 +}
972 998  
973 999 /* drivers/video/fbsysfs.c */
974 1000 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);