drm_fourcc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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/drmP.h>
  29. #include <drm/drm_fourcc.h>
  30. static char printable_char(int c)
  31. {
  32. return isascii(c) && isprint(c) ? c : '?';
  33. }
  34. /**
  35. * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
  36. * @bpp: bits per pixels
  37. * @depth: bit depth per pixel
  38. *
  39. * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
  40. * Useful in fbdev emulation code, since that deals in those values.
  41. */
  42. uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
  43. {
  44. uint32_t fmt;
  45. switch (bpp) {
  46. case 8:
  47. fmt = DRM_FORMAT_C8;
  48. break;
  49. case 16:
  50. if (depth == 15)
  51. fmt = DRM_FORMAT_XRGB1555;
  52. else
  53. fmt = DRM_FORMAT_RGB565;
  54. break;
  55. case 24:
  56. fmt = DRM_FORMAT_RGB888;
  57. break;
  58. case 32:
  59. if (depth == 24)
  60. fmt = DRM_FORMAT_XRGB8888;
  61. else if (depth == 30)
  62. fmt = DRM_FORMAT_XRGB2101010;
  63. else
  64. fmt = DRM_FORMAT_ARGB8888;
  65. break;
  66. default:
  67. DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
  68. fmt = DRM_FORMAT_XRGB8888;
  69. break;
  70. }
  71. return fmt;
  72. }
  73. EXPORT_SYMBOL(drm_mode_legacy_fb_format);
  74. /**
  75. * drm_get_format_name - return a string for drm fourcc format
  76. * @format: format to compute name of
  77. *
  78. * Note that the buffer returned by this function is owned by the caller
  79. * and will need to be freed using kfree().
  80. */
  81. char *drm_get_format_name(uint32_t format)
  82. {
  83. char *buf = kmalloc(32, GFP_KERNEL);
  84. snprintf(buf, 32,
  85. "%c%c%c%c %s-endian (0x%08x)",
  86. printable_char(format & 0xff),
  87. printable_char((format >> 8) & 0xff),
  88. printable_char((format >> 16) & 0xff),
  89. printable_char((format >> 24) & 0x7f),
  90. format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little",
  91. format);
  92. return buf;
  93. }
  94. EXPORT_SYMBOL(drm_get_format_name);
  95. /*
  96. * Internal function to query information for a given format. See
  97. * drm_format_info() for the public API.
  98. */
  99. const struct drm_format_info *__drm_format_info(u32 format)
  100. {
  101. static const struct drm_format_info formats[] = {
  102. { .format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 },
  103. { .format = DRM_FORMAT_RGB332, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 },
  104. { .format = DRM_FORMAT_BGR233, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 },
  105. { .format = DRM_FORMAT_XRGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  106. { .format = DRM_FORMAT_XBGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  107. { .format = DRM_FORMAT_RGBX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  108. { .format = DRM_FORMAT_BGRX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  109. { .format = DRM_FORMAT_ARGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  110. { .format = DRM_FORMAT_ABGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  111. { .format = DRM_FORMAT_RGBA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  112. { .format = DRM_FORMAT_BGRA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  113. { .format = DRM_FORMAT_XRGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  114. { .format = DRM_FORMAT_XBGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  115. { .format = DRM_FORMAT_RGBX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  116. { .format = DRM_FORMAT_BGRX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  117. { .format = DRM_FORMAT_ARGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  118. { .format = DRM_FORMAT_ABGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  119. { .format = DRM_FORMAT_RGBA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  120. { .format = DRM_FORMAT_BGRA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  121. { .format = DRM_FORMAT_RGB565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  122. { .format = DRM_FORMAT_BGR565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
  123. { .format = DRM_FORMAT_RGB888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 },
  124. { .format = DRM_FORMAT_BGR888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 },
  125. { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  126. { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  127. { .format = DRM_FORMAT_RGBX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  128. { .format = DRM_FORMAT_BGRX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  129. { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  130. { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  131. { .format = DRM_FORMAT_RGBX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  132. { .format = DRM_FORMAT_BGRX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  133. { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  134. { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  135. { .format = DRM_FORMAT_RGBA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  136. { .format = DRM_FORMAT_BGRA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  137. { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  138. { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  139. { .format = DRM_FORMAT_RGBA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  140. { .format = DRM_FORMAT_BGRA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  141. { .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 },
  142. { .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 },
  143. { .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 },
  144. { .format = DRM_FORMAT_YVU411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 },
  145. { .format = DRM_FORMAT_YUV420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2 },
  146. { .format = DRM_FORMAT_YVU420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2 },
  147. { .format = DRM_FORMAT_YUV422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1 },
  148. { .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1 },
  149. { .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1 },
  150. { .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1 },
  151. { .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2 },
  152. { .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2 },
  153. { .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1 },
  154. { .format = DRM_FORMAT_NV61, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1 },
  155. { .format = DRM_FORMAT_NV24, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1 },
  156. { .format = DRM_FORMAT_NV42, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1 },
  157. { .format = DRM_FORMAT_YUYV, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
  158. { .format = DRM_FORMAT_YVYU, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
  159. { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
  160. { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
  161. { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
  162. };
  163. unsigned int i;
  164. for (i = 0; i < ARRAY_SIZE(formats); ++i) {
  165. if (formats[i].format == format)
  166. return &formats[i];
  167. }
  168. return NULL;
  169. }
  170. /**
  171. * drm_format_info - query information for a given format
  172. * @format: pixel format (DRM_FORMAT_*)
  173. *
  174. * The caller should only pass a supported pixel format to this function.
  175. * Unsupported pixel formats will generate a warning in the kernel log.
  176. *
  177. * Returns:
  178. * The instance of struct drm_format_info that describes the pixel format, or
  179. * NULL if the format is unsupported.
  180. */
  181. const struct drm_format_info *drm_format_info(u32 format)
  182. {
  183. const struct drm_format_info *info;
  184. info = __drm_format_info(format);
  185. WARN_ON(!info);
  186. return info;
  187. }
  188. EXPORT_SYMBOL(drm_format_info);
  189. /**
  190. * drm_fb_get_bpp_depth - get the bpp/depth values for format
  191. * @format: pixel format (DRM_FORMAT_*)
  192. * @depth: storage for the depth value
  193. * @bpp: storage for the bpp value
  194. *
  195. * This only supports RGB formats here for compat with code that doesn't use
  196. * pixel formats directly yet.
  197. */
  198. void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
  199. int *bpp)
  200. {
  201. const struct drm_format_info *info;
  202. info = drm_format_info(format);
  203. if (!info || !info->depth) {
  204. char *format_name = drm_get_format_name(format);
  205. DRM_DEBUG_KMS("unsupported pixel format %s\n", format_name);
  206. kfree(format_name);
  207. *depth = 0;
  208. *bpp = 0;
  209. return;
  210. }
  211. *depth = info->depth;
  212. *bpp = info->cpp[0] * 8;
  213. }
  214. EXPORT_SYMBOL(drm_fb_get_bpp_depth);
  215. /**
  216. * drm_format_num_planes - get the number of planes for format
  217. * @format: pixel format (DRM_FORMAT_*)
  218. *
  219. * Returns:
  220. * The number of planes used by the specified pixel format.
  221. */
  222. int drm_format_num_planes(uint32_t format)
  223. {
  224. const struct drm_format_info *info;
  225. info = drm_format_info(format);
  226. return info ? info->num_planes : 1;
  227. }
  228. EXPORT_SYMBOL(drm_format_num_planes);
  229. /**
  230. * drm_format_plane_cpp - determine the bytes per pixel value
  231. * @format: pixel format (DRM_FORMAT_*)
  232. * @plane: plane index
  233. *
  234. * Returns:
  235. * The bytes per pixel value for the specified plane.
  236. */
  237. int drm_format_plane_cpp(uint32_t format, int plane)
  238. {
  239. const struct drm_format_info *info;
  240. info = drm_format_info(format);
  241. if (!info || plane >= info->num_planes)
  242. return 0;
  243. return info->cpp[plane];
  244. }
  245. EXPORT_SYMBOL(drm_format_plane_cpp);
  246. /**
  247. * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
  248. * @format: pixel format (DRM_FORMAT_*)
  249. *
  250. * Returns:
  251. * The horizontal chroma subsampling factor for the
  252. * specified pixel format.
  253. */
  254. int drm_format_horz_chroma_subsampling(uint32_t format)
  255. {
  256. const struct drm_format_info *info;
  257. info = drm_format_info(format);
  258. return info ? info->hsub : 1;
  259. }
  260. EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
  261. /**
  262. * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
  263. * @format: pixel format (DRM_FORMAT_*)
  264. *
  265. * Returns:
  266. * The vertical chroma subsampling factor for the
  267. * specified pixel format.
  268. */
  269. int drm_format_vert_chroma_subsampling(uint32_t format)
  270. {
  271. const struct drm_format_info *info;
  272. info = drm_format_info(format);
  273. return info ? info->vsub : 1;
  274. }
  275. EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
  276. /**
  277. * drm_format_plane_width - width of the plane given the first plane
  278. * @width: width of the first plane
  279. * @format: pixel format
  280. * @plane: plane index
  281. *
  282. * Returns:
  283. * The width of @plane, given that the width of the first plane is @width.
  284. */
  285. int drm_format_plane_width(int width, uint32_t format, int plane)
  286. {
  287. const struct drm_format_info *info;
  288. info = drm_format_info(format);
  289. if (!info || plane >= info->num_planes)
  290. return 0;
  291. if (plane == 0)
  292. return width;
  293. return width / info->hsub;
  294. }
  295. EXPORT_SYMBOL(drm_format_plane_width);
  296. /**
  297. * drm_format_plane_height - height of the plane given the first plane
  298. * @height: height of the first plane
  299. * @format: pixel format
  300. * @plane: plane index
  301. *
  302. * Returns:
  303. * The height of @plane, given that the height of the first plane is @height.
  304. */
  305. int drm_format_plane_height(int height, uint32_t format, int plane)
  306. {
  307. const struct drm_format_info *info;
  308. info = drm_format_info(format);
  309. if (!info || plane >= info->num_planes)
  310. return 0;
  311. if (plane == 0)
  312. return height;
  313. return height / info->vsub;
  314. }
  315. EXPORT_SYMBOL(drm_format_plane_height);