powerpc/mm: Avoid calling arch_enter/leave_lazy_mmu() in set_ptes
[platform/kernel/linux-starfive.git] / drivers / video / fbdev / core / syscopyarea.c
1 /*
2  *  Generic Bit Block Transfer for frame buffers located in system RAM with
3  *  packed pixels of any depth.
4  *
5  *  Based almost entirely from cfbcopyarea.c (which is based almost entirely
6  *  on Geert Uytterhoeven's copyarea routine)
7  *
8  *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
9  *
10  *  This file is subject to the terms and conditions of the GNU General Public
11  *  License.  See the file COPYING in the main directory of this archive for
12  *  more details.
13  *
14  */
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/fb.h>
19 #include <asm/types.h>
20 #include <asm/io.h>
21 #include "fb_draw.h"
22
23     /*
24      *  Generic bitwise copy algorithm
25      */
26
27 static void
28 bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
29         const unsigned long *src, unsigned src_idx, int bits, unsigned n)
30 {
31         unsigned long first, last;
32         int const shift = dst_idx-src_idx;
33         int left, right;
34
35         first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
36         last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
37
38         if (!shift) {
39                 /* Same alignment for source and dest */
40                 if (dst_idx+n <= bits) {
41                         /* Single word */
42                         if (last)
43                                 first &= last;
44                         *dst = comp(*src, *dst, first);
45                 } else {
46                         /* Multiple destination words */
47                         /* Leading bits */
48                         if (first != ~0UL) {
49                                 *dst = comp(*src, *dst, first);
50                                 dst++;
51                                 src++;
52                                 n -= bits - dst_idx;
53                         }
54
55                         /* Main chunk */
56                         n /= bits;
57                         while (n >= 8) {
58                                 *dst++ = *src++;
59                                 *dst++ = *src++;
60                                 *dst++ = *src++;
61                                 *dst++ = *src++;
62                                 *dst++ = *src++;
63                                 *dst++ = *src++;
64                                 *dst++ = *src++;
65                                 *dst++ = *src++;
66                                 n -= 8;
67                         }
68                         while (n--)
69                                 *dst++ = *src++;
70
71                         /* Trailing bits */
72                         if (last)
73                                 *dst = comp(*src, *dst, last);
74                 }
75         } else {
76                 unsigned long d0, d1;
77                 int m;
78
79                 /* Different alignment for source and dest */
80                 right = shift & (bits - 1);
81                 left = -shift & (bits - 1);
82
83                 if (dst_idx+n <= bits) {
84                         /* Single destination word */
85                         if (last)
86                                 first &= last;
87                         if (shift > 0) {
88                                 /* Single source word */
89                                 *dst = comp(*src << left, *dst, first);
90                         } else if (src_idx+n <= bits) {
91                                 /* Single source word */
92                                 *dst = comp(*src >> right, *dst, first);
93                         } else {
94                                 /* 2 source words */
95                                 d0 = *src++;
96                                 d1 = *src;
97                                 *dst = comp(d0 >> right | d1 << left, *dst,
98                                             first);
99                         }
100                 } else {
101                         /* Multiple destination words */
102                         /** We must always remember the last value read,
103                             because in case SRC and DST overlap bitwise (e.g.
104                             when moving just one pixel in 1bpp), we always
105                             collect one full long for DST and that might
106                             overlap with the current long from SRC. We store
107                             this value in 'd0'. */
108                         d0 = *src++;
109                         /* Leading bits */
110                         if (shift > 0) {
111                                 /* Single source word */
112                                 *dst = comp(d0 << left, *dst, first);
113                                 dst++;
114                                 n -= bits - dst_idx;
115                         } else {
116                                 /* 2 source words */
117                                 d1 = *src++;
118                                 *dst = comp(d0 >> right | d1 << left, *dst,
119                                             first);
120                                 d0 = d1;
121                                 dst++;
122                                 n -= bits - dst_idx;
123                         }
124
125                         /* Main chunk */
126                         m = n % bits;
127                         n /= bits;
128                         while (n >= 4) {
129                                 d1 = *src++;
130                                 *dst++ = d0 >> right | d1 << left;
131                                 d0 = d1;
132                                 d1 = *src++;
133                                 *dst++ = d0 >> right | d1 << left;
134                                 d0 = d1;
135                                 d1 = *src++;
136                                 *dst++ = d0 >> right | d1 << left;
137                                 d0 = d1;
138                                 d1 = *src++;
139                                 *dst++ = d0 >> right | d1 << left;
140                                 d0 = d1;
141                                 n -= 4;
142                         }
143                         while (n--) {
144                                 d1 = *src++;
145                                 *dst++ = d0 >> right | d1 << left;
146                                 d0 = d1;
147                         }
148
149                         /* Trailing bits */
150                         if (m) {
151                                 if (m <= bits - right) {
152                                         /* Single source word */
153                                         d0 >>= right;
154                                 } else {
155                                         /* 2 source words */
156                                         d1 = *src;
157                                         d0 = d0 >> right | d1 << left;
158                                 }
159                                 *dst = comp(d0, *dst, last);
160                         }
161                 }
162         }
163 }
164
165     /*
166      *  Generic bitwise copy algorithm, operating backward
167      */
168
169 static void
170 bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
171            const unsigned long *src, unsigned src_idx, unsigned bits,
172            unsigned n)
173 {
174         unsigned long first, last;
175         int shift;
176
177         dst += (dst_idx + n - 1) / bits;
178         src += (src_idx + n - 1) / bits;
179         dst_idx = (dst_idx + n - 1) % bits;
180         src_idx = (src_idx + n - 1) % bits;
181
182         shift = dst_idx-src_idx;
183
184         first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits);
185         last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits);
186
187         if (!shift) {
188                 /* Same alignment for source and dest */
189                 if ((unsigned long)dst_idx+1 >= n) {
190                         /* Single word */
191                         if (first)
192                                 last &= first;
193                         *dst = comp(*src, *dst, last);
194                 } else {
195                         /* Multiple destination words */
196
197                         /* Leading bits */
198                         if (first) {
199                                 *dst = comp(*src, *dst, first);
200                                 dst--;
201                                 src--;
202                                 n -= dst_idx+1;
203                         }
204
205                         /* Main chunk */
206                         n /= bits;
207                         while (n >= 8) {
208                                 *dst-- = *src--;
209                                 *dst-- = *src--;
210                                 *dst-- = *src--;
211                                 *dst-- = *src--;
212                                 *dst-- = *src--;
213                                 *dst-- = *src--;
214                                 *dst-- = *src--;
215                                 *dst-- = *src--;
216                                 n -= 8;
217                         }
218                         while (n--)
219                                 *dst-- = *src--;
220                         /* Trailing bits */
221                         if (last != -1UL)
222                                 *dst = comp(*src, *dst, last);
223                 }
224         } else {
225                 /* Different alignment for source and dest */
226
227                 int const left = shift & (bits-1);
228                 int const right = -shift & (bits-1);
229
230                 if ((unsigned long)dst_idx+1 >= n) {
231                         /* Single destination word */
232                         if (first)
233                                 last &= first;
234                         if (shift < 0) {
235                                 /* Single source word */
236                                 *dst = comp(*src >> right, *dst, last);
237                         } else if (1+(unsigned long)src_idx >= n) {
238                                 /* Single source word */
239                                 *dst = comp(*src << left, *dst, last);
240                         } else {
241                                 /* 2 source words */
242                                 *dst = comp(*src << left | *(src-1) >> right,
243                                             *dst, last);
244                         }
245                 } else {
246                         /* Multiple destination words */
247                         /** We must always remember the last value read,
248                             because in case SRC and DST overlap bitwise (e.g.
249                             when moving just one pixel in 1bpp), we always
250                             collect one full long for DST and that might
251                             overlap with the current long from SRC. We store
252                             this value in 'd0'. */
253                         unsigned long d0, d1;
254                         int m;
255
256                         d0 = *src--;
257                         /* Leading bits */
258                         if (shift < 0) {
259                                 /* Single source word */
260                                 d1 = d0;
261                                 d0 >>= right;
262                         } else {
263                                 /* 2 source words */
264                                 d1 = *src--;
265                                 d0 = d0 << left | d1 >> right;
266                         }
267                         if (!first)
268                                 *dst = d0;
269                         else
270                                 *dst = comp(d0, *dst, first);
271                         d0 = d1;
272                         dst--;
273                         n -= dst_idx+1;
274
275                         /* Main chunk */
276                         m = n % bits;
277                         n /= bits;
278                         while (n >= 4) {
279                                 d1 = *src--;
280                                 *dst-- = d0 << left | d1 >> right;
281                                 d0 = d1;
282                                 d1 = *src--;
283                                 *dst-- = d0 << left | d1 >> right;
284                                 d0 = d1;
285                                 d1 = *src--;
286                                 *dst-- = d0 << left | d1 >> right;
287                                 d0 = d1;
288                                 d1 = *src--;
289                                 *dst-- = d0 << left | d1 >> right;
290                                 d0 = d1;
291                                 n -= 4;
292                         }
293                         while (n--) {
294                                 d1 = *src--;
295                                 *dst-- = d0 << left | d1 >> right;
296                                 d0 = d1;
297                         }
298
299                         /* Trailing bits */
300                         if (m) {
301                                 if (m <= bits - left) {
302                                         /* Single source word */
303                                         d0 <<= left;
304                                 } else {
305                                         /* 2 source words */
306                                         d1 = *src;
307                                         d0 = d0 << left | d1 >> right;
308                                 }
309                                 *dst = comp(d0, *dst, last);
310                         }
311                 }
312         }
313 }
314
315 void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
316 {
317         u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
318         u32 height = area->height, width = area->width;
319         unsigned long const bits_per_line = p->fix.line_length*8u;
320         unsigned long *base = NULL;
321         int bits = BITS_PER_LONG, bytes = bits >> 3;
322         unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
323
324         if (p->state != FBINFO_STATE_RUNNING)
325                 return;
326
327         /* if the beginning of the target area might overlap with the end of
328         the source area, be have to copy the area reverse. */
329         if ((dy == sy && dx > sx) || (dy > sy)) {
330                 dy += height;
331                 sy += height;
332                 rev_copy = 1;
333         }
334
335         /* split the base of the framebuffer into a long-aligned address and
336            the index of the first bit */
337         base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
338         dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
339         /* add offset of source and target area */
340         dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
341         src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
342
343         if (p->fbops->fb_sync)
344                 p->fbops->fb_sync(p);
345
346         if (rev_copy) {
347                 while (height--) {
348                         dst_idx -= bits_per_line;
349                         src_idx -= bits_per_line;
350                         bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
351                                 base + (src_idx / bits), src_idx % bits, bits,
352                                 width*p->var.bits_per_pixel);
353                 }
354         } else {
355                 while (height--) {
356                         bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
357                                 base + (src_idx / bits), src_idx % bits, bits,
358                                 width*p->var.bits_per_pixel);
359                         dst_idx += bits_per_line;
360                         src_idx += bits_per_line;
361                 }
362         }
363 }
364
365 EXPORT_SYMBOL(sys_copyarea);
366
367 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
368 MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
369 MODULE_LICENSE("GPL");
370