diff options
author | Pavel Pisa <pisa@cmp.felk.cvut.cz> | 2007-10-16 04:29:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:19 -0400 |
commit | 779121e9f17525769c04a00475fd85600c8c04eb (patch) | |
tree | 757aad067bed869bfdd2dc2eb2f652a7f4e5e071 /drivers/video | |
parent | 3c03ec209af1dd8223888630482f1b2353dc6284 (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/Kconfig | 9 | ||||
-rw-r--r-- | drivers/video/cfbcopyarea.c | 17 | ||||
-rw-r--r-- | drivers/video/cfbfillrect.c | 20 | ||||
-rw-r--r-- | drivers/video/cfbimgblt.c | 17 | ||||
-rw-r--r-- | drivers/video/fb_draw.h | 68 |
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 | ||
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 | config FB_SYS_FILLRECT | 115 | config 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 | ||
46 | static void | 46 | static void |
47 | bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, | 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 | 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 | ||
186 | static void | 186 | static void |
187 | bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, | 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 | 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 | ||
38 | static void | 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 | 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 | */ |
148 | static void | 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 | 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 | |||
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 | #endif /* FB_DRAW_H */ | 140 | #endif /* FB_DRAW_H */ |