drm_fourcc.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /*
  2. * Copyright (c) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  3. *
  4. * DRM core format related functions
  5. *
  6. * Permission to use, copy, modify, distribute, and sell this software and its
  7. * documentation for any purpose is hereby granted without fee, provided that
  8. * the above copyright notice appear in all copies and that both that copyright
  9. * notice and this permission notice appear in supporting documentation, and
  10. * that the name of the copyright holders not be used in advertising or
  11. * publicity pertaining to distribution of the software without specific,
  12. * written prior permission. The copyright holders make no representations
  13. * about the suitability of this software for any purpose. It is provided "as
  14. * is" without express or implied warranty.
  15. *
  16. * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  17. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  18. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  19. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  20. * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  21. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  22. * OF THIS SOFTWARE.
  23. */
  24. #include <linux/bug.h>
  25. #include <linux/ctype.h>
  26. #include <linux/export.h>
  27. #include <linux/kernel.h>
  28. #include <drm/drm_device.h>
  29. #include <drm/drm_fourcc.h>
  30. /**
  31. * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
  32. * @bpp: bits per pixels
  33. * @depth: bit depth per pixel
  34. *
  35. * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
  36. */
  37. uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
  38. {
  39. uint32_t fmt = DRM_FORMAT_INVALID;
  40. switch (bpp) {
  41. case 1:
  42. if (depth == 1)
  43. fmt = DRM_FORMAT_C1;
  44. break;
  45. case 2:
  46. if (depth == 2)
  47. fmt = DRM_FORMAT_C2;
  48. break;
  49. case 4:
  50. if (depth == 4)
  51. fmt = DRM_FORMAT_C4;
  52. break;
  53. case 8:
  54. if (depth == 8)
  55. fmt = DRM_FORMAT_C8;
  56. break;
  57. case 16:
  58. switch (depth) {
  59. case 15:
  60. fmt = DRM_FORMAT_XRGB1555;
  61. break;
  62. case 16:
  63. fmt = DRM_FORMAT_RGB565;
  64. break;
  65. default:
  66. break;
  67. }
  68. break;
  69. case 24:
  70. if (depth == 24)
  71. fmt = DRM_FORMAT_RGB888;
  72. break;
  73. case 32:
  74. switch (depth) {
  75. case 24:
  76. fmt = DRM_FORMAT_XRGB8888;
  77. break;
  78. case 30:
  79. fmt = DRM_FORMAT_XRGB2101010;
  80. break;
  81. case 32:
  82. fmt = DRM_FORMAT_ARGB8888;
  83. break;
  84. default:
  85. break;
  86. }
  87. break;
  88. default:
  89. break;
  90. }
  91. return fmt;
  92. }
  93. EXPORT_SYMBOL(drm_mode_legacy_fb_format);
  94. /**
  95. * drm_driver_legacy_fb_format - compute drm fourcc code from legacy description
  96. * @dev: DRM device
  97. * @bpp: bits per pixels
  98. * @depth: bit depth per pixel
  99. *
  100. * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
  101. * Unlike drm_mode_legacy_fb_format() this looks at the drivers mode_config,
  102. * and depending on the &drm_mode_config.quirk_addfb_prefer_host_byte_order flag
  103. * it returns little endian byte order or host byte order framebuffer formats.
  104. */
  105. uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
  106. uint32_t bpp, uint32_t depth)
  107. {
  108. uint32_t fmt = drm_mode_legacy_fb_format(bpp, depth);
  109. if (dev->mode_config.quirk_addfb_prefer_host_byte_order) {
  110. if (fmt == DRM_FORMAT_XRGB8888)
  111. fmt = DRM_FORMAT_HOST_XRGB8888;
  112. if (fmt == DRM_FORMAT_ARGB8888)
  113. fmt = DRM_FORMAT_HOST_ARGB8888;
  114. if (fmt == DRM_FORMAT_RGB565)
  115. fmt = DRM_FORMAT_HOST_RGB565;
  116. if (fmt == DRM_FORMAT_XRGB1555)
  117. fmt = DRM_FORMAT_HOST_XRGB1555;
  118. }
  119. if (dev->mode_config.quirk_addfb_prefer_xbgr_30bpp &&
  120. fmt == DRM_FORMAT_XRGB2101010)
  121. fmt = DRM_FORMAT_XBGR2101010;
  122. return fmt;
  123. }
  124. EXPORT_SYMBOL(drm_driver_legacy_fb_format);
  125. /**
  126. * drm_driver_color_mode_format - Compute DRM 4CC code from color mode
  127. * @dev: DRM device
  128. * @color_mode: command-line color mode
  129. *
  130. * Computes a DRM 4CC pixel format code for the given color mode using
  131. * drm_driver_color_mode(). The color mode is in the format used and the
  132. * kernel command line. It specifies the number of bits per pixel
  133. * and color depth in a single value.
  134. *
  135. * Useful in fbdev emulation code, since that deals in those values. The
  136. * helper does not consider YUV or other complicated formats. This means
  137. * only legacy formats are supported (fmt->depth is a legacy field), but
  138. * the framebuffer emulation can only deal with such formats, specifically
  139. * RGB/BGA formats.
  140. */
  141. uint32_t drm_driver_color_mode_format(struct drm_device *dev, unsigned int color_mode)
  142. {
  143. switch (color_mode) {
  144. case 15:
  145. return drm_driver_legacy_fb_format(dev, 16, 15);
  146. case 32:
  147. return drm_driver_legacy_fb_format(dev, 32, 24);
  148. default:
  149. return drm_driver_legacy_fb_format(dev, color_mode, color_mode);
  150. }
  151. }
  152. EXPORT_SYMBOL(drm_driver_color_mode_format);
  153. /*
  154. * Internal function to query information for a given format. See
  155. * drm_format_info() for the public API.
  156. */
  157. const struct drm_format_info *__drm_format_info(u32 format)
  158. {
  159. static const struct drm_format_info formats[] = {
  160. { .format = DRM_FORMAT_C1, .depth = 1, .num_planes = 1,
  161. .char_per_block = { 1, }, .block_w = { 8, }, .block_h = { 1, }, .hsub = 1, .vsub = 1, .is_color_indexed = true },
  162. { .format = DRM_FORMAT_C2, .depth = 2, .num_planes = 1,
  163. .char_per_block = { 1, }, .block_w = { 4, }, .block_h = { 1, }, .hsub = 1, .vsub = 1, .is_color_indexed = true },
  164. { .format = DRM_FORMAT_C4, .depth = 4, .num_planes = 1,
  165. .char_per_block = { 1, }, .block_w = { 2, }, .block_h = { 1, }, .hsub = 1, .vsub = 1, .is_color_indexed = true },
  166. { .format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1, .is_color_indexed = true },
  167. { .format = DRM_FORMAT_D1, .depth = 1, .num_planes = 1,
  168. .char_per_block = { 1, }, .block_w = { 8, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 },
  169. { .format = DRM_FORMAT_D2, .depth = 2, .num_planes = 1,
  170. .char_per_block = { 1, }, .block_w = { 4, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 },
  171. { .format = DRM_FORMAT_D4, .depth = 4, .num_planes = 1,
  172. .char_per_block = { 1, }, .block_w = { 2, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 },
  173. { .format = DRM_FORMAT_D8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 },
  174. { .format = DRM_FORMAT_R1, .depth = 1, .num_planes = 1,
  175. .char_per_block = { 1, }, .block_w = { 8, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 },
  176. { .format = DRM_FORMAT_R2, .depth = 2, .num_planes = 1,
  177. .char_per_block = { 1, }, .block_w = { 4, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 },
  178. { .format = DRM_FORMAT_R4, .depth = 4, .num_planes = 1,
  179. .char_per_block = { 1, }, .block_w = { 2, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 },
  180. { .format = DRM_FORMAT_R8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 },
  181. { .format = DRM_FORMAT_R10, .depth = 10, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  182. { .format = DRM_FORMAT_R12, .depth = 12, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  183. { .format = DRM_FORMAT_RGB332, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 },
  184. { .format = DRM_FORMAT_BGR233, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 },
  185. { .format = DRM_FORMAT_XRGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  186. { .format = DRM_FORMAT_XBGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  187. { .format = DRM_FORMAT_RGBX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  188. { .format = DRM_FORMAT_BGRX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  189. { .format = DRM_FORMAT_ARGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  190. { .format = DRM_FORMAT_ABGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  191. { .format = DRM_FORMAT_RGBA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  192. { .format = DRM_FORMAT_BGRA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  193. { .format = DRM_FORMAT_XRGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  194. { .format = DRM_FORMAT_XBGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  195. { .format = DRM_FORMAT_RGBX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  196. { .format = DRM_FORMAT_BGRX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  197. { .format = DRM_FORMAT_ARGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  198. { .format = DRM_FORMAT_ABGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  199. { .format = DRM_FORMAT_RGBA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  200. { .format = DRM_FORMAT_BGRA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  201. { .format = DRM_FORMAT_RGB565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  202. { .format = DRM_FORMAT_BGR565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  203. #ifdef __BIG_ENDIAN
  204. { .format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  205. { .format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  206. #endif
  207. { .format = DRM_FORMAT_RGB888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 },
  208. { .format = DRM_FORMAT_BGR888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 },
  209. { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  210. { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  211. { .format = DRM_FORMAT_RGBX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  212. { .format = DRM_FORMAT_BGRX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  213. { .format = DRM_FORMAT_RGB565_A8, .depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  214. { .format = DRM_FORMAT_BGR565_A8, .depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  215. { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  216. { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  217. { .format = DRM_FORMAT_RGBX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  218. { .format = DRM_FORMAT_BGRX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  219. { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  220. { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  221. { .format = DRM_FORMAT_RGBA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  222. { .format = DRM_FORMAT_BGRA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  223. { .format = DRM_FORMAT_RGB161616, .depth = 0,
  224. .num_planes = 1, .char_per_block = { 6, 0, 0 },
  225. .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
  226. .hsub = 1, .vsub = 1, .has_alpha = false },
  227. { .format = DRM_FORMAT_BGR161616, .depth = 0,
  228. .num_planes = 1, .char_per_block = { 6, 0, 0 },
  229. .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
  230. .hsub = 1, .vsub = 1, .has_alpha = false },
  231. { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  232. { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  233. { .format = DRM_FORMAT_RGBA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  234. { .format = DRM_FORMAT_BGRA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  235. { .format = DRM_FORMAT_XRGB16161616F, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1 },
  236. { .format = DRM_FORMAT_XBGR16161616F, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1 },
  237. { .format = DRM_FORMAT_ARGB16161616F, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  238. { .format = DRM_FORMAT_ABGR16161616F, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  239. { .format = DRM_FORMAT_AXBXGXRX106106106106, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  240. { .format = DRM_FORMAT_XRGB16161616, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1 },
  241. { .format = DRM_FORMAT_XBGR16161616, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1 },
  242. { .format = DRM_FORMAT_ARGB16161616, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  243. { .format = DRM_FORMAT_ABGR16161616, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  244. { .format = DRM_FORMAT_RGB888_A8, .depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  245. { .format = DRM_FORMAT_BGR888_A8, .depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  246. { .format = DRM_FORMAT_XRGB8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  247. { .format = DRM_FORMAT_XBGR8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  248. { .format = DRM_FORMAT_RGBX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  249. { .format = DRM_FORMAT_BGRX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
  250. { .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4, .is_yuv = true },
  251. { .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4, .is_yuv = true },
  252. { .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1, .is_yuv = true },
  253. { .format = DRM_FORMAT_YVU411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1, .is_yuv = true },
  254. { .format = DRM_FORMAT_YUV420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .is_yuv = true },
  255. { .format = DRM_FORMAT_YVU420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .is_yuv = true },
  256. { .format = DRM_FORMAT_YUV422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  257. { .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  258. { .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true },
  259. { .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true },
  260. { .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true },
  261. { .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true },
  262. { .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  263. { .format = DRM_FORMAT_NV61, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  264. { .format = DRM_FORMAT_NV24, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
  265. { .format = DRM_FORMAT_NV42, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
  266. { .format = DRM_FORMAT_YUYV, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  267. { .format = DRM_FORMAT_YVYU, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  268. { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  269. { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  270. { .format = DRM_FORMAT_XYUV8888, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
  271. { .format = DRM_FORMAT_VUY888, .depth = 0, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
  272. { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
  273. { .format = DRM_FORMAT_Y210, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  274. { .format = DRM_FORMAT_Y212, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  275. { .format = DRM_FORMAT_Y216, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
  276. { .format = DRM_FORMAT_Y410, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
  277. { .format = DRM_FORMAT_Y412, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
  278. { .format = DRM_FORMAT_Y416, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
  279. { .format = DRM_FORMAT_XVYU2101010, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
  280. { .format = DRM_FORMAT_XVYU12_16161616, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
  281. { .format = DRM_FORMAT_XVYU16161616, .depth = 0, .num_planes = 1, .cpp = { 8, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
  282. { .format = DRM_FORMAT_Y0L0, .depth = 0, .num_planes = 1,
  283. .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
  284. .hsub = 2, .vsub = 2, .has_alpha = true, .is_yuv = true },
  285. { .format = DRM_FORMAT_X0L0, .depth = 0, .num_planes = 1,
  286. .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
  287. .hsub = 2, .vsub = 2, .is_yuv = true },
  288. { .format = DRM_FORMAT_Y0L2, .depth = 0, .num_planes = 1,
  289. .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
  290. .hsub = 2, .vsub = 2, .has_alpha = true, .is_yuv = true },
  291. { .format = DRM_FORMAT_X0L2, .depth = 0, .num_planes = 1,
  292. .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
  293. .hsub = 2, .vsub = 2, .is_yuv = true },
  294. { .format = DRM_FORMAT_P010, .depth = 0, .num_planes = 2,
  295. .char_per_block = { 2, 4, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 },
  296. .hsub = 2, .vsub = 2, .is_yuv = true},
  297. { .format = DRM_FORMAT_P012, .depth = 0, .num_planes = 2,
  298. .char_per_block = { 2, 4, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 },
  299. .hsub = 2, .vsub = 2, .is_yuv = true},
  300. { .format = DRM_FORMAT_P016, .depth = 0, .num_planes = 2,
  301. .char_per_block = { 2, 4, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 },
  302. .hsub = 2, .vsub = 2, .is_yuv = true},
  303. { .format = DRM_FORMAT_P210, .depth = 0,
  304. .num_planes = 2, .char_per_block = { 2, 4, 0 },
  305. .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2,
  306. .vsub = 1, .is_yuv = true },
  307. { .format = DRM_FORMAT_VUY101010, .depth = 0,
  308. .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 1, .vsub = 1,
  309. .is_yuv = true },
  310. { .format = DRM_FORMAT_YUV420_8BIT, .depth = 0,
  311. .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 2, .vsub = 2,
  312. .is_yuv = true },
  313. { .format = DRM_FORMAT_YUV420_10BIT, .depth = 0,
  314. .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 2, .vsub = 2,
  315. .is_yuv = true },
  316. { .format = DRM_FORMAT_NV15, .depth = 0,
  317. .num_planes = 2, .char_per_block = { 5, 5, 0 },
  318. .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2,
  319. .vsub = 2, .is_yuv = true },
  320. { .format = DRM_FORMAT_NV20, .depth = 0,
  321. .num_planes = 2, .char_per_block = { 5, 5, 0 },
  322. .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2,
  323. .vsub = 1, .is_yuv = true },
  324. { .format = DRM_FORMAT_NV30, .depth = 0,
  325. .num_planes = 2, .char_per_block = { 5, 5, 0 },
  326. .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 1,
  327. .vsub = 1, .is_yuv = true },
  328. { .format = DRM_FORMAT_Q410, .depth = 0,
  329. .num_planes = 3, .char_per_block = { 2, 2, 2 },
  330. .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 1,
  331. .vsub = 1, .is_yuv = true },
  332. { .format = DRM_FORMAT_Q401, .depth = 0,
  333. .num_planes = 3, .char_per_block = { 2, 2, 2 },
  334. .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 1,
  335. .vsub = 1, .is_yuv = true },
  336. { .format = DRM_FORMAT_P030, .depth = 0, .num_planes = 2,
  337. .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 },
  338. .hsub = 2, .vsub = 2, .is_yuv = true},
  339. { .format = DRM_FORMAT_S010, .depth = 0, .num_planes = 3,
  340. .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
  341. .hsub = 2, .vsub = 2, .is_yuv = true},
  342. { .format = DRM_FORMAT_S210, .depth = 0, .num_planes = 3,
  343. .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
  344. .hsub = 2, .vsub = 1, .is_yuv = true},
  345. { .format = DRM_FORMAT_S410, .depth = 0, .num_planes = 3,
  346. .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
  347. .hsub = 1, .vsub = 1, .is_yuv = true},
  348. { .format = DRM_FORMAT_S012, .depth = 0, .num_planes = 3,
  349. .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
  350. .hsub = 2, .vsub = 2, .is_yuv = true},
  351. { .format = DRM_FORMAT_S212, .depth = 0, .num_planes = 3,
  352. .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
  353. .hsub = 2, .vsub = 1, .is_yuv = true},
  354. { .format = DRM_FORMAT_S412, .depth = 0, .num_planes = 3,
  355. .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
  356. .hsub = 1, .vsub = 1, .is_yuv = true},
  357. { .format = DRM_FORMAT_S016, .depth = 0, .num_planes = 3,
  358. .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
  359. .hsub = 2, .vsub = 2, .is_yuv = true},
  360. { .format = DRM_FORMAT_S216, .depth = 0, .num_planes = 3,
  361. .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
  362. .hsub = 2, .vsub = 1, .is_yuv = true},
  363. { .format = DRM_FORMAT_S416, .depth = 0, .num_planes = 3,
  364. .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
  365. .hsub = 1, .vsub = 1, .is_yuv = true},
  366. };
  367. unsigned int i;
  368. for (i = 0; i < ARRAY_SIZE(formats); ++i) {
  369. if (formats[i].format == format)
  370. return &formats[i];
  371. }
  372. return NULL;
  373. }
  374. /**
  375. * drm_format_info - query information for a given format
  376. * @format: pixel format (DRM_FORMAT_*)
  377. *
  378. * The caller should only pass a supported pixel format to this function.
  379. * Unsupported pixel formats will generate a warning in the kernel log.
  380. *
  381. * Returns:
  382. * The instance of struct drm_format_info that describes the pixel format, or
  383. * NULL if the format is unsupported.
  384. */
  385. const struct drm_format_info *drm_format_info(u32 format)
  386. {
  387. const struct drm_format_info *info;
  388. info = __drm_format_info(format);
  389. WARN_ON(!info);
  390. return info;
  391. }
  392. EXPORT_SYMBOL(drm_format_info);
  393. /**
  394. * drm_get_format_info - query information for a given framebuffer configuration
  395. * @dev: DRM device
  396. * @pixel_format: pixel format (DRM_FORMAT_*)
  397. * @modifier: modifier
  398. *
  399. * Returns:
  400. * The instance of struct drm_format_info that describes the pixel format, or
  401. * NULL if the format is unsupported.
  402. */
  403. const struct drm_format_info *
  404. drm_get_format_info(struct drm_device *dev,
  405. u32 pixel_format, u64 modifier)
  406. {
  407. const struct drm_format_info *info = NULL;
  408. if (dev->mode_config.funcs->get_format_info)
  409. info = dev->mode_config.funcs->get_format_info(pixel_format,
  410. modifier);
  411. if (!info)
  412. info = drm_format_info(pixel_format);
  413. return info;
  414. }
  415. EXPORT_SYMBOL(drm_get_format_info);
  416. /**
  417. * drm_format_info_block_width - width in pixels of block.
  418. * @info: pixel format info
  419. * @plane: plane index
  420. *
  421. * Returns:
  422. * The width in pixels of a block, depending on the plane index.
  423. */
  424. unsigned int drm_format_info_block_width(const struct drm_format_info *info,
  425. int plane)
  426. {
  427. if (!info || plane < 0 || plane >= info->num_planes)
  428. return 0;
  429. if (!info->block_w[plane])
  430. return 1;
  431. return info->block_w[plane];
  432. }
  433. EXPORT_SYMBOL(drm_format_info_block_width);
  434. /**
  435. * drm_format_info_block_height - height in pixels of a block
  436. * @info: pixel format info
  437. * @plane: plane index
  438. *
  439. * Returns:
  440. * The height in pixels of a block, depending on the plane index.
  441. */
  442. unsigned int drm_format_info_block_height(const struct drm_format_info *info,
  443. int plane)
  444. {
  445. if (!info || plane < 0 || plane >= info->num_planes)
  446. return 0;
  447. if (!info->block_h[plane])
  448. return 1;
  449. return info->block_h[plane];
  450. }
  451. EXPORT_SYMBOL(drm_format_info_block_height);
  452. /**
  453. * drm_format_info_bpp - number of bits per pixel
  454. * @info: pixel format info
  455. * @plane: plane index
  456. *
  457. * Returns:
  458. * The actual number of bits per pixel, depending on the plane index.
  459. */
  460. unsigned int drm_format_info_bpp(const struct drm_format_info *info, int plane)
  461. {
  462. if (!info || plane < 0 || plane >= info->num_planes)
  463. return 0;
  464. return info->char_per_block[plane] * 8 /
  465. (drm_format_info_block_width(info, plane) *
  466. drm_format_info_block_height(info, plane));
  467. }
  468. EXPORT_SYMBOL(drm_format_info_bpp);
  469. /**
  470. * drm_format_info_min_pitch - computes the minimum required pitch in bytes
  471. * @info: pixel format info
  472. * @plane: plane index
  473. * @buffer_width: buffer width in pixels
  474. *
  475. * Returns:
  476. * The minimum required pitch in bytes for a buffer by taking into consideration
  477. * the pixel format information and the buffer width.
  478. */
  479. uint64_t drm_format_info_min_pitch(const struct drm_format_info *info,
  480. int plane, unsigned int buffer_width)
  481. {
  482. if (!info || plane < 0 || plane >= info->num_planes)
  483. return 0;
  484. return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
  485. drm_format_info_block_width(info, plane) *
  486. drm_format_info_block_height(info, plane));
  487. }
  488. EXPORT_SYMBOL(drm_format_info_min_pitch);