diff options
author | Mans Rullgard <mans@mansr.com> | 2015-01-21 20:19:49 -0500 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2015-01-30 02:46:59 -0500 |
commit | ee06bd155b081a1895f995ec2777094c7e746152 (patch) | |
tree | f3577ee2e9491e286a16d384eb50d206b527974f /drivers/video | |
parent | 6984330a13efff2e5385c612b6fc2b3b38103be1 (diff) |
video: fbdev: fix sys_copyarea
The sys_copyarea() function performs the same operation as
cfb_copyarea() but using normal memory access instead of I/O
accessors. Since the introduction of sys_copyarea(), there
have been two fixes to cfb_copyarea():
- 00a9d699 ("framebuffer: fix cfb_copyarea")
- 5b789da8 ("framebuffer: fix screen corruption when copying")
This patch incorporates the fixes into sys_copyarea() as well.
Signed-off-by: Mans Rullgard <mans@mansr.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/fbdev/core/syscopyarea.c | 137 |
1 files changed, 65 insertions, 72 deletions
diff --git a/drivers/video/fbdev/core/syscopyarea.c b/drivers/video/fbdev/core/syscopyarea.c index 844a32fd38ed..c1eda3190968 100644 --- a/drivers/video/fbdev/core/syscopyarea.c +++ b/drivers/video/fbdev/core/syscopyarea.c | |||
@@ -25,8 +25,8 @@ | |||
25 | */ | 25 | */ |
26 | 26 | ||
27 | static void | 27 | static void |
28 | bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, | 28 | bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx, |
29 | const unsigned long *src, int src_idx, int bits, unsigned n) | 29 | const unsigned long *src, unsigned src_idx, int bits, unsigned n) |
30 | { | 30 | { |
31 | unsigned long first, last; | 31 | unsigned long first, last; |
32 | int const shift = dst_idx-src_idx; | 32 | int const shift = dst_idx-src_idx; |
@@ -86,15 +86,15 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, | |||
86 | first &= last; | 86 | first &= last; |
87 | if (shift > 0) { | 87 | if (shift > 0) { |
88 | /* Single source word */ | 88 | /* Single source word */ |
89 | *dst = comp(*src >> right, *dst, first); | 89 | *dst = comp(*src << left, *dst, first); |
90 | } else if (src_idx+n <= bits) { | 90 | } else if (src_idx+n <= bits) { |
91 | /* Single source word */ | 91 | /* Single source word */ |
92 | *dst = comp(*src << left, *dst, first); | 92 | *dst = comp(*src >> right, *dst, first); |
93 | } else { | 93 | } else { |
94 | /* 2 source words */ | 94 | /* 2 source words */ |
95 | d0 = *src++; | 95 | d0 = *src++; |
96 | d1 = *src; | 96 | d1 = *src; |
97 | *dst = comp(d0 << left | d1 >> right, *dst, | 97 | *dst = comp(d0 >> right | d1 << left, *dst, |
98 | first); | 98 | first); |
99 | } | 99 | } |
100 | } else { | 100 | } else { |
@@ -109,13 +109,14 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, | |||
109 | /* Leading bits */ | 109 | /* Leading bits */ |
110 | if (shift > 0) { | 110 | if (shift > 0) { |
111 | /* Single source word */ | 111 | /* Single source word */ |
112 | *dst = comp(d0 >> right, *dst, first); | 112 | *dst = comp(d0 << left, *dst, first); |
113 | dst++; | 113 | dst++; |
114 | n -= bits - dst_idx; | 114 | n -= bits - dst_idx; |
115 | } else { | 115 | } else { |
116 | /* 2 source words */ | 116 | /* 2 source words */ |
117 | d1 = *src++; | 117 | d1 = *src++; |
118 | *dst = comp(d0 << left | *dst >> right, *dst, first); | 118 | *dst = comp(d0 >> right | d1 << left, *dst, |
119 | first); | ||
119 | d0 = d1; | 120 | d0 = d1; |
120 | dst++; | 121 | dst++; |
121 | n -= bits - dst_idx; | 122 | n -= bits - dst_idx; |
@@ -126,36 +127,36 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, | |||
126 | n /= bits; | 127 | n /= bits; |
127 | while (n >= 4) { | 128 | while (n >= 4) { |
128 | d1 = *src++; | 129 | d1 = *src++; |
129 | *dst++ = d0 << left | d1 >> right; | 130 | *dst++ = d0 >> right | d1 << left; |
130 | d0 = d1; | 131 | d0 = d1; |
131 | d1 = *src++; | 132 | d1 = *src++; |
132 | *dst++ = d0 << left | d1 >> right; | 133 | *dst++ = d0 >> right | d1 << left; |
133 | d0 = d1; | 134 | d0 = d1; |
134 | d1 = *src++; | 135 | d1 = *src++; |
135 | *dst++ = d0 << left | d1 >> right; | 136 | *dst++ = d0 >> right | d1 << left; |
136 | d0 = d1; | 137 | d0 = d1; |
137 | d1 = *src++; | 138 | d1 = *src++; |
138 | *dst++ = d0 << left | d1 >> right; | 139 | *dst++ = d0 >> right | d1 << left; |
139 | d0 = d1; | 140 | d0 = d1; |
140 | n -= 4; | 141 | n -= 4; |
141 | } | 142 | } |
142 | while (n--) { | 143 | while (n--) { |
143 | d1 = *src++; | 144 | d1 = *src++; |
144 | *dst++ = d0 << left | d1 >> right; | 145 | *dst++ = d0 >> right | d1 << left; |
145 | d0 = d1; | 146 | d0 = d1; |
146 | } | 147 | } |
147 | 148 | ||
148 | /* Trailing bits */ | 149 | /* Trailing bits */ |
149 | if (last) { | 150 | if (m) { |
150 | if (m <= right) { | 151 | if (m <= bits - right) { |
151 | /* Single source word */ | 152 | /* Single source word */ |
152 | *dst = comp(d0 << left, *dst, last); | 153 | d0 >>= right; |
153 | } else { | 154 | } else { |
154 | /* 2 source words */ | 155 | /* 2 source words */ |
155 | d1 = *src; | 156 | d1 = *src; |
156 | *dst = comp(d0 << left | d1 >> right, | 157 | d0 = d0 >> right | d1 << left; |
157 | *dst, last); | ||
158 | } | 158 | } |
159 | *dst = comp(d0, *dst, last); | ||
159 | } | 160 | } |
160 | } | 161 | } |
161 | } | 162 | } |
@@ -166,40 +167,35 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, | |||
166 | */ | 167 | */ |
167 | 168 | ||
168 | static void | 169 | static void |
169 | bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, | 170 | bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx, |
170 | const unsigned long *src, int src_idx, int bits, unsigned n) | 171 | const unsigned long *src, unsigned src_idx, unsigned bits, |
172 | unsigned n) | ||
171 | { | 173 | { |
172 | unsigned long first, last; | 174 | unsigned long first, last; |
173 | int shift; | 175 | int shift; |
174 | 176 | ||
175 | dst += (n-1)/bits; | 177 | dst += (dst_idx + n - 1) / bits; |
176 | src += (n-1)/bits; | 178 | src += (src_idx + n - 1) / bits; |
177 | if ((n-1) % bits) { | 179 | dst_idx = (dst_idx + n - 1) % bits; |
178 | dst_idx += (n-1) % bits; | 180 | src_idx = (src_idx + n - 1) % bits; |
179 | dst += dst_idx >> (ffs(bits) - 1); | ||
180 | dst_idx &= bits - 1; | ||
181 | src_idx += (n-1) % bits; | ||
182 | src += src_idx >> (ffs(bits) - 1); | ||
183 | src_idx &= bits - 1; | ||
184 | } | ||
185 | 181 | ||
186 | shift = dst_idx-src_idx; | 182 | shift = dst_idx-src_idx; |
187 | 183 | ||
188 | first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx); | 184 | first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits); |
189 | last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits))); | 185 | last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits); |
190 | 186 | ||
191 | if (!shift) { | 187 | if (!shift) { |
192 | /* Same alignment for source and dest */ | 188 | /* Same alignment for source and dest */ |
193 | if ((unsigned long)dst_idx+1 >= n) { | 189 | if ((unsigned long)dst_idx+1 >= n) { |
194 | /* Single word */ | 190 | /* Single word */ |
195 | if (last) | 191 | if (first) |
196 | first &= last; | 192 | last &= first; |
197 | *dst = comp(*src, *dst, first); | 193 | *dst = comp(*src, *dst, last); |
198 | } else { | 194 | } else { |
199 | /* Multiple destination words */ | 195 | /* Multiple destination words */ |
200 | 196 | ||
201 | /* Leading bits */ | 197 | /* Leading bits */ |
202 | if (first != ~0UL) { | 198 | if (first) { |
203 | *dst = comp(*src, *dst, first); | 199 | *dst = comp(*src, *dst, first); |
204 | dst--; | 200 | dst--; |
205 | src--; | 201 | src--; |
@@ -222,29 +218,29 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, | |||
222 | while (n--) | 218 | while (n--) |
223 | *dst-- = *src--; | 219 | *dst-- = *src--; |
224 | /* Trailing bits */ | 220 | /* Trailing bits */ |
225 | if (last) | 221 | if (last != -1UL) |
226 | *dst = comp(*src, *dst, last); | 222 | *dst = comp(*src, *dst, last); |
227 | } | 223 | } |
228 | } else { | 224 | } else { |
229 | /* Different alignment for source and dest */ | 225 | /* Different alignment for source and dest */ |
230 | 226 | ||
231 | int const left = -shift & (bits-1); | 227 | int const left = shift & (bits-1); |
232 | int const right = shift & (bits-1); | 228 | int const right = -shift & (bits-1); |
233 | 229 | ||
234 | if ((unsigned long)dst_idx+1 >= n) { | 230 | if ((unsigned long)dst_idx+1 >= n) { |
235 | /* Single destination word */ | 231 | /* Single destination word */ |
236 | if (last) | 232 | if (first) |
237 | first &= last; | 233 | last &= first; |
238 | if (shift < 0) { | 234 | if (shift < 0) { |
239 | /* Single source word */ | 235 | /* Single source word */ |
240 | *dst = comp(*src << left, *dst, first); | 236 | *dst = comp(*src >> right, *dst, last); |
241 | } else if (1+(unsigned long)src_idx >= n) { | 237 | } else if (1+(unsigned long)src_idx >= n) { |
242 | /* Single source word */ | 238 | /* Single source word */ |
243 | *dst = comp(*src >> right, *dst, first); | 239 | *dst = comp(*src << left, *dst, last); |
244 | } else { | 240 | } else { |
245 | /* 2 source words */ | 241 | /* 2 source words */ |
246 | *dst = comp(*src >> right | *(src-1) << left, | 242 | *dst = comp(*src << left | *(src-1) >> right, |
247 | *dst, first); | 243 | *dst, last); |
248 | } | 244 | } |
249 | } else { | 245 | } else { |
250 | /* Multiple destination words */ | 246 | /* Multiple destination words */ |
@@ -261,14 +257,18 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, | |||
261 | /* Leading bits */ | 257 | /* Leading bits */ |
262 | if (shift < 0) { | 258 | if (shift < 0) { |
263 | /* Single source word */ | 259 | /* Single source word */ |
264 | *dst = comp(d0 << left, *dst, first); | 260 | d1 = d0; |
261 | d0 >>= right; | ||
265 | } else { | 262 | } else { |
266 | /* 2 source words */ | 263 | /* 2 source words */ |
267 | d1 = *src--; | 264 | d1 = *src--; |
268 | *dst = comp(d0 >> right | d1 << left, *dst, | 265 | d0 = d0 << left | d1 >> right; |
269 | first); | ||
270 | d0 = d1; | ||
271 | } | 266 | } |
267 | if (!first) | ||
268 | *dst = d0; | ||
269 | else | ||
270 | *dst = comp(d0, *dst, first); | ||
271 | d0 = d1; | ||
272 | dst--; | 272 | dst--; |
273 | n -= dst_idx+1; | 273 | n -= dst_idx+1; |
274 | 274 | ||
@@ -277,36 +277,36 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, | |||
277 | n /= bits; | 277 | n /= bits; |
278 | while (n >= 4) { | 278 | while (n >= 4) { |
279 | d1 = *src--; | 279 | d1 = *src--; |
280 | *dst-- = d0 >> right | d1 << left; | 280 | *dst-- = d0 << left | d1 >> right; |
281 | d0 = d1; | 281 | d0 = d1; |
282 | d1 = *src--; | 282 | d1 = *src--; |
283 | *dst-- = d0 >> right | d1 << left; | 283 | *dst-- = d0 << left | d1 >> right; |
284 | d0 = d1; | 284 | d0 = d1; |
285 | d1 = *src--; | 285 | d1 = *src--; |
286 | *dst-- = d0 >> right | d1 << left; | 286 | *dst-- = d0 << left | d1 >> right; |
287 | d0 = d1; | 287 | d0 = d1; |
288 | d1 = *src--; | 288 | d1 = *src--; |
289 | *dst-- = d0 >> right | d1 << left; | 289 | *dst-- = d0 << left | d1 >> right; |
290 | d0 = d1; | 290 | d0 = d1; |
291 | n -= 4; | 291 | n -= 4; |
292 | } | 292 | } |
293 | while (n--) { | 293 | while (n--) { |
294 | d1 = *src--; | 294 | d1 = *src--; |
295 | *dst-- = d0 >> right | d1 << left; | 295 | *dst-- = d0 << left | d1 >> right; |
296 | d0 = d1; | 296 | d0 = d1; |
297 | } | 297 | } |
298 | 298 | ||
299 | /* Trailing bits */ | 299 | /* Trailing bits */ |
300 | if (last) { | 300 | if (m) { |
301 | if (m <= left) { | 301 | if (m <= bits - left) { |
302 | /* Single source word */ | 302 | /* Single source word */ |
303 | *dst = comp(d0 >> right, *dst, last); | 303 | d0 <<= left; |
304 | } else { | 304 | } else { |
305 | /* 2 source words */ | 305 | /* 2 source words */ |
306 | d1 = *src; | 306 | d1 = *src; |
307 | *dst = comp(d0 >> right | d1 << left, | 307 | d0 = d0 << left | d1 >> right; |
308 | *dst, last); | ||
309 | } | 308 | } |
309 | *dst = comp(d0, *dst, last); | ||
310 | } | 310 | } |
311 | } | 311 | } |
312 | } | 312 | } |
@@ -317,9 +317,9 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) | |||
317 | u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; | 317 | u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; |
318 | u32 height = area->height, width = area->width; | 318 | u32 height = area->height, width = area->width; |
319 | unsigned long const bits_per_line = p->fix.line_length*8u; | 319 | unsigned long const bits_per_line = p->fix.line_length*8u; |
320 | unsigned long *dst = NULL, *src = NULL; | 320 | unsigned long *base = NULL; |
321 | int bits = BITS_PER_LONG, bytes = bits >> 3; | 321 | int bits = BITS_PER_LONG, bytes = bits >> 3; |
322 | int dst_idx = 0, src_idx = 0, rev_copy = 0; | 322 | unsigned dst_idx = 0, src_idx = 0, rev_copy = 0; |
323 | 323 | ||
324 | if (p->state != FBINFO_STATE_RUNNING) | 324 | if (p->state != FBINFO_STATE_RUNNING) |
325 | return; | 325 | return; |
@@ -334,8 +334,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) | |||
334 | 334 | ||
335 | /* split the base of the framebuffer into a long-aligned address and | 335 | /* split the base of the framebuffer into a long-aligned address and |
336 | the index of the first bit */ | 336 | the index of the first bit */ |
337 | dst = src = (unsigned long *)((unsigned long)p->screen_base & | 337 | base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1)); |
338 | ~(bytes-1)); | ||
339 | dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); | 338 | dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); |
340 | /* add offset of source and target area */ | 339 | /* add offset of source and target area */ |
341 | dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; | 340 | dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; |
@@ -348,20 +347,14 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) | |||
348 | while (height--) { | 347 | while (height--) { |
349 | dst_idx -= bits_per_line; | 348 | dst_idx -= bits_per_line; |
350 | src_idx -= bits_per_line; | 349 | src_idx -= bits_per_line; |
351 | dst += dst_idx >> (ffs(bits) - 1); | 350 | bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits, |
352 | dst_idx &= (bytes - 1); | 351 | base + (src_idx / bits), src_idx % bits, bits, |
353 | src += src_idx >> (ffs(bits) - 1); | ||
354 | src_idx &= (bytes - 1); | ||
355 | bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, | ||
356 | width*p->var.bits_per_pixel); | 352 | width*p->var.bits_per_pixel); |
357 | } | 353 | } |
358 | } else { | 354 | } else { |
359 | while (height--) { | 355 | while (height--) { |
360 | dst += dst_idx >> (ffs(bits) - 1); | 356 | bitcpy(p, base + (dst_idx / bits), dst_idx % bits, |
361 | dst_idx &= (bytes - 1); | 357 | base + (src_idx / bits), src_idx % bits, bits, |
362 | src += src_idx >> (ffs(bits) - 1); | ||
363 | src_idx &= (bytes - 1); | ||
364 | bitcpy(p, dst, dst_idx, src, src_idx, bits, | ||
365 | width*p->var.bits_per_pixel); | 358 | width*p->var.bits_per_pixel); |
366 | dst_idx += bits_per_line; | 359 | dst_idx += bits_per_line; |
367 | src_idx += bits_per_line; | 360 | src_idx += bits_per_line; |