cfbcopyarea.c 11 KB

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