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