aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorMans Rullgard <mans@mansr.com>2015-01-21 20:19:49 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2015-01-30 02:46:59 -0500
commitee06bd155b081a1895f995ec2777094c7e746152 (patch)
treef3577ee2e9491e286a16d384eb50d206b527974f /drivers/video
parent6984330a13efff2e5385c612b6fc2b3b38103be1 (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.c137
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
27static void 27static void
28bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, 28bitcpy(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
168static void 169static void
169bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, 170bitcpy_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;