cfbfillrect.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * Generic fillrect for frame buffers with packed pixels of any depth.
  3. *
  4. * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.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. * The code for depths like 24 that don't have integer number of pixels per
  13. * long is broken and needs to be fixed. For now I turned these types of
  14. * mode off.
  15. *
  16. * Also need to add code to deal with cards endians that are different than
  17. * the native cpu endians. I also need to deal with MSB position in the word.
  18. *
  19. */
  20. #include <linux/module.h>
  21. #include <linux/string.h>
  22. #include <linux/fb.h>
  23. #include <asm/types.h>
  24. #if BITS_PER_LONG == 32
  25. # define FB_WRITEL fb_writel
  26. # define FB_READL fb_readl
  27. #else
  28. # define FB_WRITEL fb_writeq
  29. # define FB_READL fb_readq
  30. #endif
  31. /*
  32. * Compose two values, using a bitmask as decision value
  33. * This is equivalent to (a & mask) | (b & ~mask)
  34. */
  35. static inline unsigned long
  36. comp(unsigned long a, unsigned long b, unsigned long mask)
  37. {
  38. return ((a ^ b) & mask) ^ b;
  39. }
  40. /*
  41. * Create a pattern with the given pixel's color
  42. */
  43. #if BITS_PER_LONG == 64
  44. static inline unsigned long
  45. pixel_to_pat( u32 bpp, u32 pixel)
  46. {
  47. switch (bpp) {
  48. case 1:
  49. return 0xfffffffffffffffful*pixel;
  50. case 2:
  51. return 0x5555555555555555ul*pixel;
  52. case 4:
  53. return 0x1111111111111111ul*pixel;
  54. case 8:
  55. return 0x0101010101010101ul*pixel;
  56. case 12:
  57. return 0x0001001001001001ul*pixel;
  58. case 16:
  59. return 0x0001000100010001ul*pixel;
  60. case 24:
  61. return 0x0000000001000001ul*pixel;
  62. case 32:
  63. return 0x0000000100000001ul*pixel;
  64. default:
  65. panic("pixel_to_pat(): unsupported pixelformat\n");
  66. }
  67. }
  68. #else
  69. static inline unsigned long
  70. pixel_to_pat( u32 bpp, u32 pixel)
  71. {
  72. switch (bpp) {
  73. case 1:
  74. return 0xfffffffful*pixel;
  75. case 2:
  76. return 0x55555555ul*pixel;
  77. case 4:
  78. return 0x11111111ul*pixel;
  79. case 8:
  80. return 0x01010101ul*pixel;
  81. case 12:
  82. return 0x00001001ul*pixel;
  83. case 16:
  84. return 0x00010001ul*pixel;
  85. case 24:
  86. return 0x00000001ul*pixel;
  87. case 32:
  88. return 0x00000001ul*pixel;
  89. default:
  90. panic("pixel_to_pat(): unsupported pixelformat\n");
  91. }
  92. }
  93. #endif
  94. /*
  95. * Aligned pattern fill using 32/64-bit memory accesses
  96. */
  97. static void
  98. bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
  99. {
  100. unsigned long first, last;
  101. if (!n)
  102. return;
  103. first = FB_SHIFT_HIGH(~0UL, dst_idx);
  104. last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  105. if (dst_idx+n <= bits) {
  106. // Single word
  107. if (last)
  108. first &= last;
  109. FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
  110. } else {
  111. // Multiple destination words
  112. // Leading bits
  113. if (first!= ~0UL) {
  114. FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
  115. dst++;
  116. n -= bits - dst_idx;
  117. }
  118. // Main chunk
  119. n /= bits;
  120. while (n >= 8) {
  121. FB_WRITEL(pat, dst++);
  122. FB_WRITEL(pat, dst++);
  123. FB_WRITEL(pat, dst++);
  124. FB_WRITEL(pat, dst++);
  125. FB_WRITEL(pat, dst++);
  126. FB_WRITEL(pat, dst++);
  127. FB_WRITEL(pat, dst++);
  128. FB_WRITEL(pat, dst++);
  129. n -= 8;
  130. }
  131. while (n--)
  132. FB_WRITEL(pat, dst++);
  133. // Trailing bits
  134. if (last)
  135. FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
  136. }
  137. }
  138. /*
  139. * Unaligned generic pattern fill using 32/64-bit memory accesses
  140. * The pattern must have been expanded to a full 32/64-bit value
  141. * Left/right are the appropriate shifts to convert to the pattern to be
  142. * used for the next 32/64-bit word
  143. */
  144. static void
  145. bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
  146. int left, int right, unsigned n, int bits)
  147. {
  148. unsigned long first, last;
  149. if (!n)
  150. return;
  151. first = FB_SHIFT_HIGH(~0UL, dst_idx);
  152. last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  153. if (dst_idx+n <= bits) {
  154. // Single word
  155. if (last)
  156. first &= last;
  157. FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
  158. } else {
  159. // Multiple destination words
  160. // Leading bits
  161. if (first) {
  162. FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
  163. dst++;
  164. pat = pat << left | pat >> right;
  165. n -= bits - dst_idx;
  166. }
  167. // Main chunk
  168. n /= bits;
  169. while (n >= 4) {
  170. FB_WRITEL(pat, dst++);
  171. pat = pat << left | pat >> right;
  172. FB_WRITEL(pat, dst++);
  173. pat = pat << left | pat >> right;
  174. FB_WRITEL(pat, dst++);
  175. pat = pat << left | pat >> right;
  176. FB_WRITEL(pat, dst++);
  177. pat = pat << left | pat >> right;
  178. n -= 4;
  179. }
  180. while (n--) {
  181. FB_WRITEL(pat, dst++);
  182. pat = pat << left | pat >> right;
  183. }
  184. // Trailing bits
  185. if (last)
  186. FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
  187. }
  188. }
  189. /*
  190. * Aligned pattern invert using 32/64-bit memory accesses
  191. */
  192. static void
  193. bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
  194. {
  195. unsigned long val = pat, dat;
  196. unsigned long first, last;
  197. if (!n)
  198. return;
  199. first = FB_SHIFT_HIGH(~0UL, dst_idx);
  200. last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  201. if (dst_idx+n <= bits) {
  202. // Single word
  203. if (last)
  204. first &= last;
  205. dat = FB_READL(dst);
  206. FB_WRITEL(comp(dat ^ val, dat, first), dst);
  207. } else {
  208. // Multiple destination words
  209. // Leading bits
  210. if (first!=0UL) {
  211. dat = FB_READL(dst);
  212. FB_WRITEL(comp(dat ^ val, dat, first), dst);
  213. dst++;
  214. n -= bits - dst_idx;
  215. }
  216. // Main chunk
  217. n /= bits;
  218. while (n >= 8) {
  219. FB_WRITEL(FB_READL(dst) ^ val, dst);
  220. dst++;
  221. FB_WRITEL(FB_READL(dst) ^ val, dst);
  222. dst++;
  223. FB_WRITEL(FB_READL(dst) ^ val, dst);
  224. dst++;
  225. FB_WRITEL(FB_READL(dst) ^ val, dst);
  226. dst++;
  227. FB_WRITEL(FB_READL(dst) ^ val, dst);
  228. dst++;
  229. FB_WRITEL(FB_READL(dst) ^ val, dst);
  230. dst++;
  231. FB_WRITEL(FB_READL(dst) ^ val, dst);
  232. dst++;
  233. FB_WRITEL(FB_READL(dst) ^ val, dst);
  234. dst++;
  235. n -= 8;
  236. }
  237. while (n--) {
  238. FB_WRITEL(FB_READL(dst) ^ val, dst);
  239. dst++;
  240. }
  241. // Trailing bits
  242. if (last) {
  243. dat = FB_READL(dst);
  244. FB_WRITEL(comp(dat ^ val, dat, last), dst);
  245. }
  246. }
  247. }
  248. /*
  249. * Unaligned generic pattern invert using 32/64-bit memory accesses
  250. * The pattern must have been expanded to a full 32/64-bit value
  251. * Left/right are the appropriate shifts to convert to the pattern to be
  252. * used for the next 32/64-bit word
  253. */
  254. static void
  255. bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
  256. int left, int right, unsigned n, int bits)
  257. {
  258. unsigned long first, last, dat;
  259. if (!n)
  260. return;
  261. first = FB_SHIFT_HIGH(~0UL, dst_idx);
  262. last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
  263. if (dst_idx+n <= bits) {
  264. // Single word
  265. if (last)
  266. first &= last;
  267. dat = FB_READL(dst);
  268. FB_WRITEL(comp(dat ^ pat, dat, first), dst);
  269. } else {
  270. // Multiple destination words
  271. // Leading bits
  272. if (first != 0UL) {
  273. dat = FB_READL(dst);
  274. FB_WRITEL(comp(dat ^ pat, dat, first), dst);
  275. dst++;
  276. pat = pat << left | pat >> right;
  277. n -= bits - dst_idx;
  278. }
  279. // Main chunk
  280. n /= bits;
  281. while (n >= 4) {
  282. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  283. dst++;
  284. pat = pat << left | pat >> right;
  285. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  286. dst++;
  287. pat = pat << left | pat >> right;
  288. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  289. dst++;
  290. pat = pat << left | pat >> right;
  291. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  292. dst++;
  293. pat = pat << left | pat >> right;
  294. n -= 4;
  295. }
  296. while (n--) {
  297. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  298. dst++;
  299. pat = pat << left | pat >> right;
  300. }
  301. // Trailing bits
  302. if (last) {
  303. dat = FB_READL(dst);
  304. FB_WRITEL(comp(dat ^ pat, dat, last), dst);
  305. }
  306. }
  307. }
  308. void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
  309. {
  310. unsigned long pat, fg;
  311. unsigned long width = rect->width, height = rect->height;
  312. int bits = BITS_PER_LONG, bytes = bits >> 3;
  313. u32 bpp = p->var.bits_per_pixel;
  314. unsigned long __iomem *dst;
  315. int dst_idx, left;
  316. if (p->state != FBINFO_STATE_RUNNING)
  317. return;
  318. if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
  319. p->fix.visual == FB_VISUAL_DIRECTCOLOR )
  320. fg = ((u32 *) (p->pseudo_palette))[rect->color];
  321. else
  322. fg = rect->color;
  323. pat = pixel_to_pat( bpp, fg);
  324. dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
  325. dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
  326. dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
  327. /* FIXME For now we support 1-32 bpp only */
  328. left = bits % bpp;
  329. if (p->fbops->fb_sync)
  330. p->fbops->fb_sync(p);
  331. if (!left) {
  332. void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
  333. unsigned long pat, unsigned n, int bits) = NULL;
  334. switch (rect->rop) {
  335. case ROP_XOR:
  336. fill_op32 = bitfill_aligned_rev;
  337. break;
  338. case ROP_COPY:
  339. fill_op32 = bitfill_aligned;
  340. break;
  341. default:
  342. printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
  343. fill_op32 = bitfill_aligned;
  344. break;
  345. }
  346. while (height--) {
  347. dst += dst_idx >> (ffs(bits) - 1);
  348. dst_idx &= (bits - 1);
  349. fill_op32(dst, dst_idx, pat, width*bpp, bits);
  350. dst_idx += p->fix.line_length*8;
  351. }
  352. } else {
  353. int right;
  354. int r;
  355. int rot = (left-dst_idx) % bpp;
  356. void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
  357. unsigned long pat, int left, int right,
  358. unsigned n, int bits) = NULL;
  359. /* rotate pattern to correct start position */
  360. pat = pat << rot | pat >> (bpp-rot);
  361. right = bpp-left;
  362. switch (rect->rop) {
  363. case ROP_XOR:
  364. fill_op = bitfill_unaligned_rev;
  365. break;
  366. case ROP_COPY:
  367. fill_op = bitfill_unaligned;
  368. break;
  369. default:
  370. printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
  371. fill_op = bitfill_unaligned;
  372. break;
  373. }
  374. while (height--) {
  375. dst += dst_idx >> (ffs(bits) - 1);
  376. dst_idx &= (bits - 1);
  377. fill_op(dst, dst_idx, pat, left, right,
  378. width*bpp, bits);
  379. r = (p->fix.line_length*8) % bpp;
  380. pat = pat << (bpp-r) | pat >> r;
  381. dst_idx += p->fix.line_length*8;
  382. }
  383. }
  384. }
  385. EXPORT_SYMBOL(cfb_fillrect);
  386. MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
  387. MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
  388. MODULE_LICENSE("GPL");