cfbfillrect.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  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. * Also need to add code to deal with cards endians that are different than
  13. * the native cpu endians. I also need to deal with MSB position in the word.
  14. *
  15. * Modified by Harm Hanemaaijer (fgenfb@yahoo.com 2013):
  16. *
  17. * The previous implementation was doing reads from the uncached framebuffer,
  18. * even for simple fills, which for performance reasons, on most platforms,
  19. * is ill-advised unless strictly necessary to conform to the raster operation.
  20. * In these circumstances, doing 64-bit access on 64-bit systems does not serve
  21. * much purpose except for probing for corner-case bugs and race conditions in
  22. * the hardware's framebuffer bus implementation. For 16bpp, it is better to
  23. * take advantage of write-combining features of the framebuffer and write a
  24. * half-word if required for the left and right edges.
  25. *
  26. * Additionally, on most platforms, integer divides are relatively slow so are
  27. * best avoided, especially in inner loops.
  28. */
  29. #include <linux/module.h>
  30. #include <linux/string.h>
  31. #include <linux/fb.h>
  32. #include <asm/types.h>
  33. #include "fb_draw.h"
  34. #if BITS_PER_LONG == 32
  35. # define FB_WRITEL fb_writel
  36. # define FB_READL fb_readl
  37. #else
  38. # define FB_WRITEL fb_writeq
  39. # define FB_READL fb_readq
  40. #endif
  41. /*
  42. * Aligned pattern fill using 32/64-bit memory accesses
  43. */
  44. static void
  45. bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
  46. unsigned long pat, unsigned n, int bits, u32 bswapmask)
  47. {
  48. unsigned long first, last;
  49. if (!n)
  50. return;
  51. first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
  52. last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
  53. if (dst_idx+n <= bits) {
  54. // Single word
  55. if (last)
  56. first &= last;
  57. FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
  58. } else {
  59. // Multiple destination words
  60. // Leading bits
  61. if (first!= ~0UL) {
  62. FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
  63. dst++;
  64. n -= bits - dst_idx;
  65. }
  66. // Main chunk
  67. n /= bits;
  68. while (n >= 8) {
  69. FB_WRITEL(pat, dst++);
  70. FB_WRITEL(pat, dst++);
  71. FB_WRITEL(pat, dst++);
  72. FB_WRITEL(pat, dst++);
  73. FB_WRITEL(pat, dst++);
  74. FB_WRITEL(pat, dst++);
  75. FB_WRITEL(pat, dst++);
  76. FB_WRITEL(pat, dst++);
  77. n -= 8;
  78. }
  79. while (n--)
  80. FB_WRITEL(pat, dst++);
  81. // Trailing bits
  82. if (last)
  83. FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
  84. }
  85. }
  86. /*
  87. * Unaligned generic pattern fill using 32/64-bit memory accesses
  88. * The pattern must have been expanded to a full 32/64-bit value
  89. * Left/right are the appropriate shifts to convert to the pattern to be
  90. * used for the next 32/64-bit word
  91. */
  92. static void
  93. bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
  94. unsigned long pat, int left, int right, unsigned n, int bits)
  95. {
  96. unsigned long first, last;
  97. if (!n)
  98. return;
  99. first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  100. last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
  101. if (dst_idx+n <= bits) {
  102. // Single word
  103. if (last)
  104. first &= last;
  105. FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
  106. } else {
  107. // Multiple destination words
  108. // Leading bits
  109. if (first) {
  110. FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
  111. dst++;
  112. pat = pat << left | pat >> right;
  113. n -= bits - dst_idx;
  114. }
  115. // Main chunk
  116. n /= bits;
  117. while (n >= 4) {
  118. FB_WRITEL(pat, dst++);
  119. pat = pat << left | pat >> right;
  120. FB_WRITEL(pat, dst++);
  121. pat = pat << left | pat >> right;
  122. FB_WRITEL(pat, dst++);
  123. pat = pat << left | pat >> right;
  124. FB_WRITEL(pat, dst++);
  125. pat = pat << left | pat >> right;
  126. n -= 4;
  127. }
  128. while (n--) {
  129. FB_WRITEL(pat, dst++);
  130. pat = pat << left | pat >> right;
  131. }
  132. // Trailing bits
  133. if (last)
  134. FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
  135. }
  136. }
  137. /*
  138. * Aligned pattern invert using 32/64-bit memory accesses
  139. */
  140. static void
  141. bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
  142. int dst_idx, unsigned long pat, unsigned n, int bits,
  143. u32 bswapmask)
  144. {
  145. unsigned long val = pat, dat;
  146. unsigned long first, last;
  147. if (!n)
  148. return;
  149. first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
  150. last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
  151. if (dst_idx+n <= bits) {
  152. // Single word
  153. if (last)
  154. first &= last;
  155. dat = FB_READL(dst);
  156. FB_WRITEL(comp(dat ^ val, dat, first), dst);
  157. } else {
  158. // Multiple destination words
  159. // Leading bits
  160. if (first!=0UL) {
  161. dat = FB_READL(dst);
  162. FB_WRITEL(comp(dat ^ val, dat, first), dst);
  163. dst++;
  164. n -= bits - dst_idx;
  165. }
  166. // Main chunk
  167. n /= bits;
  168. while (n >= 8) {
  169. FB_WRITEL(FB_READL(dst) ^ val, dst);
  170. dst++;
  171. FB_WRITEL(FB_READL(dst) ^ val, dst);
  172. dst++;
  173. FB_WRITEL(FB_READL(dst) ^ val, dst);
  174. dst++;
  175. FB_WRITEL(FB_READL(dst) ^ val, dst);
  176. dst++;
  177. FB_WRITEL(FB_READL(dst) ^ val, dst);
  178. dst++;
  179. FB_WRITEL(FB_READL(dst) ^ val, dst);
  180. dst++;
  181. FB_WRITEL(FB_READL(dst) ^ val, dst);
  182. dst++;
  183. FB_WRITEL(FB_READL(dst) ^ val, dst);
  184. dst++;
  185. n -= 8;
  186. }
  187. while (n--) {
  188. FB_WRITEL(FB_READL(dst) ^ val, dst);
  189. dst++;
  190. }
  191. // Trailing bits
  192. if (last) {
  193. dat = FB_READL(dst);
  194. FB_WRITEL(comp(dat ^ val, dat, last), dst);
  195. }
  196. }
  197. }
  198. /*
  199. * Unaligned generic pattern invert using 32/64-bit memory accesses
  200. * The pattern must have been expanded to a full 32/64-bit value
  201. * Left/right are the appropriate shifts to convert to the pattern to be
  202. * used for the next 32/64-bit word
  203. */
  204. static void
  205. bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
  206. int dst_idx, unsigned long pat, int left, int right,
  207. unsigned n, int bits)
  208. {
  209. unsigned long first, last, dat;
  210. if (!n)
  211. return;
  212. first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  213. last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
  214. if (dst_idx+n <= bits) {
  215. // Single word
  216. if (last)
  217. first &= last;
  218. dat = FB_READL(dst);
  219. FB_WRITEL(comp(dat ^ pat, dat, first), dst);
  220. } else {
  221. // Multiple destination words
  222. // Leading bits
  223. if (first != 0UL) {
  224. dat = FB_READL(dst);
  225. FB_WRITEL(comp(dat ^ pat, dat, first), dst);
  226. dst++;
  227. pat = pat << left | pat >> right;
  228. n -= bits - dst_idx;
  229. }
  230. // Main chunk
  231. n /= bits;
  232. while (n >= 4) {
  233. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  234. dst++;
  235. pat = pat << left | pat >> right;
  236. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  237. dst++;
  238. pat = pat << left | pat >> right;
  239. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  240. dst++;
  241. pat = pat << left | pat >> right;
  242. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  243. dst++;
  244. pat = pat << left | pat >> right;
  245. n -= 4;
  246. }
  247. while (n--) {
  248. FB_WRITEL(FB_READL(dst) ^ pat, dst);
  249. dst++;
  250. pat = pat << left | pat >> right;
  251. }
  252. // Trailing bits
  253. if (last) {
  254. dat = FB_READL(dst);
  255. FB_WRITEL(comp(dat ^ pat, dat, last), dst);
  256. }
  257. }
  258. }
  259. static void
  260. fast_fill16(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
  261. unsigned long pat, u32 width_in_bits, u32 height)
  262. {
  263. for (; height--; dst_idx += p->fix.line_length * 8) {
  264. u32 n;
  265. unsigned long __iomem *dstp;
  266. u32 last_bits;
  267. dst += dst_idx >> (ffs(BITS_PER_LONG) - 1);
  268. dst_idx &= (BITS_PER_LONG - 1);
  269. n = width_in_bits;
  270. dstp = dst;
  271. #if BITS_PER_LONG == 32
  272. if (dst_idx) {
  273. fb_writew(pat, (u16 *)dstp + 1);
  274. dstp++;
  275. n -= 16;
  276. if (n == 0)
  277. continue;
  278. }
  279. else if (n == 16) {
  280. fb_writew(pat, (u16 *)dstp);
  281. continue;
  282. }
  283. #else /* BITS_PER_LONG == 64 */
  284. if (dst_idx) {
  285. if (dst_idx == 16) {
  286. fb_writew(pat, (u16 *)dstp + 1);
  287. if (n == 32) {
  288. fb_writew(pat, (u16 *)dstp + 2);
  289. continue;
  290. }
  291. fb_writel(pat, (u32 *)dstp + 1);
  292. }
  293. else if (dst_idx == 32) {
  294. if (n == 16) {
  295. fb_writew(pat, (u16 *)dstp + 2);
  296. continue;
  297. }
  298. fb_writel(pat, (u32 *)dstp + 1);
  299. }
  300. else if (dst_idx == 48) {
  301. fb_writew(pat, (u16 *)dstp + 3);
  302. dstp++;
  303. n -= 64 - dist_idx;
  304. if (n == 0)
  305. continue;
  306. }
  307. #endif
  308. n /= BITS_PER_LONG;
  309. while (n >= 8) {
  310. FB_WRITEL(pat, dstp++);
  311. FB_WRITEL(pat, dstp++);
  312. FB_WRITEL(pat, dstp++);
  313. FB_WRITEL(pat, dstp++);
  314. FB_WRITEL(pat, dstp++);
  315. FB_WRITEL(pat, dstp++);
  316. FB_WRITEL(pat, dstp++);
  317. FB_WRITEL(pat, dstp++);
  318. n -= 8;
  319. }
  320. while (n--)
  321. FB_WRITEL(pat, dstp++);
  322. last_bits = (dst_idx + width_in_bits) % BITS_PER_LONG;
  323. #if BITS_PER_LONG == 32
  324. if (last_bits)
  325. fb_writew(pat, dstp);
  326. #else /* BITS_PER_LONG == 64 */
  327. if (last_bits & 32) {
  328. fb_writel(pat, dstp);
  329. if (last_bits & 16)
  330. fb_writew(pat, (u16 *)dstp + 2);
  331. }
  332. else if (last_bits & 16)
  333. fb_writew(pat, dstp);
  334. #endif
  335. }
  336. }
  337. static void
  338. fast_fill32(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
  339. unsigned long pat, u32 width_in_bits, u32 height)
  340. {
  341. for (; height--; dst_idx += p->fix.line_length * 8) {
  342. u32 n;
  343. unsigned long __iomem *dstp;
  344. dst += dst_idx >> (ffs(BITS_PER_LONG) - 1);
  345. dst_idx &= (BITS_PER_LONG - 1);
  346. n = width_in_bits;
  347. dstp = dst;
  348. #if BITS_PER_LONG == 64
  349. if (dst_idx) {
  350. fb_writel(pat, (u32 *)dstp + 1);
  351. dstp++;
  352. n -= 32;
  353. if (n == 0)
  354. continue;
  355. }
  356. else if (n == 32) {
  357. fb_writel(pat, dstp);
  358. continue;
  359. }
  360. #endif
  361. n /= BITS_PER_LONG;
  362. while (n >= 8) {
  363. FB_WRITEL(pat, dstp++);
  364. FB_WRITEL(pat, dstp++);
  365. FB_WRITEL(pat, dstp++);
  366. FB_WRITEL(pat, dstp++);
  367. FB_WRITEL(pat, dstp++);
  368. FB_WRITEL(pat, dstp++);
  369. FB_WRITEL(pat, dstp++);
  370. FB_WRITEL(pat, dstp++);
  371. n -= 8;
  372. }
  373. while (n--)
  374. FB_WRITEL(pat, dstp++);
  375. #if BITS_PER_LONG == 64
  376. if ((dst_idx + width_in_bits) % 64)
  377. fb_writel(pat, dstp);
  378. #endif
  379. }
  380. }
  381. void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
  382. {
  383. unsigned long pat, pat2, fg;
  384. unsigned long width = rect->width, height = rect->height;
  385. int bits = BITS_PER_LONG, bytes = bits >> 3;
  386. u32 bpp = p->var.bits_per_pixel;
  387. unsigned long __iomem *dst;
  388. int dst_idx, left;
  389. if (p->state != FBINFO_STATE_RUNNING)
  390. return;
  391. if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
  392. p->fix.visual == FB_VISUAL_DIRECTCOLOR )
  393. fg = ((u32 *) (p->pseudo_palette))[rect->color];
  394. else
  395. fg = rect->color;
  396. pat = pixel_to_pat(bpp, fg);
  397. dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
  398. dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
  399. dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
  400. /* FIXME For now we support 1-32 bpp only */
  401. if (p->fbops->fb_sync)
  402. p->fbops->fb_sync(p);
  403. /*
  404. * Note: fb_be_math(p) could be used to check fb endianness, but
  405. * __LITTLE_ENDIAN is used later in the function, so also use it here.
  406. */
  407. #if !defined(CONFIG_FB_CFB_REV_PIXELS_IN_BYTE) && defined(__LITTLE_ENDIAN)
  408. if (rect->rop == ROP_COPY) {
  409. if (bpp == 16) {
  410. fast_fill16(p, dst, dst_idx, pat, width * 16, height);
  411. return;
  412. }
  413. else if (bpp == 32) {
  414. fast_fill32(p, dst, dst_idx, pat, width * 32, height);
  415. return;
  416. }
  417. }
  418. #endif
  419. left = bits % bpp;
  420. if (!left) {
  421. u32 bswapmask = fb_compute_bswapmask(p);
  422. void (*fill_op32)(struct fb_info *p,
  423. unsigned long __iomem *dst, int dst_idx,
  424. unsigned long pat, unsigned n, int bits,
  425. u32 bswapmask) = NULL;
  426. switch (rect->rop) {
  427. case ROP_XOR:
  428. fill_op32 = bitfill_aligned_rev;
  429. break;
  430. case ROP_COPY:
  431. fill_op32 = bitfill_aligned;
  432. break;
  433. default:
  434. printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
  435. fill_op32 = bitfill_aligned;
  436. break;
  437. }
  438. while (height--) {
  439. dst += dst_idx >> (ffs(bits) - 1);
  440. dst_idx &= (bits - 1);
  441. fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
  442. bswapmask);
  443. dst_idx += p->fix.line_length*8;
  444. }
  445. } else {
  446. int right, r;
  447. void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
  448. int dst_idx, unsigned long pat, int left,
  449. int right, unsigned n, int bits) = NULL;
  450. #ifdef __LITTLE_ENDIAN
  451. right = left;
  452. left = bpp - right;
  453. #else
  454. right = bpp - left;
  455. #endif
  456. switch (rect->rop) {
  457. case ROP_XOR:
  458. fill_op = bitfill_unaligned_rev;
  459. break;
  460. case ROP_COPY:
  461. fill_op = bitfill_unaligned;
  462. break;
  463. default:
  464. printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
  465. fill_op = bitfill_unaligned;
  466. break;
  467. }
  468. while (height--) {
  469. dst += dst_idx / bits;
  470. dst_idx &= (bits - 1);
  471. r = dst_idx % bpp;
  472. /* rotate pattern to the correct start position */
  473. pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
  474. fill_op(p, dst, dst_idx, pat2, left, right,
  475. width*bpp, bits);
  476. dst_idx += p->fix.line_length*8;
  477. }
  478. }
  479. }
  480. EXPORT_SYMBOL(cfb_fillrect);
  481. MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
  482. MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
  483. MODULE_LICENSE("GPL");