0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include <linux/module.h>
0026 #include <linux/kernel.h>
0027 #include <linux/string.h>
0028 #include <linux/fb.h>
0029 #include <asm/types.h>
0030 #include <asm/io.h>
0031 #include "fb_draw.h"
0032
0033 #if BITS_PER_LONG == 32
0034 # define FB_WRITEL fb_writel
0035 # define FB_READL fb_readl
0036 #else
0037 # define FB_WRITEL fb_writeq
0038 # define FB_READL fb_readq
0039 #endif
0040
0041
0042
0043
0044
0045 static void
0046 bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
0047 const unsigned long __iomem *src, unsigned src_idx, int bits,
0048 unsigned n, u32 bswapmask)
0049 {
0050 unsigned long first, last;
0051 int const shift = dst_idx-src_idx;
0052
0053 #if 0
0054
0055
0056
0057
0058 memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
0059 (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
0060 return;
0061 #endif
0062
0063 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
0064 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
0065
0066 if (!shift) {
0067
0068
0069 if (dst_idx+n <= bits) {
0070
0071 if (last)
0072 first &= last;
0073 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
0074 } else {
0075
0076
0077
0078 if (first != ~0UL) {
0079 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
0080 dst++;
0081 src++;
0082 n -= bits - dst_idx;
0083 }
0084
0085
0086 n /= bits;
0087 while (n >= 8) {
0088 FB_WRITEL(FB_READL(src++), dst++);
0089 FB_WRITEL(FB_READL(src++), dst++);
0090 FB_WRITEL(FB_READL(src++), dst++);
0091 FB_WRITEL(FB_READL(src++), dst++);
0092 FB_WRITEL(FB_READL(src++), dst++);
0093 FB_WRITEL(FB_READL(src++), dst++);
0094 FB_WRITEL(FB_READL(src++), dst++);
0095 FB_WRITEL(FB_READL(src++), dst++);
0096 n -= 8;
0097 }
0098 while (n--)
0099 FB_WRITEL(FB_READL(src++), dst++);
0100
0101
0102 if (last)
0103 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
0104 }
0105 } else {
0106
0107 unsigned long d0, d1;
0108 int m;
0109
0110 int const left = shift & (bits - 1);
0111 int const right = -shift & (bits - 1);
0112
0113 if (dst_idx+n <= bits) {
0114
0115 if (last)
0116 first &= last;
0117 d0 = FB_READL(src);
0118 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0119 if (shift > 0) {
0120
0121 d0 <<= left;
0122 } else if (src_idx+n <= bits) {
0123
0124 d0 >>= right;
0125 } else {
0126
0127 d1 = FB_READL(src + 1);
0128 d1 = fb_rev_pixels_in_long(d1, bswapmask);
0129 d0 = d0 >> right | d1 << left;
0130 }
0131 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0132 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
0133 } else {
0134
0135
0136
0137
0138
0139
0140 d0 = FB_READL(src++);
0141 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0142
0143 if (shift > 0) {
0144
0145 d1 = d0;
0146 d0 <<= left;
0147 n -= bits - dst_idx;
0148 } else {
0149
0150 d1 = FB_READL(src++);
0151 d1 = fb_rev_pixels_in_long(d1, bswapmask);
0152
0153 d0 = d0 >> right | d1 << left;
0154 n -= bits - dst_idx;
0155 }
0156 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0157 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
0158 d0 = d1;
0159 dst++;
0160
0161
0162 m = n % bits;
0163 n /= bits;
0164 while ((n >= 4) && !bswapmask) {
0165 d1 = FB_READL(src++);
0166 FB_WRITEL(d0 >> right | d1 << left, dst++);
0167 d0 = d1;
0168 d1 = FB_READL(src++);
0169 FB_WRITEL(d0 >> right | d1 << left, dst++);
0170 d0 = d1;
0171 d1 = FB_READL(src++);
0172 FB_WRITEL(d0 >> right | d1 << left, dst++);
0173 d0 = d1;
0174 d1 = FB_READL(src++);
0175 FB_WRITEL(d0 >> right | d1 << left, dst++);
0176 d0 = d1;
0177 n -= 4;
0178 }
0179 while (n--) {
0180 d1 = FB_READL(src++);
0181 d1 = fb_rev_pixels_in_long(d1, bswapmask);
0182 d0 = d0 >> right | d1 << left;
0183 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0184 FB_WRITEL(d0, dst++);
0185 d0 = d1;
0186 }
0187
0188
0189 if (m) {
0190 if (m <= bits - right) {
0191
0192 d0 >>= right;
0193 } else {
0194
0195 d1 = FB_READL(src);
0196 d1 = fb_rev_pixels_in_long(d1,
0197 bswapmask);
0198 d0 = d0 >> right | d1 << left;
0199 }
0200 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0201 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
0202 }
0203 }
0204 }
0205 }
0206
0207
0208
0209
0210
0211 static void
0212 bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
0213 const unsigned long __iomem *src, unsigned src_idx, int bits,
0214 unsigned n, u32 bswapmask)
0215 {
0216 unsigned long first, last;
0217 int shift;
0218
0219 #if 0
0220
0221
0222
0223
0224 memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
0225 (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
0226 return;
0227 #endif
0228
0229 dst += (dst_idx + n - 1) / bits;
0230 src += (src_idx + n - 1) / bits;
0231 dst_idx = (dst_idx + n - 1) % bits;
0232 src_idx = (src_idx + n - 1) % bits;
0233
0234 shift = dst_idx-src_idx;
0235
0236 first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask);
0237 last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask);
0238
0239 if (!shift) {
0240
0241
0242 if ((unsigned long)dst_idx+1 >= n) {
0243
0244 if (first)
0245 last &= first;
0246 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
0247 } else {
0248
0249
0250
0251 if (first) {
0252 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
0253 dst--;
0254 src--;
0255 n -= dst_idx+1;
0256 }
0257
0258
0259 n /= bits;
0260 while (n >= 8) {
0261 FB_WRITEL(FB_READL(src--), dst--);
0262 FB_WRITEL(FB_READL(src--), dst--);
0263 FB_WRITEL(FB_READL(src--), dst--);
0264 FB_WRITEL(FB_READL(src--), dst--);
0265 FB_WRITEL(FB_READL(src--), dst--);
0266 FB_WRITEL(FB_READL(src--), dst--);
0267 FB_WRITEL(FB_READL(src--), dst--);
0268 FB_WRITEL(FB_READL(src--), dst--);
0269 n -= 8;
0270 }
0271 while (n--)
0272 FB_WRITEL(FB_READL(src--), dst--);
0273
0274
0275 if (last != -1UL)
0276 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
0277 }
0278 } else {
0279
0280 unsigned long d0, d1;
0281 int m;
0282
0283 int const left = shift & (bits-1);
0284 int const right = -shift & (bits-1);
0285
0286 if ((unsigned long)dst_idx+1 >= n) {
0287
0288 if (first)
0289 last &= first;
0290 d0 = FB_READL(src);
0291 if (shift < 0) {
0292
0293 d0 >>= right;
0294 } else if (1+(unsigned long)src_idx >= n) {
0295
0296 d0 <<= left;
0297 } else {
0298
0299 d1 = FB_READL(src - 1);
0300 d1 = fb_rev_pixels_in_long(d1, bswapmask);
0301 d0 = d0 << left | d1 >> right;
0302 }
0303 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0304 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
0305 } else {
0306
0307
0308
0309
0310
0311
0312
0313 d0 = FB_READL(src--);
0314 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0315
0316 if (shift < 0) {
0317
0318 d1 = d0;
0319 d0 >>= right;
0320 } else {
0321
0322 d1 = FB_READL(src--);
0323 d1 = fb_rev_pixels_in_long(d1, bswapmask);
0324 d0 = d0 << left | d1 >> right;
0325 }
0326 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0327 if (!first)
0328 FB_WRITEL(d0, dst);
0329 else
0330 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
0331 d0 = d1;
0332 dst--;
0333 n -= dst_idx+1;
0334
0335
0336 m = n % bits;
0337 n /= bits;
0338 while ((n >= 4) && !bswapmask) {
0339 d1 = FB_READL(src--);
0340 FB_WRITEL(d0 << left | d1 >> right, dst--);
0341 d0 = d1;
0342 d1 = FB_READL(src--);
0343 FB_WRITEL(d0 << left | d1 >> right, dst--);
0344 d0 = d1;
0345 d1 = FB_READL(src--);
0346 FB_WRITEL(d0 << left | d1 >> right, dst--);
0347 d0 = d1;
0348 d1 = FB_READL(src--);
0349 FB_WRITEL(d0 << left | d1 >> right, dst--);
0350 d0 = d1;
0351 n -= 4;
0352 }
0353 while (n--) {
0354 d1 = FB_READL(src--);
0355 d1 = fb_rev_pixels_in_long(d1, bswapmask);
0356 d0 = d0 << left | d1 >> right;
0357 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0358 FB_WRITEL(d0, dst--);
0359 d0 = d1;
0360 }
0361
0362
0363 if (m) {
0364 if (m <= bits - left) {
0365
0366 d0 <<= left;
0367 } else {
0368
0369 d1 = FB_READL(src);
0370 d1 = fb_rev_pixels_in_long(d1,
0371 bswapmask);
0372 d0 = d0 << left | d1 >> right;
0373 }
0374 d0 = fb_rev_pixels_in_long(d0, bswapmask);
0375 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
0376 }
0377 }
0378 }
0379 }
0380
0381 void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
0382 {
0383 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
0384 u32 height = area->height, width = area->width;
0385 unsigned long const bits_per_line = p->fix.line_length*8u;
0386 unsigned long __iomem *base = NULL;
0387 int bits = BITS_PER_LONG, bytes = bits >> 3;
0388 unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
0389 u32 bswapmask = fb_compute_bswapmask(p);
0390
0391 if (p->state != FBINFO_STATE_RUNNING)
0392 return;
0393
0394
0395
0396 if ((dy == sy && dx > sx) || (dy > sy)) {
0397 dy += height;
0398 sy += height;
0399 rev_copy = 1;
0400 }
0401
0402
0403
0404 base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
0405 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
0406
0407 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
0408 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
0409
0410 if (p->fbops->fb_sync)
0411 p->fbops->fb_sync(p);
0412
0413 if (rev_copy) {
0414 while (height--) {
0415 dst_idx -= bits_per_line;
0416 src_idx -= bits_per_line;
0417 bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
0418 base + (src_idx / bits), src_idx % bits, bits,
0419 width*p->var.bits_per_pixel, bswapmask);
0420 }
0421 } else {
0422 while (height--) {
0423 bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
0424 base + (src_idx / bits), src_idx % bits, bits,
0425 width*p->var.bits_per_pixel, bswapmask);
0426 dst_idx += bits_per_line;
0427 src_idx += bits_per_line;
0428 }
0429 }
0430 }
0431
0432 EXPORT_SYMBOL(cfb_copyarea);
0433
0434 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
0435 MODULE_DESCRIPTION("Generic software accelerated copyarea");
0436 MODULE_LICENSE("GPL");
0437