cfbfillrect.c 10 KB

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