aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorPavel Pisa <pisa@cmp.felk.cvut.cz>2007-10-16 04:29:21 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:19 -0400
commit779121e9f17525769c04a00475fd85600c8c04eb (patch)
tree757aad067bed869bfdd2dc2eb2f652a7f4e5e071 /drivers/video
parent3c03ec209af1dd8223888630482f1b2353dc6284 (diff)
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>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig9
-rw-r--r--drivers/video/cfbcopyarea.c17
-rw-r--r--drivers/video/cfbfillrect.c20
-rw-r--r--drivers/video/cfbimgblt.c17
-rw-r--r--drivers/video/fb_draw.h68
5 files changed, 108 insertions, 23 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index f1cc8996456f..5c1ef0938006 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -103,6 +103,15 @@ config FB_CFB_IMAGEBLIT
103 blitting. This is used by drivers that don't provide their own 103 blitting. This is used by drivers that don't provide their own
104 (accelerated) version. 104 (accelerated) version.
105 105
106config 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
106config FB_SYS_FILLRECT 115config FB_SYS_FILLRECT
107 tristate 116 tristate
108 depends on FB 117 depends on FB
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
index 032210f45be3..1c67885a1f4f 100644
--- a/drivers/video/cfbcopyarea.c
+++ b/drivers/video/cfbcopyarea.c
@@ -45,14 +45,14 @@
45 45
46static void 46static void
47bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, 47bitcpy(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 unsigned long first, last; 50 unsigned long first, last;
51 int const shift = dst_idx-src_idx; 51 int const shift = dst_idx-src_idx;
52 int left, right; 52 int left, right;
53 53
54 first = FB_SHIFT_HIGH(~0UL, dst_idx); 54 first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
55 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 55 last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
56 56
57 if (!shift) { 57 if (!shift) {
58 // Same alignment for source and dest 58 // Same alignment for source and dest
@@ -185,7 +185,7 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
185 185
186static void 186static void
187bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, 187bitcpy_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 unsigned long first, last; 190 unsigned long first, last;
191 int shift; 191 int shift;
@@ -203,8 +203,8 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
203 203
204 shift = dst_idx-src_idx; 204 shift = dst_idx-src_idx;
205 205
206 first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx); 206 first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask);
207 last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits))); 207 last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask);
208 208
209 if (!shift) { 209 if (!shift) {
210 // Same alignment for source and dest 210 // Same alignment for source and dest
@@ -336,6 +336,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
336 unsigned long __iomem *dst = NULL, *src = NULL; 336 unsigned long __iomem *dst = NULL, *src = NULL;
337 int bits = BITS_PER_LONG, bytes = bits >> 3; 337 int bits = BITS_PER_LONG, bytes = bits >> 3;
338 int dst_idx = 0, src_idx = 0, rev_copy = 0; 338 int dst_idx = 0, src_idx = 0, rev_copy = 0;
339 u32 bswapmask = fb_compute_bswapmask(p);
339 340
340 if (p->state != FBINFO_STATE_RUNNING) 341 if (p->state != FBINFO_STATE_RUNNING)
341 return; 342 return;
@@ -368,7 +369,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
368 src += src_idx >> (ffs(bits) - 1); 369 src += src_idx >> (ffs(bits) - 1);
369 src_idx &= (bytes - 1); 370 src_idx &= (bytes - 1);
370 bitcpy_rev(dst, dst_idx, src, src_idx, bits, 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 } else { 374 } else {
374 while (height--) { 375 while (height--) {
@@ -377,7 +378,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
377 src += src_idx >> (ffs(bits) - 1); 378 src += src_idx >> (ffs(bits) - 1);
378 src_idx &= (bytes - 1); 379 src_idx &= (bytes - 1);
379 bitcpy(dst, dst_idx, src, src_idx, bits, 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 dst_idx += bits_per_line; 382 dst_idx += bits_per_line;
382 src_idx += bits_per_line; 383 src_idx += bits_per_line;
383 } 384 }
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index 71623b4f8ca2..23d70a12e4da 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -36,15 +36,16 @@
36 */ 36 */
37 37
38static void 38static void
39bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) 39bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
40 unsigned n, int bits, u32 bswapmask)
40{ 41{
41 unsigned long first, last; 42 unsigned long first, last;
42 43
43 if (!n) 44 if (!n)
44 return; 45 return;
45 46
46 first = FB_SHIFT_HIGH(~0UL, dst_idx); 47 first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
47 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 48 last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
48 49
49 if (dst_idx+n <= bits) { 50 if (dst_idx+n <= bits) {
50 // Single word 51 // Single word
@@ -146,7 +147,8 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
146 * Aligned pattern invert using 32/64-bit memory accesses 147 * Aligned pattern invert using 32/64-bit memory accesses
147 */ 148 */
148static void 149static void
149bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) 150bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
151 unsigned n, int bits, u32 bswapmask)
150{ 152{
151 unsigned long val = pat, dat; 153 unsigned long val = pat, dat;
152 unsigned long first, last; 154 unsigned long first, last;
@@ -154,8 +156,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
154 if (!n) 156 if (!n)
155 return; 157 return;
156 158
157 first = FB_SHIFT_HIGH(~0UL, dst_idx); 159 first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
158 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 160 last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
159 161
160 if (dst_idx+n <= bits) { 162 if (dst_idx+n <= bits) {
161 // Single word 163 // Single word
@@ -303,8 +305,10 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
303 if (p->fbops->fb_sync) 305 if (p->fbops->fb_sync)
304 p->fbops->fb_sync(p); 306 p->fbops->fb_sync(p);
305 if (!left) { 307 if (!left) {
308 u32 bswapmask = fb_compute_bswapmask(p);
306 void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, 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 switch (rect->rop) { 313 switch (rect->rop) {
310 case ROP_XOR: 314 case ROP_XOR:
@@ -321,7 +325,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
321 while (height--) { 325 while (height--) {
322 dst += dst_idx >> (ffs(bits) - 1); 326 dst += dst_idx >> (ffs(bits) - 1);
323 dst_idx &= (bits - 1); 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 dst_idx += p->fix.line_length*8; 329 dst_idx += p->fix.line_length*8;
326 } 330 }
327 } else { 331 } else {
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index 261004473c8e..f598907b42ad 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -33,6 +33,7 @@
33#include <linux/string.h> 33#include <linux/string.h>
34#include <linux/fb.h> 34#include <linux/fb.h>
35#include <asm/types.h> 35#include <asm/types.h>
36#include "fb_draw.h"
36 37
37#define DEBUG 38#define DEBUG
38 39
@@ -87,6 +88,7 @@ static inline void color_imageblit(const struct fb_image *image,
87 u32 null_bits = 32 - bpp; 88 u32 null_bits = 32 - bpp;
88 u32 *palette = (u32 *) p->pseudo_palette; 89 u32 *palette = (u32 *) p->pseudo_palette;
89 const u8 *src = image->data; 90 const u8 *src = image->data;
91 u32 bswapmask = fb_compute_bswapmask(p);
90 92
91 dst2 = (u32 __iomem *) dst1; 93 dst2 = (u32 __iomem *) dst1;
92 for (i = image->height; i--; ) { 94 for (i = image->height; i--; ) {
@@ -96,7 +98,7 @@ static inline void color_imageblit(const struct fb_image *image,
96 val = 0; 98 val = 0;
97 99
98 if (start_index) { 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 val = FB_READL(dst) & start_mask; 102 val = FB_READL(dst) & start_mask;
101 shift = start_index; 103 shift = start_index;
102 } 104 }
@@ -107,7 +109,7 @@ static inline void color_imageblit(const struct fb_image *image,
107 else 109 else
108 color = *src; 110 color = *src;
109 color <<= FB_LEFT_POS(bpp); 111 color <<= FB_LEFT_POS(bpp);
110 val |= FB_SHIFT_HIGH(color, shift); 112 val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
111 if (shift >= null_bits) { 113 if (shift >= null_bits) {
112 FB_WRITEL(val, dst++); 114 FB_WRITEL(val, dst++);
113 115
@@ -119,7 +121,7 @@ static inline void color_imageblit(const struct fb_image *image,
119 src++; 121 src++;
120 } 122 }
121 if (shift) { 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 FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); 126 FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
125 } 127 }
@@ -147,7 +149,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
147 u32 spitch = (image->width+7)/8; 149 u32 spitch = (image->width+7)/8;
148 const u8 *src = image->data, *s; 150 const u8 *src = image->data, *s;
149 u32 i, j, l; 151 u32 i, j, l;
150 152 u32 bswapmask = fb_compute_bswapmask(p);
153
151 dst2 = (u32 __iomem *) dst1; 154 dst2 = (u32 __iomem *) dst1;
152 fgcolor <<= FB_LEFT_POS(bpp); 155 fgcolor <<= FB_LEFT_POS(bpp);
153 bgcolor <<= FB_LEFT_POS(bpp); 156 bgcolor <<= FB_LEFT_POS(bpp);
@@ -161,7 +164,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
161 164
162 /* write leading bits */ 165 /* write leading bits */
163 if (start_index) { 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 val = FB_READL(dst) & start_mask; 168 val = FB_READL(dst) & start_mask;
166 shift = start_index; 169 shift = start_index;
167 } 170 }
@@ -169,7 +172,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
169 while (j--) { 172 while (j--) {
170 l--; 173 l--;
171 color = (*s & (1 << l)) ? fgcolor : bgcolor; 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 /* Did the bitshift spill bits to the next long? */ 177 /* Did the bitshift spill bits to the next long? */
175 if (shift >= null_bits) { 178 if (shift >= null_bits) {
@@ -184,7 +187,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
184 187
185 /* write trailing bits */ 188 /* write trailing bits */
186 if (shift) { 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 FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); 192 FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
190 } 193 }
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
index c5c45203833b..816843f06bb7 100644
--- a/drivers/video/fb_draw.h
+++ b/drivers/video/fb_draw.h
@@ -2,6 +2,7 @@
2#define _FB_DRAW_H 2#define _FB_DRAW_H
3 3
4#include <asm/types.h> 4#include <asm/types.h>
5#include <linux/fb.h>
5 6
6 /* 7 /*
7 * Compose two values, using a bitmask as decision value 8 * Compose two values, using a bitmask as decision value
@@ -69,4 +70,71 @@ pixel_to_pat( u32 bpp, u32 pixel)
69 } 70 }
70} 71}
71#endif 72#endif
73
74#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE
75
76static 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
96static 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
117static 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#endif /* FB_DRAW_H */ 140#endif /* FB_DRAW_H */