drm_format_helper.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // SPDX-License-Identifier: GPL-2.0 or MIT
  2. /*
  3. * Copyright (C) 2016 Noralf Trønnes
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. */
  10. #include <linux/module.h>
  11. #include <linux/slab.h>
  12. #include <linux/io.h>
  13. #include <drm/drm_format_helper.h>
  14. #include <drm/drm_framebuffer.h>
  15. #include <drm/drm_fourcc.h>
  16. #include <drm/drm_rect.h>
  17. static unsigned int clip_offset(struct drm_rect *clip,
  18. unsigned int pitch, unsigned int cpp)
  19. {
  20. return clip->y1 * pitch + clip->x1 * cpp;
  21. }
  22. /**
  23. * drm_fb_memcpy - Copy clip buffer
  24. * @dst: Destination buffer
  25. * @vaddr: Source buffer
  26. * @fb: DRM framebuffer
  27. * @clip: Clip rectangle area to copy
  28. *
  29. * This function does not apply clipping on dst, i.e. the destination
  30. * is a small buffer containing the clip rect only.
  31. */
  32. void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
  33. struct drm_rect *clip)
  34. {
  35. unsigned int cpp = fb->format->cpp[0];
  36. size_t len = (clip->x2 - clip->x1) * cpp;
  37. unsigned int y, lines = clip->y2 - clip->y1;
  38. vaddr += clip_offset(clip, fb->pitches[0], cpp);
  39. for (y = 0; y < lines; y++) {
  40. memcpy(dst, vaddr, len);
  41. vaddr += fb->pitches[0];
  42. dst += len;
  43. }
  44. }
  45. EXPORT_SYMBOL(drm_fb_memcpy);
  46. /**
  47. * drm_fb_memcpy_dstclip - Copy clip buffer
  48. * @dst: Destination buffer (iomem)
  49. * @vaddr: Source buffer
  50. * @fb: DRM framebuffer
  51. * @clip: Clip rectangle area to copy
  52. *
  53. * This function applies clipping on dst, i.e. the destination is a
  54. * full (iomem) framebuffer but only the clip rect content is copied over.
  55. */
  56. void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
  57. struct drm_framebuffer *fb,
  58. struct drm_rect *clip)
  59. {
  60. unsigned int cpp = fb->format->cpp[0];
  61. unsigned int offset = clip_offset(clip, fb->pitches[0], cpp);
  62. size_t len = (clip->x2 - clip->x1) * cpp;
  63. unsigned int y, lines = clip->y2 - clip->y1;
  64. vaddr += offset;
  65. dst += offset;
  66. for (y = 0; y < lines; y++) {
  67. memcpy_toio(dst, vaddr, len);
  68. vaddr += fb->pitches[0];
  69. dst += fb->pitches[0];
  70. }
  71. }
  72. EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
  73. /**
  74. * drm_fb_swab - Swap bytes into clip buffer
  75. * @dst: Destination buffer
  76. * @src: Source buffer
  77. * @fb: DRM framebuffer
  78. * @clip: Clip rectangle area to copy
  79. * @cached: Source buffer is mapped cached (eg. not write-combined)
  80. *
  81. * If @cached is false a temporary buffer is used to cache one pixel line at a
  82. * time to speed up slow uncached reads.
  83. *
  84. * This function does not apply clipping on dst, i.e. the destination
  85. * is a small buffer containing the clip rect only.
  86. */
  87. void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb,
  88. struct drm_rect *clip, bool cached)
  89. {
  90. u8 cpp = fb->format->cpp[0];
  91. size_t len = drm_rect_width(clip) * cpp;
  92. u16 *src16, *dst16 = dst;
  93. u32 *src32, *dst32 = dst;
  94. unsigned int x, y;
  95. void *buf = NULL;
  96. if (WARN_ON_ONCE(cpp != 2 && cpp != 4))
  97. return;
  98. if (!cached)
  99. buf = kmalloc(len, GFP_KERNEL);
  100. src += clip_offset(clip, fb->pitches[0], cpp);
  101. for (y = clip->y1; y < clip->y2; y++) {
  102. if (buf) {
  103. memcpy(buf, src, len);
  104. src16 = buf;
  105. src32 = buf;
  106. } else {
  107. src16 = src;
  108. src32 = src;
  109. }
  110. for (x = clip->x1; x < clip->x2; x++) {
  111. if (cpp == 4)
  112. *dst32++ = swab32(*src32++);
  113. else
  114. *dst16++ = swab16(*src16++);
  115. }
  116. src += fb->pitches[0];
  117. }
  118. kfree(buf);
  119. }
  120. EXPORT_SYMBOL(drm_fb_swab);
  121. static void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf,
  122. unsigned int pixels,
  123. bool swab)
  124. {
  125. unsigned int x;
  126. u16 val16;
  127. for (x = 0; x < pixels; x++) {
  128. val16 = ((sbuf[x] & 0x00F80000) >> 8) |
  129. ((sbuf[x] & 0x0000FC00) >> 5) |
  130. ((sbuf[x] & 0x000000F8) >> 3);
  131. if (swab)
  132. dbuf[x] = swab16(val16);
  133. else
  134. dbuf[x] = val16;
  135. }
  136. }
  137. /**
  138. * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
  139. * @dst: RGB565 destination buffer
  140. * @vaddr: XRGB8888 source buffer
  141. * @fb: DRM framebuffer
  142. * @clip: Clip rectangle area to copy
  143. * @swab: Swap bytes
  144. *
  145. * Drivers can use this function for RGB565 devices that don't natively
  146. * support XRGB8888.
  147. *
  148. * This function does not apply clipping on dst, i.e. the destination
  149. * is a small buffer containing the clip rect only.
  150. */
  151. void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
  152. struct drm_framebuffer *fb,
  153. struct drm_rect *clip, bool swab)
  154. {
  155. size_t linepixels = clip->x2 - clip->x1;
  156. size_t src_len = linepixels * sizeof(u32);
  157. size_t dst_len = linepixels * sizeof(u16);
  158. unsigned y, lines = clip->y2 - clip->y1;
  159. void *sbuf;
  160. /*
  161. * The cma memory is write-combined so reads are uncached.
  162. * Speed up by fetching one line at a time.
  163. */
  164. sbuf = kmalloc(src_len, GFP_KERNEL);
  165. if (!sbuf)
  166. return;
  167. vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
  168. for (y = 0; y < lines; y++) {
  169. memcpy(sbuf, vaddr, src_len);
  170. drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels, swab);
  171. vaddr += fb->pitches[0];
  172. dst += dst_len;
  173. }
  174. kfree(sbuf);
  175. }
  176. EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
  177. /**
  178. * drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer
  179. * @dst: RGB565 destination buffer (iomem)
  180. * @dst_pitch: destination buffer pitch
  181. * @vaddr: XRGB8888 source buffer
  182. * @fb: DRM framebuffer
  183. * @clip: Clip rectangle area to copy
  184. * @swab: Swap bytes
  185. *
  186. * Drivers can use this function for RGB565 devices that don't natively
  187. * support XRGB8888.
  188. *
  189. * This function applies clipping on dst, i.e. the destination is a
  190. * full (iomem) framebuffer but only the clip rect content is copied over.
  191. */
  192. void drm_fb_xrgb8888_to_rgb565_dstclip(void __iomem *dst, unsigned int dst_pitch,
  193. void *vaddr, struct drm_framebuffer *fb,
  194. struct drm_rect *clip, bool swab)
  195. {
  196. size_t linepixels = clip->x2 - clip->x1;
  197. size_t dst_len = linepixels * sizeof(u16);
  198. unsigned y, lines = clip->y2 - clip->y1;
  199. void *dbuf;
  200. dbuf = kmalloc(dst_len, GFP_KERNEL);
  201. if (!dbuf)
  202. return;
  203. vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
  204. dst += clip_offset(clip, dst_pitch, sizeof(u16));
  205. for (y = 0; y < lines; y++) {
  206. drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels, swab);
  207. memcpy_toio(dst, dbuf, dst_len);
  208. vaddr += fb->pitches[0];
  209. dst += dst_len;
  210. }
  211. kfree(dbuf);
  212. }
  213. EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
  214. static void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf,
  215. unsigned int pixels)
  216. {
  217. unsigned int x;
  218. for (x = 0; x < pixels; x++) {
  219. *dbuf++ = (sbuf[x] & 0x000000FF) >> 0;
  220. *dbuf++ = (sbuf[x] & 0x0000FF00) >> 8;
  221. *dbuf++ = (sbuf[x] & 0x00FF0000) >> 16;
  222. }
  223. }
  224. /**
  225. * drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer
  226. * @dst: RGB565 destination buffer (iomem)
  227. * @dst_pitch: destination buffer pitch
  228. * @vaddr: XRGB8888 source buffer
  229. * @fb: DRM framebuffer
  230. * @clip: Clip rectangle area to copy
  231. *
  232. * Drivers can use this function for RGB888 devices that don't natively
  233. * support XRGB8888.
  234. *
  235. * This function applies clipping on dst, i.e. the destination is a
  236. * full (iomem) framebuffer but only the clip rect content is copied over.
  237. */
  238. void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch,
  239. void *vaddr, struct drm_framebuffer *fb,
  240. struct drm_rect *clip)
  241. {
  242. size_t linepixels = clip->x2 - clip->x1;
  243. size_t dst_len = linepixels * 3;
  244. unsigned y, lines = clip->y2 - clip->y1;
  245. void *dbuf;
  246. dbuf = kmalloc(dst_len, GFP_KERNEL);
  247. if (!dbuf)
  248. return;
  249. vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
  250. dst += clip_offset(clip, dst_pitch, sizeof(u16));
  251. for (y = 0; y < lines; y++) {
  252. drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels);
  253. memcpy_toio(dst, dbuf, dst_len);
  254. vaddr += fb->pitches[0];
  255. dst += dst_len;
  256. }
  257. kfree(dbuf);
  258. }
  259. EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip);
  260. /**
  261. * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
  262. * @dst: 8-bit grayscale destination buffer
  263. * @vaddr: XRGB8888 source buffer
  264. * @fb: DRM framebuffer
  265. * @clip: Clip rectangle area to copy
  266. *
  267. * Drm doesn't have native monochrome or grayscale support.
  268. * Such drivers can announce the commonly supported XR24 format to userspace
  269. * and use this function to convert to the native format.
  270. *
  271. * Monochrome drivers will use the most significant bit,
  272. * where 1 means foreground color and 0 background color.
  273. *
  274. * ITU BT.601 is used for the RGB -> luma (brightness) conversion.
  275. */
  276. void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
  277. struct drm_rect *clip)
  278. {
  279. unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
  280. unsigned int x, y;
  281. void *buf;
  282. u32 *src;
  283. if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
  284. return;
  285. /*
  286. * The cma memory is write-combined so reads are uncached.
  287. * Speed up by fetching one line at a time.
  288. */
  289. buf = kmalloc(len, GFP_KERNEL);
  290. if (!buf)
  291. return;
  292. for (y = clip->y1; y < clip->y2; y++) {
  293. src = vaddr + (y * fb->pitches[0]);
  294. src += clip->x1;
  295. memcpy(buf, src, len);
  296. src = buf;
  297. for (x = clip->x1; x < clip->x2; x++) {
  298. u8 r = (*src & 0x00ff0000) >> 16;
  299. u8 g = (*src & 0x0000ff00) >> 8;
  300. u8 b = *src & 0x000000ff;
  301. /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
  302. *dst++ = (3 * r + 6 * g + b) / 10;
  303. src++;
  304. }
  305. }
  306. kfree(buf);
  307. }
  308. EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);