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/drm_device.h>
31 #include <drm/drm_fourcc.h>
32
printable_char(int c)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 */
drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)46 uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
47 {
48 uint32_t fmt = DRM_FORMAT_INVALID;
49
50 switch (bpp) {
51 case 0x8:
52 if (depth == 0x8) {
53 fmt = DRM_FORMAT_C8;
54 }
55 break;
56
57 case 0x10:
58 switch (depth) {
59 case 0xf:
60 fmt = DRM_FORMAT_XRGB1555;
61 break;
62 case 0x10:
63 fmt = DRM_FORMAT_RGB565;
64 break;
65 default:
66 break;
67 }
68 break;
69
70 case 0x18:
71 if (depth == 0x18) {
72 fmt = DRM_FORMAT_RGB888;
73 }
74 break;
75
76 case 0x20:
77 switch (depth) {
78 case 0x18:
79 fmt = DRM_FORMAT_XRGB8888;
80 break;
81 case 0x1e:
82 fmt = DRM_FORMAT_XRGB2101010;
83 break;
84 case 0x20:
85 fmt = DRM_FORMAT_ARGB8888;
86 break;
87 default:
88 break;
89 }
90 break;
91
92 default:
93 break;
94 }
95
96 return fmt;
97 }
98 EXPORT_SYMBOL(drm_mode_legacy_fb_format);
99
100 /**
101 * drm_driver_legacy_fb_format - compute drm fourcc code from legacy description
102 * @dev: DRM device
103 * @bpp: bits per pixels
104 * @depth: bit depth per pixel
105 *
106 * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
107 * Unlike drm_mode_legacy_fb_format() this looks at the drivers mode_config,
108 * and depending on the &drm_mode_config.quirk_addfb_prefer_host_byte_order flag
109 * it returns little endian byte order or host byte order framebuffer formats.
110 */
drm_driver_legacy_fb_format(struct drm_device *dev, uint32_t bpp, uint32_t depth)111 uint32_t drm_driver_legacy_fb_format(struct drm_device *dev, uint32_t bpp, uint32_t depth)
112 {
113 uint32_t fmt = drm_mode_legacy_fb_format(bpp, depth);
114
115 if (dev->mode_config.quirk_addfb_prefer_host_byte_order) {
116 if (fmt == DRM_FORMAT_XRGB8888) {
117 fmt = DRM_FORMAT_HOST_XRGB8888;
118 }
119 if (fmt == DRM_FORMAT_ARGB8888) {
120 fmt = DRM_FORMAT_HOST_ARGB8888;
121 }
122 if (fmt == DRM_FORMAT_RGB565) {
123 fmt = DRM_FORMAT_HOST_RGB565;
124 }
125 if (fmt == DRM_FORMAT_XRGB1555) {
126 fmt = DRM_FORMAT_HOST_XRGB1555;
127 }
128 }
129
130 if (dev->mode_config.quirk_addfb_prefer_xbgr_30bpp && fmt == DRM_FORMAT_XRGB2101010) {
131 fmt = DRM_FORMAT_XBGR2101010;
132 }
133
134 return fmt;
135 }
136 EXPORT_SYMBOL(drm_driver_legacy_fb_format);
137
138 /**
139 * drm_get_format_name - fill a string with a drm fourcc format's name
140 * @format: format to compute name of
141 * @buf: caller-supplied buffer
142 */
drm_get_format_name(uint32_t format, struct drm_format_name_buf *buf)143 const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf *buf)
144 {
145 int ret = 0;
146 ret = snprintf(buf->str, sizeof(buf->str), "%c%c%c%c %s-endian (0x%08x)", printable_char(format & 0xff),
147 printable_char((format >> 0x8) & 0xff), printable_char((format >> 0x10) & 0xff),
148 printable_char((format >> 0x18) & 0x7f), format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", format);
149
150 return buf->str;
151 }
152 EXPORT_SYMBOL(drm_get_format_name);
153
154 /*
155 * Internal function to query information for a given format. See
156 * drm_format_info() for the public API.
157 */
__drm_format_info(u32 format)158 const struct drm_format_info *__drm_format_info(u32 format)
159 {
160 static const struct drm_format_info formats[] = {
161 {.format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = {1, 0, 0}, .hsub = 1, .vsub = 1},
162 {.format = DRM_FORMAT_RGB332, .depth = 8, .num_planes = 1, .cpp = {1, 0, 0}, .hsub = 1, .vsub = 1},
163 {.format = DRM_FORMAT_BGR233, .depth = 8, .num_planes = 1, .cpp = {1, 0, 0}, .hsub = 1, .vsub = 1},
164 {.format = DRM_FORMAT_XRGB4444, .depth = 0, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
165 {.format = DRM_FORMAT_XBGR4444, .depth = 0, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
166 {.format = DRM_FORMAT_RGBX4444, .depth = 0, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
167 {.format = DRM_FORMAT_BGRX4444, .depth = 0, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
168 {.format = DRM_FORMAT_ARGB4444,
169 .depth = 0,
170 .num_planes = 1,
171 .cpp = {2, 0, 0},
172 .hsub = 1,
173 .vsub = 1,
174 .has_alpha = true},
175 {.format = DRM_FORMAT_ABGR4444,
176 .depth = 0,
177 .num_planes = 1,
178 .cpp = {2, 0, 0},
179 .hsub = 1,
180 .vsub = 1,
181 .has_alpha = true},
182 {.format = DRM_FORMAT_RGBA4444,
183 .depth = 0,
184 .num_planes = 1,
185 .cpp = {2, 0, 0},
186 .hsub = 1,
187 .vsub = 1,
188 .has_alpha = true},
189 {.format = DRM_FORMAT_BGRA4444,
190 .depth = 0,
191 .num_planes = 1,
192 .cpp = {2, 0, 0},
193 .hsub = 1,
194 .vsub = 1,
195 .has_alpha = true},
196 {.format = DRM_FORMAT_XRGB1555, .depth = 15, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
197 {.format = DRM_FORMAT_XBGR1555, .depth = 15, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
198 {.format = DRM_FORMAT_RGBX5551, .depth = 15, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
199 {.format = DRM_FORMAT_BGRX5551, .depth = 15, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
200 {.format = DRM_FORMAT_ARGB1555,
201 .depth = 15,
202 .num_planes = 1,
203 .cpp = {2, 0, 0},
204 .hsub = 1,
205 .vsub = 1,
206 .has_alpha = true},
207 {.format = DRM_FORMAT_ABGR1555,
208 .depth = 15,
209 .num_planes = 1,
210 .cpp = {2, 0, 0},
211 .hsub = 1,
212 .vsub = 1,
213 .has_alpha = true},
214 {.format = DRM_FORMAT_RGBA5551,
215 .depth = 15,
216 .num_planes = 1,
217 .cpp = {2, 0, 0},
218 .hsub = 1,
219 .vsub = 1,
220 .has_alpha = true},
221 {.format = DRM_FORMAT_BGRA5551,
222 .depth = 15,
223 .num_planes = 1,
224 .cpp = {2, 0, 0},
225 .hsub = 1,
226 .vsub = 1,
227 .has_alpha = true},
228 {.format = DRM_FORMAT_RGB565, .depth = 16, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
229 {.format = DRM_FORMAT_BGR565, .depth = 16, .num_planes = 1, .cpp = {2, 0, 0}, .hsub = 1, .vsub = 1},
230 {.format = DRM_FORMAT_RGB888, .depth = 24, .num_planes = 1, .cpp = {3, 0, 0}, .hsub = 1, .vsub = 1},
231 {.format = DRM_FORMAT_BGR888, .depth = 24, .num_planes = 1, .cpp = {3, 0, 0}, .hsub = 1, .vsub = 1},
232 {.format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 1, .cpp = {4, 0, 0}, .hsub = 1, .vsub = 1},
233 {.format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 1, .cpp = {4, 0, 0}, .hsub = 1, .vsub = 1},
234 {.format = DRM_FORMAT_RGBX8888, .depth = 24, .num_planes = 1, .cpp = {4, 0, 0}, .hsub = 1, .vsub = 1},
235 {.format = DRM_FORMAT_BGRX8888, .depth = 24, .num_planes = 1, .cpp = {4, 0, 0}, .hsub = 1, .vsub = 1},
236 {.format = DRM_FORMAT_RGB565_A8,
237 .depth = 24,
238 .num_planes = 2,
239 .cpp = {2, 1, 0},
240 .hsub = 1,
241 .vsub = 1,
242 .has_alpha = true},
243 {.format = DRM_FORMAT_BGR565_A8,
244 .depth = 24,
245 .num_planes = 2,
246 .cpp = {2, 1, 0},
247 .hsub = 1,
248 .vsub = 1,
249 .has_alpha = true},
250 {.format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 1, .cpp = {4, 0, 0}, .hsub = 1, .vsub = 1},
251 {.format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 1, .cpp = {4, 0, 0}, .hsub = 1, .vsub = 1},
252 {.format = DRM_FORMAT_RGBX1010102, .depth = 30, .num_planes = 1, .cpp = {4, 0, 0}, .hsub = 1, .vsub = 1},
253 {.format = DRM_FORMAT_BGRX1010102, .depth = 30, .num_planes = 1, .cpp = {4, 0, 0}, .hsub = 1, .vsub = 1},
254 {.format = DRM_FORMAT_ARGB2101010,
255 .depth = 30,
256 .num_planes = 1,
257 .cpp = {4, 0, 0},
258 .hsub = 1,
259 .vsub = 1,
260 .has_alpha = true},
261 {.format = DRM_FORMAT_ABGR2101010,
262 .depth = 30,
263 .num_planes = 1,
264 .cpp = {4, 0, 0},
265 .hsub = 1,
266 .vsub = 1,
267 .has_alpha = true},
268 {.format = DRM_FORMAT_RGBA1010102,
269 .depth = 30,
270 .num_planes = 1,
271 .cpp = {4, 0, 0},
272 .hsub = 1,
273 .vsub = 1,
274 .has_alpha = true},
275 {.format = DRM_FORMAT_BGRA1010102,
276 .depth = 30,
277 .num_planes = 1,
278 .cpp = {4, 0, 0},
279 .hsub = 1,
280 .vsub = 1,
281 .has_alpha = true},
282 {.format = DRM_FORMAT_ARGB8888,
283 .depth = 32,
284 .num_planes = 1,
285 .cpp = {4, 0, 0},
286 .hsub = 1,
287 .vsub = 1,
288 .has_alpha = true},
289 {.format = DRM_FORMAT_ABGR8888,
290 .depth = 32,
291 .num_planes = 1,
292 .cpp = {4, 0, 0},
293 .hsub = 1,
294 .vsub = 1,
295 .has_alpha = true},
296 {.format = DRM_FORMAT_RGBA8888,
297 .depth = 32,
298 .num_planes = 1,
299 .cpp = {4, 0, 0},
300 .hsub = 1,
301 .vsub = 1,
302 .has_alpha = true},
303 {.format = DRM_FORMAT_BGRA8888,
304 .depth = 32,
305 .num_planes = 1,
306 .cpp = {4, 0, 0},
307 .hsub = 1,
308 .vsub = 1,
309 .has_alpha = true},
310 {.format = DRM_FORMAT_XRGB16161616F, .depth = 0, .num_planes = 1, .cpp = {8, 0, 0}, .hsub = 1, .vsub = 1},
311 {.format = DRM_FORMAT_XBGR16161616F, .depth = 0, .num_planes = 1, .cpp = {8, 0, 0}, .hsub = 1, .vsub = 1},
312 {.format = DRM_FORMAT_ARGB16161616F,
313 .depth = 0,
314 .num_planes = 1,
315 .cpp = {8, 0, 0},
316 .hsub = 1,
317 .vsub = 1,
318 .has_alpha = true},
319 {.format = DRM_FORMAT_ABGR16161616F,
320 .depth = 0,
321 .num_planes = 1,
322 .cpp = {8, 0, 0},
323 .hsub = 1,
324 .vsub = 1,
325 .has_alpha = true},
326 {.format = DRM_FORMAT_RGB888_A8,
327 .depth = 32,
328 .num_planes = 2,
329 .cpp = {3, 1, 0},
330 .hsub = 1,
331 .vsub = 1,
332 .has_alpha = true},
333 {.format = DRM_FORMAT_BGR888_A8,
334 .depth = 32,
335 .num_planes = 2,
336 .cpp = {3, 1, 0},
337 .hsub = 1,
338 .vsub = 1,
339 .has_alpha = true},
340 {.format = DRM_FORMAT_XRGB8888_A8,
341 .depth = 32,
342 .num_planes = 2,
343 .cpp = {4, 1, 0},
344 .hsub = 1,
345 .vsub = 1,
346 .has_alpha = true},
347 {.format = DRM_FORMAT_XBGR8888_A8,
348 .depth = 32,
349 .num_planes = 2,
350 .cpp = {4, 1, 0},
351 .hsub = 1,
352 .vsub = 1,
353 .has_alpha = true},
354 {.format = DRM_FORMAT_RGBX8888_A8,
355 .depth = 32,
356 .num_planes = 2,
357 .cpp = {4, 1, 0},
358 .hsub = 1,
359 .vsub = 1,
360 .has_alpha = true},
361 {.format = DRM_FORMAT_BGRX8888_A8,
362 .depth = 32,
363 .num_planes = 2,
364 .cpp = {4, 1, 0},
365 .hsub = 1,
366 .vsub = 1,
367 .has_alpha = true},
368 {.format = DRM_FORMAT_YUV410,
369 .depth = 0,
370 .num_planes = 3,
371 .cpp = {1, 1, 1},
372 .hsub = 4,
373 .vsub = 4,
374 .is_yuv = true},
375 {.format = DRM_FORMAT_YVU410,
376 .depth = 0,
377 .num_planes = 3,
378 .cpp = {1, 1, 1},
379 .hsub = 4,
380 .vsub = 4,
381 .is_yuv = true},
382 {.format = DRM_FORMAT_YUV411,
383 .depth = 0,
384 .num_planes = 3,
385 .cpp = {1, 1, 1},
386 .hsub = 4,
387 .vsub = 1,
388 .is_yuv = true},
389 {.format = DRM_FORMAT_YVU411,
390 .depth = 0,
391 .num_planes = 3,
392 .cpp = {1, 1, 1},
393 .hsub = 4,
394 .vsub = 1,
395 .is_yuv = true},
396 {.format = DRM_FORMAT_YUV420,
397 .depth = 0,
398 .num_planes = 3,
399 .cpp = {1, 1, 1},
400 .hsub = 2,
401 .vsub = 2,
402 .is_yuv = true},
403 {.format = DRM_FORMAT_YVU420,
404 .depth = 0,
405 .num_planes = 3,
406 .cpp = {1, 1, 1},
407 .hsub = 2,
408 .vsub = 2,
409 .is_yuv = true},
410 {.format = DRM_FORMAT_YUV422,
411 .depth = 0,
412 .num_planes = 3,
413 .cpp = {1, 1, 1},
414 .hsub = 2,
415 .vsub = 1,
416 .is_yuv = true},
417 {.format = DRM_FORMAT_YVU422,
418 .depth = 0,
419 .num_planes = 3,
420 .cpp = {1, 1, 1},
421 .hsub = 2,
422 .vsub = 1,
423 .is_yuv = true},
424 {.format = DRM_FORMAT_YUV444,
425 .depth = 0,
426 .num_planes = 3,
427 .cpp = {1, 1, 1},
428 .hsub = 1,
429 .vsub = 1,
430 .is_yuv = true},
431 {.format = DRM_FORMAT_YVU444,
432 .depth = 0,
433 .num_planes = 3,
434 .cpp = {1, 1, 1},
435 .hsub = 1,
436 .vsub = 1,
437 .is_yuv = true},
438 {.format = DRM_FORMAT_NV12,
439 .depth = 0,
440 .num_planes = 2,
441 .cpp = {1, 2, 0},
442 .hsub = 2,
443 .vsub = 2,
444 .is_yuv = true},
445 {.format = DRM_FORMAT_NV21,
446 .depth = 0,
447 .num_planes = 2,
448 .cpp = {1, 2, 0},
449 .hsub = 2,
450 .vsub = 2,
451 .is_yuv = true},
452 {.format = DRM_FORMAT_NV16,
453 .depth = 0,
454 .num_planes = 2,
455 .cpp = {1, 2, 0},
456 .hsub = 2,
457 .vsub = 1,
458 .is_yuv = true},
459 {.format = DRM_FORMAT_NV61,
460 .depth = 0,
461 .num_planes = 2,
462 .cpp = {1, 2, 0},
463 .hsub = 2,
464 .vsub = 1,
465 .is_yuv = true},
466 {.format = DRM_FORMAT_NV24,
467 .depth = 0,
468 .num_planes = 2,
469 .cpp = {1, 2, 0},
470 .hsub = 1,
471 .vsub = 1,
472 .is_yuv = true},
473 {.format = DRM_FORMAT_NV42,
474 .depth = 0,
475 .num_planes = 2,
476 .cpp = {1, 2, 0},
477 .hsub = 1,
478 .vsub = 1,
479 .is_yuv = true},
480 {.format = DRM_FORMAT_YUYV,
481 .depth = 0,
482 .num_planes = 1,
483 .cpp = {2, 0, 0},
484 .hsub = 2,
485 .vsub = 1,
486 .is_yuv = true},
487 {.format = DRM_FORMAT_YVYU,
488 .depth = 0,
489 .num_planes = 1,
490 .cpp = {2, 0, 0},
491 .hsub = 2,
492 .vsub = 1,
493 .is_yuv = true},
494 {.format = DRM_FORMAT_UYVY,
495 .depth = 0,
496 .num_planes = 1,
497 .cpp = {2, 0, 0},
498 .hsub = 2,
499 .vsub = 1,
500 .is_yuv = true},
501 {.format = DRM_FORMAT_VYUY,
502 .depth = 0,
503 .num_planes = 1,
504 .cpp = {2, 0, 0},
505 .hsub = 2,
506 .vsub = 1,
507 .is_yuv = true},
508 {.format = DRM_FORMAT_XYUV8888,
509 .depth = 0,
510 .num_planes = 1,
511 .cpp = {4, 0, 0},
512 .hsub = 1,
513 .vsub = 1,
514 .is_yuv = true},
515 {.format = DRM_FORMAT_VUY888,
516 .depth = 0,
517 .num_planes = 1,
518 .cpp = {3, 0, 0},
519 .hsub = 1,
520 .vsub = 1,
521 .is_yuv = true},
522 {.format = DRM_FORMAT_AYUV,
523 .depth = 0,
524 .num_planes = 1,
525 .cpp = {4, 0, 0},
526 .hsub = 1,
527 .vsub = 1,
528 .has_alpha = true,
529 .is_yuv = true},
530 {.format = DRM_FORMAT_Y210,
531 .depth = 0,
532 .num_planes = 1,
533 .cpp = {4, 0, 0},
534 .hsub = 2,
535 .vsub = 1,
536 .is_yuv = true},
537 {.format = DRM_FORMAT_Y212,
538 .depth = 0,
539 .num_planes = 1,
540 .cpp = {4, 0, 0},
541 .hsub = 2,
542 .vsub = 1,
543 .is_yuv = true},
544 {.format = DRM_FORMAT_Y216,
545 .depth = 0,
546 .num_planes = 1,
547 .cpp = {4, 0, 0},
548 .hsub = 2,
549 .vsub = 1,
550 .is_yuv = true},
551 {.format = DRM_FORMAT_Y410,
552 .depth = 0,
553 .num_planes = 1,
554 .cpp = {4, 0, 0},
555 .hsub = 1,
556 .vsub = 1,
557 .has_alpha = true,
558 .is_yuv = true},
559 {.format = DRM_FORMAT_Y412,
560 .depth = 0,
561 .num_planes = 1,
562 .cpp = {8, 0, 0},
563 .hsub = 1,
564 .vsub = 1,
565 .has_alpha = true,
566 .is_yuv = true},
567 {.format = DRM_FORMAT_Y416,
568 .depth = 0,
569 .num_planes = 1,
570 .cpp = {8, 0, 0},
571 .hsub = 1,
572 .vsub = 1,
573 .has_alpha = true,
574 .is_yuv = true},
575 {.format = DRM_FORMAT_XVYU2101010,
576 .depth = 0,
577 .num_planes = 1,
578 .cpp = {4, 0, 0},
579 .hsub = 1,
580 .vsub = 1,
581 .is_yuv = true},
582 {.format = DRM_FORMAT_XVYU12_16161616,
583 .depth = 0,
584 .num_planes = 1,
585 .cpp = {8, 0, 0},
586 .hsub = 1,
587 .vsub = 1,
588 .is_yuv = true},
589 {.format = DRM_FORMAT_XVYU16161616,
590 .depth = 0,
591 .num_planes = 1,
592 .cpp = {8, 0, 0},
593 .hsub = 1,
594 .vsub = 1,
595 .is_yuv = true},
596 {.format = DRM_FORMAT_Y0L0,
597 .depth = 0,
598 .num_planes = 1,
599 .char_per_block = {8, 0, 0},
600 .block_w = {2, 0, 0},
601 .block_h = {2, 0, 0},
602 .hsub = 2,
603 .vsub = 2,
604 .has_alpha = true,
605 .is_yuv = true},
606 {.format = DRM_FORMAT_X0L0,
607 .depth = 0,
608 .num_planes = 1,
609 .char_per_block = {8, 0, 0},
610 .block_w = {2, 0, 0},
611 .block_h = {2, 0, 0},
612 .hsub = 2,
613 .vsub = 2,
614 .is_yuv = true},
615 {.format = DRM_FORMAT_Y0L2,
616 .depth = 0,
617 .num_planes = 1,
618 .char_per_block = {8, 0, 0},
619 .block_w = {2, 0, 0},
620 .block_h = {2, 0, 0},
621 .hsub = 2,
622 .vsub = 2,
623 .has_alpha = true,
624 .is_yuv = true},
625 {.format = DRM_FORMAT_X0L2,
626 .depth = 0,
627 .num_planes = 1,
628 .char_per_block = {8, 0, 0},
629 .block_w = {2, 0, 0},
630 .block_h = {2, 0, 0},
631 .hsub = 2,
632 .vsub = 2,
633 .is_yuv = true},
634 {.format = DRM_FORMAT_P010,
635 .depth = 0,
636 .num_planes = 2,
637 .char_per_block = {2, 4, 0},
638 .block_w = {1, 1, 0},
639 .block_h = {1, 1, 0},
640 .hsub = 2,
641 .vsub = 2,
642 .is_yuv = true},
643 {.format = DRM_FORMAT_P012,
644 .depth = 0,
645 .num_planes = 2,
646 .char_per_block = {2, 4, 0},
647 .block_w = {1, 1, 0},
648 .block_h = {1, 1, 0},
649 .hsub = 2,
650 .vsub = 2,
651 .is_yuv = true},
652 {.format = DRM_FORMAT_P016,
653 .depth = 0,
654 .num_planes = 2,
655 .char_per_block = {2, 4, 0},
656 .block_w = {1, 1, 0},
657 .block_h = {1, 1, 0},
658 .hsub = 2,
659 .vsub = 2,
660 .is_yuv = true},
661 {.format = DRM_FORMAT_P210,
662 .depth = 0,
663 .num_planes = 2,
664 .char_per_block = {2, 4, 0},
665 .block_w = {1, 1, 0},
666 .block_h = {1, 1, 0},
667 .hsub = 2,
668 .vsub = 1,
669 .is_yuv = true},
670 {.format = DRM_FORMAT_VUY101010,
671 .depth = 0,
672 .num_planes = 1,
673 .cpp = {0, 0, 0},
674 .hsub = 1,
675 .vsub = 1,
676 .is_yuv = true},
677 {.format = DRM_FORMAT_YUV420_8BIT,
678 .depth = 0,
679 .num_planes = 1,
680 .cpp = {0, 0, 0},
681 .hsub = 2,
682 .vsub = 2,
683 .is_yuv = true},
684 {.format = DRM_FORMAT_YUV420_10BIT,
685 .depth = 0,
686 .num_planes = 1,
687 .cpp = {0, 0, 0},
688 .hsub = 2,
689 .vsub = 2,
690 .is_yuv = true},
691 {.format = DRM_FORMAT_NV15,
692 .depth = 0,
693 .num_planes = 2,
694 .char_per_block = {5, 5, 0},
695 .block_w = {4, 2, 0},
696 .block_h = {1, 1, 0},
697 .hsub = 2,
698 .vsub = 2,
699 .is_yuv = true},
700 #ifdef CONFIG_NO_GKI
701 {.format = DRM_FORMAT_NV20,
702 .depth = 0,
703 .num_planes = 2,
704 .char_per_block = {5, 5, 0},
705 .block_w = {4, 2, 0},
706 .block_h = {1, 1, 0},
707 .hsub = 2,
708 .vsub = 1,
709 .is_yuv = true},
710 {.format = DRM_FORMAT_NV30,
711 .depth = 0,
712 .num_planes = 2,
713 .char_per_block = {5, 5, 0},
714 .block_w = {4, 2, 0},
715 .block_h = {1, 1, 0},
716 .hsub = 1,
717 .vsub = 1,
718 .is_yuv = true},
719 #endif
720 {.format = DRM_FORMAT_Q410,
721 .depth = 0,
722 .num_planes = 3,
723 .char_per_block = {2, 2, 2},
724 .block_w = {1, 1, 1},
725 .block_h = {1, 1, 1},
726 .hsub = 0,
727 .vsub = 0,
728 .is_yuv = true},
729 {.format = DRM_FORMAT_Q401,
730 .depth = 0,
731 .num_planes = 3,
732 .char_per_block = {2, 2, 2},
733 .block_w = {1, 1, 1},
734 .block_h = {1, 1, 1},
735 .hsub = 0,
736 .vsub = 0,
737 .is_yuv = true},
738 };
739
740 unsigned int i;
741
742 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
743 if (formats[i].format == format) {
744 return &formats[i];
745 }
746 }
747
748 return NULL;
749 }
750
751 /**
752 * drm_format_info - query information for a given format
753 * @format: pixel format (DRM_FORMAT_*)
754 *
755 * The caller should only pass a supported pixel format to this function.
756 * Unsupported pixel formats will generate a warning in the kernel log.
757 *
758 * Returns:
759 * The instance of struct drm_format_info that describes the pixel format, or
760 * NULL if the format is unsupported.
761 */
drm_format_info(u32 format)762 const struct drm_format_info *drm_format_info(u32 format)
763 {
764 const struct drm_format_info *info;
765
766 info = __drm_format_info(format);
767 WARN_ON(!info);
768 return info;
769 }
770 EXPORT_SYMBOL(drm_format_info);
771
772 /**
773 * drm_get_format_info - query information for a given framebuffer configuration
774 * @dev: DRM device
775 * @mode_cmd: metadata from the userspace fb creation request
776 *
777 * Returns:
778 * The instance of struct drm_format_info that describes the pixel format, or
779 * NULL if the format is unsupported.
780 */
drm_get_format_info(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd)781 const struct drm_format_info *drm_get_format_info(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd)
782 {
783 const struct drm_format_info *info = NULL;
784
785 if (dev->mode_config.funcs->get_format_info) {
786 info = dev->mode_config.funcs->get_format_info(mode_cmd);
787 }
788
789 if (!info) {
790 info = drm_format_info(mode_cmd->pixel_format);
791 }
792
793 return info;
794 }
795 EXPORT_SYMBOL(drm_get_format_info);
796
797 /**
798 * drm_format_info_block_width - width in pixels of block.
799 * @info: pixel format info
800 * @plane: plane index
801 *
802 * Returns:
803 * The width in pixels of a block, depending on the plane index.
804 */
drm_format_info_block_width(const struct drm_format_info *info, int plane)805 unsigned int drm_format_info_block_width(const struct drm_format_info *info, int plane)
806 {
807 if (!info || plane < 0 || plane >= info->num_planes) {
808 return 0;
809 }
810
811 if (!info->block_w[plane]) {
812 return 1;
813 }
814 return info->block_w[plane];
815 }
816 EXPORT_SYMBOL(drm_format_info_block_width);
817
818 /**
819 * drm_format_info_block_height - height in pixels of a block
820 * @info: pixel format info
821 * @plane: plane index
822 *
823 * Returns:
824 * The height in pixels of a block, depending on the plane index.
825 */
drm_format_info_block_height(const struct drm_format_info *info, int plane)826 unsigned int drm_format_info_block_height(const struct drm_format_info *info, int plane)
827 {
828 if (!info || plane < 0 || plane >= info->num_planes) {
829 return 0;
830 }
831
832 if (!info->block_h[plane]) {
833 return 1;
834 }
835 return info->block_h[plane];
836 }
837 EXPORT_SYMBOL(drm_format_info_block_height);
838
839 /**
840 * drm_format_info_min_pitch - computes the minimum required pitch in bytes
841 * @info: pixel format info
842 * @plane: plane index
843 * @buffer_width: buffer width in pixels
844 *
845 * Returns:
846 * The minimum required pitch in bytes for a buffer by taking into consideration
847 * the pixel format information and the buffer width.
848 */
drm_format_info_min_pitch(const struct drm_format_info *info, int plane, unsigned int buffer_width)849 uint64_t drm_format_info_min_pitch(const struct drm_format_info *info, int plane, unsigned int buffer_width)
850 {
851 if (!info || plane < 0 || plane >= info->num_planes) {
852 return 0;
853 }
854
855 return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
856 drm_format_info_block_width(info, plane) * drm_format_info_block_height(info, plane));
857 }
858 EXPORT_SYMBOL(drm_format_info_min_pitch);
859