diff options
author | Pavel Pisa <pisa@cmp.felk.cvut.cz> | 2007-10-16 04:29:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:23 -0400 |
commit | 15afdd433610c4ba0edf1f8a59915b3755af7365 (patch) | |
tree | 0e59d4eeb2e66af72a4b1a1fead29fa362826792 /drivers/video | |
parent | c3ca34f90b44049dcde62a8f97554409112bf376 (diff) |
fbdev: copyarea function taught to fully support swapped pixel order in byte
This correct case, when source and destination X coordinates difference is n
multiple of pixels in byte. This is probably rare case, but this case should
supported for completeness.
Reorganization of FB_READL and FB_WRITEL calls results in code size decrease
for normal build without swapping support and size with support enabled is
reasonable too.
[adaplas]
Add missing fb_rev_pixels_in_long() prototype.
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Signed-off-by: Antonino Daplas <adaplas@gmail.com>
[akpm@linux-foundation.org: coding-style fixes]
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/cfbcopyarea.c | 86 | ||||
-rw-r--r-- | drivers/video/fb_draw.h | 26 |
2 files changed, 87 insertions, 25 deletions
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index 1c67885a1f4f..b07e419b12d2 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c | |||
@@ -94,29 +94,34 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
94 | FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); | 94 | FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); |
95 | } | 95 | } |
96 | } else { | 96 | } else { |
97 | /* Different alignment for source and dest */ | ||
97 | unsigned long d0, d1; | 98 | unsigned long d0, d1; |
98 | int m; | 99 | int m; |
99 | // Different alignment for source and dest | ||
100 | 100 | ||
101 | right = shift & (bits - 1); | 101 | right = shift & (bits - 1); |
102 | left = -shift & (bits - 1); | 102 | left = -shift & (bits - 1); |
103 | bswapmask &= shift; | ||
103 | 104 | ||
104 | if (dst_idx+n <= bits) { | 105 | if (dst_idx+n <= bits) { |
105 | // Single destination word | 106 | // Single destination word |
106 | if (last) | 107 | if (last) |
107 | first &= last; | 108 | first &= last; |
109 | d0 = FB_READL(src); | ||
110 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
108 | if (shift > 0) { | 111 | if (shift > 0) { |
109 | // Single source word | 112 | // Single source word |
110 | FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst); | 113 | d0 >>= right; |
111 | } else if (src_idx+n <= bits) { | 114 | } else if (src_idx+n <= bits) { |
112 | // Single source word | 115 | // Single source word |
113 | FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst); | 116 | d0 <<= left;; |
114 | } else { | 117 | } else { |
115 | // 2 source words | 118 | // 2 source words |
116 | d0 = FB_READL(src++); | 119 | d1 = FB_READL(src + 1); |
117 | d1 = FB_READL(src); | 120 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
118 | FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); | 121 | d0 = d0<<left | d1>>right; |
119 | } | 122 | } |
123 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
124 | FB_WRITEL(comp(d0, FB_READL(dst), first), dst); | ||
120 | } else { | 125 | } else { |
121 | // Multiple destination words | 126 | // Multiple destination words |
122 | /** We must always remember the last value read, because in case | 127 | /** We must always remember the last value read, because in case |
@@ -125,25 +130,31 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
125 | overlap with the current long from SRC. We store this value in | 130 | overlap with the current long from SRC. We store this value in |
126 | 'd0'. */ | 131 | 'd0'. */ |
127 | d0 = FB_READL(src++); | 132 | d0 = FB_READL(src++); |
133 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
128 | // Leading bits | 134 | // Leading bits |
129 | if (shift > 0) { | 135 | if (shift > 0) { |
130 | // Single source word | 136 | // Single source word |
131 | FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst); | 137 | d1 = d0; |
138 | d0 >>= right; | ||
132 | dst++; | 139 | dst++; |
133 | n -= bits - dst_idx; | 140 | n -= bits - dst_idx; |
134 | } else { | 141 | } else { |
135 | // 2 source words | 142 | // 2 source words |
136 | d1 = FB_READL(src++); | 143 | d1 = FB_READL(src++); |
137 | FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); | 144 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
138 | d0 = d1; | 145 | |
146 | d0 = d0<<left | d1>>right; | ||
139 | dst++; | 147 | dst++; |
140 | n -= bits - dst_idx; | 148 | n -= bits - dst_idx; |
141 | } | 149 | } |
150 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
151 | FB_WRITEL(comp(d0, FB_READL(dst), first), dst); | ||
152 | d0 = d1; | ||
142 | 153 | ||
143 | // Main chunk | 154 | // Main chunk |
144 | m = n % bits; | 155 | m = n % bits; |
145 | n /= bits; | 156 | n /= bits; |
146 | while (n >= 4) { | 157 | while ((n >= 4) && !bswapmask) { |
147 | d1 = FB_READL(src++); | 158 | d1 = FB_READL(src++); |
148 | FB_WRITEL(d0 << left | d1 >> right, dst++); | 159 | FB_WRITEL(d0 << left | d1 >> right, dst++); |
149 | d0 = d1; | 160 | d0 = d1; |
@@ -160,7 +171,10 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
160 | } | 171 | } |
161 | while (n--) { | 172 | while (n--) { |
162 | d1 = FB_READL(src++); | 173 | d1 = FB_READL(src++); |
163 | FB_WRITEL(d0 << left | d1 >> right, dst++); | 174 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
175 | d0 = d0 << left | d1 >> right; | ||
176 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
177 | FB_WRITEL(d0, dst++); | ||
164 | d0 = d1; | 178 | d0 = d1; |
165 | } | 179 | } |
166 | 180 | ||
@@ -168,12 +182,16 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
168 | if (last) { | 182 | if (last) { |
169 | if (m <= right) { | 183 | if (m <= right) { |
170 | // Single source word | 184 | // Single source word |
171 | FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst); | 185 | d0 <<= left; |
172 | } else { | 186 | } else { |
173 | // 2 source words | 187 | // 2 source words |
174 | d1 = FB_READL(src); | 188 | d1 = FB_READL(src); |
175 | FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst); | 189 | d1 = fb_rev_pixels_in_long(d1, |
190 | bswapmask); | ||
191 | d0 = d0<<left | d1>>right; | ||
176 | } | 192 | } |
193 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
194 | FB_WRITEL(comp(d0, FB_READL(dst), last), dst); | ||
177 | } | 195 | } |
178 | } | 196 | } |
179 | } | 197 | } |
@@ -247,24 +265,32 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
247 | } | 265 | } |
248 | } else { | 266 | } else { |
249 | // Different alignment for source and dest | 267 | // Different alignment for source and dest |
268 | unsigned long d0, d1; | ||
269 | int m; | ||
250 | 270 | ||
251 | int const left = -shift & (bits-1); | 271 | int const left = -shift & (bits-1); |
252 | int const right = shift & (bits-1); | 272 | int const right = shift & (bits-1); |
273 | bswapmask &= shift; | ||
253 | 274 | ||
254 | if ((unsigned long)dst_idx+1 >= n) { | 275 | if ((unsigned long)dst_idx+1 >= n) { |
255 | // Single destination word | 276 | // Single destination word |
256 | if (last) | 277 | if (last) |
257 | first &= last; | 278 | first &= last; |
279 | d0 = FB_READL(src); | ||
258 | if (shift < 0) { | 280 | if (shift < 0) { |
259 | // Single source word | 281 | // Single source word |
260 | FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst); | 282 | d0 <<= left; |
261 | } else if (1+(unsigned long)src_idx >= n) { | 283 | } else if (1+(unsigned long)src_idx >= n) { |
262 | // Single source word | 284 | // Single source word |
263 | FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst); | 285 | d0 >>= right; |
264 | } else { | 286 | } else { |
265 | // 2 source words | 287 | // 2 source words |
266 | FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst); | 288 | d1 = FB_READL(src - 1); |
289 | d1 = fb_rev_pixels_in_long(d1, bswapmask); | ||
290 | d0 = d0>>right | d1<<left; | ||
267 | } | 291 | } |
292 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
293 | FB_WRITEL(comp(d0, FB_READL(dst), first), dst); | ||
268 | } else { | 294 | } else { |
269 | // Multiple destination words | 295 | // Multiple destination words |
270 | /** We must always remember the last value read, because in case | 296 | /** We must always remember the last value read, because in case |
@@ -272,27 +298,30 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
272 | 1bpp), we always collect one full long for DST and that might | 298 | 1bpp), we always collect one full long for DST and that might |
273 | overlap with the current long from SRC. We store this value in | 299 | overlap with the current long from SRC. We store this value in |
274 | 'd0'. */ | 300 | 'd0'. */ |
275 | unsigned long d0, d1; | ||
276 | int m; | ||
277 | 301 | ||
278 | d0 = FB_READL(src--); | 302 | d0 = FB_READL(src--); |
303 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
279 | // Leading bits | 304 | // Leading bits |
280 | if (shift < 0) { | 305 | if (shift < 0) { |
281 | // Single source word | 306 | // Single source word |
282 | FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst); | 307 | d1 = d0; |
308 | d0 <<= left; | ||
283 | } else { | 309 | } else { |
284 | // 2 source words | 310 | // 2 source words |
285 | d1 = FB_READL(src--); | 311 | d1 = FB_READL(src--); |
286 | FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst); | 312 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
287 | d0 = d1; | 313 | d0 = d0>>right | d1<<left; |
288 | } | 314 | } |
315 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
316 | FB_WRITEL(comp(d0, FB_READL(dst), first), dst); | ||
317 | d0 = d1; | ||
289 | dst--; | 318 | dst--; |
290 | n -= dst_idx+1; | 319 | n -= dst_idx+1; |
291 | 320 | ||
292 | // Main chunk | 321 | // Main chunk |
293 | m = n % bits; | 322 | m = n % bits; |
294 | n /= bits; | 323 | n /= bits; |
295 | while (n >= 4) { | 324 | while ((n >= 4) && !bswapmask) { |
296 | d1 = FB_READL(src--); | 325 | d1 = FB_READL(src--); |
297 | FB_WRITEL(d0 >> right | d1 << left, dst--); | 326 | FB_WRITEL(d0 >> right | d1 << left, dst--); |
298 | d0 = d1; | 327 | d0 = d1; |
@@ -309,7 +338,10 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
309 | } | 338 | } |
310 | while (n--) { | 339 | while (n--) { |
311 | d1 = FB_READL(src--); | 340 | d1 = FB_READL(src--); |
312 | FB_WRITEL(d0 >> right | d1 << left, dst--); | 341 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
342 | d0 = d0 >> right | d1 << left; | ||
343 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
344 | FB_WRITEL(d0, dst--); | ||
313 | d0 = d1; | 345 | d0 = d1; |
314 | } | 346 | } |
315 | 347 | ||
@@ -317,12 +349,16 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
317 | if (last) { | 349 | if (last) { |
318 | if (m <= left) { | 350 | if (m <= left) { |
319 | // Single source word | 351 | // Single source word |
320 | FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst); | 352 | d0 >>= right; |
321 | } else { | 353 | } else { |
322 | // 2 source words | 354 | // 2 source words |
323 | d1 = FB_READL(src); | 355 | d1 = FB_READL(src); |
324 | FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst); | 356 | d1 = fb_rev_pixels_in_long(d1, |
357 | bswapmask); | ||
358 | d0 = d0>>right | d1<<left; | ||
325 | } | 359 | } |
360 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
361 | FB_WRITEL(comp(d0, FB_READL(dst), last), dst); | ||
326 | } | 362 | } |
327 | } | 363 | } |
328 | } | 364 | } |
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index 816843f06bb7..cdafbe14ef1f 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h | |||
@@ -72,6 +72,26 @@ pixel_to_pat( u32 bpp, u32 pixel) | |||
72 | #endif | 72 | #endif |
73 | 73 | ||
74 | #ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE | 74 | #ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE |
75 | #if BITS_PER_LONG == 64 | ||
76 | #define REV_PIXELS_MASK1 0x5555555555555555ul | ||
77 | #define REV_PIXELS_MASK2 0x3333333333333333ul | ||
78 | #define REV_PIXELS_MASK4 0x0f0f0f0f0f0f0f0ful | ||
79 | #else | ||
80 | #define REV_PIXELS_MASK1 0x55555555ul | ||
81 | #define REV_PIXELS_MASK2 0x33333333ul | ||
82 | #define REV_PIXELS_MASK4 0x0f0f0f0ful | ||
83 | #endif | ||
84 | |||
85 | static inline unsigned long fb_rev_pixels_in_long(unsigned long val, | ||
86 | u32 bswapmask) | ||
87 | { | ||
88 | if (bswapmask & 1) | ||
89 | val = comp(val >> 1, val << 1, REV_PIXELS_MASK1); | ||
90 | if (bswapmask & 2) | ||
91 | val = comp(val >> 2, val << 2, REV_PIXELS_MASK2); | ||
92 | if (bswapmask & 3) | ||
93 | val = comp(val >> 4, val << 4, REV_PIXELS_MASK4); | ||
94 | } | ||
75 | 95 | ||
76 | static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) | 96 | static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) |
77 | { | 97 | { |
@@ -131,6 +151,12 @@ static inline u32 fb_compute_bswapmask(struct fb_info *info) | |||
131 | 151 | ||
132 | #else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ | 152 | #else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ |
133 | 153 | ||
154 | static inline unsigned long fb_rev_pixels_in_long(unsigned long val, | ||
155 | u32 bswapmask) | ||
156 | { | ||
157 | return val; | ||
158 | } | ||
159 | |||
134 | #define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i)) | 160 | #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)) | 161 | #define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i)) |
136 | #define fb_compute_bswapmask(...) 0 | 162 | #define fb_compute_bswapmask(...) 0 |