Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.21 404 lines 11 kB view raw
1/* 2 * Generic function for frame buffer with packed pixels of any depth. 3 * 4 * Copyright (C) 1999-2005 James Simmons <jsimmons@www.infradead.org> 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file COPYING in the main directory of this archive for 8 * more details. 9 * 10 * NOTES: 11 * 12 * This is for cfb packed pixels. Iplan and such are incorporated in the 13 * drivers that need them. 14 * 15 * FIXME 16 * 17 * Also need to add code to deal with cards endians that are different than 18 * the native cpu endians. I also need to deal with MSB position in the word. 19 * 20 * The two functions or copying forward and backward could be split up like 21 * the ones for filling, i.e. in aligned and unaligned versions. This would 22 * help moving some redundant computations and branches out of the loop, too. 23 */ 24 25 26 27#include <linux/module.h> 28#include <linux/kernel.h> 29#include <linux/string.h> 30#include <linux/fb.h> 31#include <linux/slab.h> 32#include <asm/types.h> 33#include <asm/io.h> 34 35#if BITS_PER_LONG == 32 36# define FB_WRITEL fb_writel 37# define FB_READL fb_readl 38#else 39# define FB_WRITEL fb_writeq 40# define FB_READL fb_readq 41#endif 42 43 /* 44 * Compose two values, using a bitmask as decision value 45 * This is equivalent to (a & mask) | (b & ~mask) 46 */ 47 48static inline unsigned long 49comp(unsigned long a, unsigned long b, unsigned long mask) 50{ 51 return ((a ^ b) & mask) ^ b; 52} 53 54 /* 55 * Generic bitwise copy algorithm 56 */ 57 58static void 59bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, 60 int src_idx, int bits, unsigned n) 61{ 62 unsigned long first, last; 63 int const shift = dst_idx-src_idx; 64 int left, right; 65 66 first = FB_SHIFT_HIGH(~0UL, dst_idx); 67 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 68 69 if (!shift) { 70 // Same alignment for source and dest 71 72 if (dst_idx+n <= bits) { 73 // Single word 74 if (last) 75 first &= last; 76 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 77 } else { 78 // Multiple destination words 79 80 // Leading bits 81 if (first != ~0UL) { 82 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 83 dst++; 84 src++; 85 n -= bits - dst_idx; 86 } 87 88 // Main chunk 89 n /= bits; 90 while (n >= 8) { 91 FB_WRITEL(FB_READL(src++), dst++); 92 FB_WRITEL(FB_READL(src++), dst++); 93 FB_WRITEL(FB_READL(src++), dst++); 94 FB_WRITEL(FB_READL(src++), dst++); 95 FB_WRITEL(FB_READL(src++), dst++); 96 FB_WRITEL(FB_READL(src++), dst++); 97 FB_WRITEL(FB_READL(src++), dst++); 98 FB_WRITEL(FB_READL(src++), dst++); 99 n -= 8; 100 } 101 while (n--) 102 FB_WRITEL(FB_READL(src++), dst++); 103 104 // Trailing bits 105 if (last) 106 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); 107 } 108 } else { 109 unsigned long d0, d1; 110 int m; 111 // Different alignment for source and dest 112 113 right = shift & (bits - 1); 114 left = -shift & (bits - 1); 115 116 if (dst_idx+n <= bits) { 117 // Single destination word 118 if (last) 119 first &= last; 120 if (shift > 0) { 121 // Single source word 122 FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst); 123 } else if (src_idx+n <= bits) { 124 // Single source word 125 FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst); 126 } else { 127 // 2 source words 128 d0 = FB_READL(src++); 129 d1 = FB_READL(src); 130 FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); 131 } 132 } else { 133 // Multiple destination words 134 /** We must always remember the last value read, because in case 135 SRC and DST overlap bitwise (e.g. when moving just one pixel in 136 1bpp), we always collect one full long for DST and that might 137 overlap with the current long from SRC. We store this value in 138 'd0'. */ 139 d0 = FB_READL(src++); 140 // Leading bits 141 if (shift > 0) { 142 // Single source word 143 FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst); 144 dst++; 145 n -= bits - dst_idx; 146 } else { 147 // 2 source words 148 d1 = FB_READL(src++); 149 FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); 150 d0 = d1; 151 dst++; 152 n -= bits - dst_idx; 153 } 154 155 // Main chunk 156 m = n % bits; 157 n /= bits; 158 while (n >= 4) { 159 d1 = FB_READL(src++); 160 FB_WRITEL(d0 << left | d1 >> right, dst++); 161 d0 = d1; 162 d1 = FB_READL(src++); 163 FB_WRITEL(d0 << left | d1 >> right, dst++); 164 d0 = d1; 165 d1 = FB_READL(src++); 166 FB_WRITEL(d0 << left | d1 >> right, dst++); 167 d0 = d1; 168 d1 = FB_READL(src++); 169 FB_WRITEL(d0 << left | d1 >> right, dst++); 170 d0 = d1; 171 n -= 4; 172 } 173 while (n--) { 174 d1 = FB_READL(src++); 175 FB_WRITEL(d0 << left | d1 >> right, dst++); 176 d0 = d1; 177 } 178 179 // Trailing bits 180 if (last) { 181 if (m <= right) { 182 // Single source word 183 FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst); 184 } else { 185 // 2 source words 186 d1 = FB_READL(src); 187 FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst); 188 } 189 } 190 } 191 } 192} 193 194 /* 195 * Generic bitwise copy algorithm, operating backward 196 */ 197 198static void 199bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, 200 int src_idx, int bits, unsigned n) 201{ 202 unsigned long first, last; 203 int shift; 204 205 dst += (n-1)/bits; 206 src += (n-1)/bits; 207 if ((n-1) % bits) { 208 dst_idx += (n-1) % bits; 209 dst += dst_idx >> (ffs(bits) - 1); 210 dst_idx &= bits - 1; 211 src_idx += (n-1) % bits; 212 src += src_idx >> (ffs(bits) - 1); 213 src_idx &= bits - 1; 214 } 215 216 shift = dst_idx-src_idx; 217 218 first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx); 219 last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits))); 220 221 if (!shift) { 222 // Same alignment for source and dest 223 224 if ((unsigned long)dst_idx+1 >= n) { 225 // Single word 226 if (last) 227 first &= last; 228 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 229 } else { 230 // Multiple destination words 231 232 // Leading bits 233 if (first != ~0UL) { 234 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 235 dst--; 236 src--; 237 n -= dst_idx+1; 238 } 239 240 // Main chunk 241 n /= bits; 242 while (n >= 8) { 243 FB_WRITEL(FB_READL(src--), dst--); 244 FB_WRITEL(FB_READL(src--), dst--); 245 FB_WRITEL(FB_READL(src--), dst--); 246 FB_WRITEL(FB_READL(src--), dst--); 247 FB_WRITEL(FB_READL(src--), dst--); 248 FB_WRITEL(FB_READL(src--), dst--); 249 FB_WRITEL(FB_READL(src--), dst--); 250 FB_WRITEL(FB_READL(src--), dst--); 251 n -= 8; 252 } 253 while (n--) 254 FB_WRITEL(FB_READL(src--), dst--); 255 256 // Trailing bits 257 if (last) 258 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); 259 } 260 } else { 261 // Different alignment for source and dest 262 263 int const left = -shift & (bits-1); 264 int const right = shift & (bits-1); 265 266 if ((unsigned long)dst_idx+1 >= n) { 267 // Single destination word 268 if (last) 269 first &= last; 270 if (shift < 0) { 271 // Single source word 272 FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst); 273 } else if (1+(unsigned long)src_idx >= n) { 274 // Single source word 275 FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst); 276 } else { 277 // 2 source words 278 FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst); 279 } 280 } else { 281 // Multiple destination words 282 /** We must always remember the last value read, because in case 283 SRC and DST overlap bitwise (e.g. when moving just one pixel in 284 1bpp), we always collect one full long for DST and that might 285 overlap with the current long from SRC. We store this value in 286 'd0'. */ 287 unsigned long d0, d1; 288 int m; 289 290 d0 = FB_READL(src--); 291 // Leading bits 292 if (shift < 0) { 293 // Single source word 294 FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst); 295 } else { 296 // 2 source words 297 d1 = FB_READL(src--); 298 FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst); 299 d0 = d1; 300 } 301 dst--; 302 n -= dst_idx+1; 303 304 // Main chunk 305 m = n % bits; 306 n /= bits; 307 while (n >= 4) { 308 d1 = FB_READL(src--); 309 FB_WRITEL(d0 >> right | d1 << left, dst--); 310 d0 = d1; 311 d1 = FB_READL(src--); 312 FB_WRITEL(d0 >> right | d1 << left, dst--); 313 d0 = d1; 314 d1 = FB_READL(src--); 315 FB_WRITEL(d0 >> right | d1 << left, dst--); 316 d0 = d1; 317 d1 = FB_READL(src--); 318 FB_WRITEL(d0 >> right | d1 << left, dst--); 319 d0 = d1; 320 n -= 4; 321 } 322 while (n--) { 323 d1 = FB_READL(src--); 324 FB_WRITEL(d0 >> right | d1 << left, dst--); 325 d0 = d1; 326 } 327 328 // Trailing bits 329 if (last) { 330 if (m <= left) { 331 // Single source word 332 FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst); 333 } else { 334 // 2 source words 335 d1 = FB_READL(src); 336 FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst); 337 } 338 } 339 } 340 } 341} 342 343void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 344{ 345 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; 346 u32 height = area->height, width = area->width; 347 unsigned long const bits_per_line = p->fix.line_length*8u; 348 unsigned long __iomem *dst = NULL, *src = NULL; 349 int bits = BITS_PER_LONG, bytes = bits >> 3; 350 int dst_idx = 0, src_idx = 0, rev_copy = 0; 351 352 if (p->state != FBINFO_STATE_RUNNING) 353 return; 354 355 /* if the beginning of the target area might overlap with the end of 356 the source area, be have to copy the area reverse. */ 357 if ((dy == sy && dx > sx) || (dy > sy)) { 358 dy += height; 359 sy += height; 360 rev_copy = 1; 361 } 362 363 // split the base of the framebuffer into a long-aligned address and the 364 // index of the first bit 365 dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); 366 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); 367 // add offset of source and target area 368 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; 369 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel; 370 371 if (p->fbops->fb_sync) 372 p->fbops->fb_sync(p); 373 374 if (rev_copy) { 375 while (height--) { 376 dst_idx -= bits_per_line; 377 src_idx -= bits_per_line; 378 dst += dst_idx >> (ffs(bits) - 1); 379 dst_idx &= (bytes - 1); 380 src += src_idx >> (ffs(bits) - 1); 381 src_idx &= (bytes - 1); 382 bitcpy_rev(dst, dst_idx, src, src_idx, bits, 383 width*p->var.bits_per_pixel); 384 } 385 } else { 386 while (height--) { 387 dst += dst_idx >> (ffs(bits) - 1); 388 dst_idx &= (bytes - 1); 389 src += src_idx >> (ffs(bits) - 1); 390 src_idx &= (bytes - 1); 391 bitcpy(dst, dst_idx, src, src_idx, bits, 392 width*p->var.bits_per_pixel); 393 dst_idx += bits_per_line; 394 src_idx += bits_per_line; 395 } 396 } 397} 398 399EXPORT_SYMBOL(cfb_copyarea); 400 401MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); 402MODULE_DESCRIPTION("Generic software accelerated copyarea"); 403MODULE_LICENSE("GPL"); 404