diff options
-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 | ||||
-rw-r--r-- | include/linux/fb.h | 1 |
6 files changed, 109 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 */ |
diff --git a/include/linux/fb.h b/include/linux/fb.h index cec54106aa87..b39395caa460 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
@@ -180,6 +180,7 @@ struct fb_bitfield { | |||
180 | }; | 180 | }; |
181 | 181 | ||
182 | #define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ | 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 | #define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ | 185 | #define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ |
185 | #define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ | 186 | #define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ |