Merge tag 'mm-hotfixes-stable-2025-07-11-16-16' of git://git.kernel.org/pub/scm/linux...
[linux-block.git] / drivers / gpu / drm / drm_format_helper.c
... / ...
CommitLineData
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
11#include <linux/io.h>
12#include <linux/iosys-map.h>
13#include <linux/module.h>
14#include <linux/slab.h>
15
16#include <drm/drm_device.h>
17#include <drm/drm_format_helper.h>
18#include <drm/drm_framebuffer.h>
19#include <drm/drm_fourcc.h>
20#include <drm/drm_print.h>
21#include <drm/drm_rect.h>
22
23#include "drm_format_internal.h"
24
25/**
26 * drm_format_conv_state_init - Initialize format-conversion state
27 * @state: The state to initialize
28 *
29 * Clears all fields in struct drm_format_conv_state. The state will
30 * be empty with no preallocated resources.
31 */
32void drm_format_conv_state_init(struct drm_format_conv_state *state)
33{
34 state->tmp.mem = NULL;
35 state->tmp.size = 0;
36 state->tmp.preallocated = false;
37}
38EXPORT_SYMBOL(drm_format_conv_state_init);
39
40/**
41 * drm_format_conv_state_copy - Copy format-conversion state
42 * @state: Destination state
43 * @old_state: Source state
44 *
45 * Copies format-conversion state from @old_state to @state; except for
46 * temporary storage.
47 */
48void drm_format_conv_state_copy(struct drm_format_conv_state *state,
49 const struct drm_format_conv_state *old_state)
50{
51 /*
52 * So far, there's only temporary storage here, which we don't
53 * duplicate. Just clear the fields.
54 */
55 state->tmp.mem = NULL;
56 state->tmp.size = 0;
57 state->tmp.preallocated = false;
58}
59EXPORT_SYMBOL(drm_format_conv_state_copy);
60
61/**
62 * drm_format_conv_state_reserve - Allocates storage for format conversion
63 * @state: The format-conversion state
64 * @new_size: The minimum allocation size
65 * @flags: Flags for kmalloc()
66 *
67 * Allocates at least @new_size bytes and returns a pointer to the memory
68 * range. After calling this function, previously returned memory blocks
69 * are invalid. It's best to collect all memory requirements of a format
70 * conversion and call this function once to allocate the range.
71 *
72 * Returns:
73 * A pointer to the allocated memory range, or NULL otherwise.
74 */
75void *drm_format_conv_state_reserve(struct drm_format_conv_state *state,
76 size_t new_size, gfp_t flags)
77{
78 void *mem;
79
80 if (new_size <= state->tmp.size)
81 goto out;
82 else if (state->tmp.preallocated)
83 return NULL;
84
85 mem = krealloc(state->tmp.mem, new_size, flags);
86 if (!mem)
87 return NULL;
88
89 state->tmp.mem = mem;
90 state->tmp.size = new_size;
91
92out:
93 return state->tmp.mem;
94}
95EXPORT_SYMBOL(drm_format_conv_state_reserve);
96
97/**
98 * drm_format_conv_state_release - Releases an format-conversion storage
99 * @state: The format-conversion state
100 *
101 * Releases the memory range references by the format-conversion state.
102 * After this call, all pointers to the memory are invalid. Prefer
103 * drm_format_conv_state_init() for cleaning up and unloading a driver.
104 */
105void drm_format_conv_state_release(struct drm_format_conv_state *state)
106{
107 if (state->tmp.preallocated)
108 return;
109
110 kfree(state->tmp.mem);
111 state->tmp.mem = NULL;
112 state->tmp.size = 0;
113}
114EXPORT_SYMBOL(drm_format_conv_state_release);
115
116static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
117{
118 return clip->y1 * pitch + clip->x1 * cpp;
119}
120
121/**
122 * drm_fb_clip_offset - Returns the clipping rectangles byte-offset in a framebuffer
123 * @pitch: Framebuffer line pitch in byte
124 * @format: Framebuffer format
125 * @clip: Clip rectangle
126 *
127 * Returns:
128 * The byte offset of the clip rectangle's top-left corner within the framebuffer.
129 */
130unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
131 const struct drm_rect *clip)
132{
133 return clip_offset(clip, pitch, format->cpp[0]);
134}
135EXPORT_SYMBOL(drm_fb_clip_offset);
136
137/* TODO: Make this function work with multi-plane formats. */
138static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
139 const void *vaddr, const struct drm_framebuffer *fb,
140 const struct drm_rect *clip, bool vaddr_cached_hint,
141 struct drm_format_conv_state *state,
142 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
143{
144 unsigned long linepixels = drm_rect_width(clip);
145 unsigned long lines = drm_rect_height(clip);
146 size_t sbuf_len = linepixels * fb->format->cpp[0];
147 void *stmp = NULL;
148 unsigned long i;
149 const void *sbuf;
150
151 /*
152 * Some source buffers, such as DMA memory, use write-combine
153 * caching, so reads are uncached. Speed up access by fetching
154 * one line at a time.
155 */
156 if (!vaddr_cached_hint) {
157 stmp = drm_format_conv_state_reserve(state, sbuf_len, GFP_KERNEL);
158 if (!stmp)
159 return -ENOMEM;
160 }
161
162 if (!dst_pitch)
163 dst_pitch = drm_rect_width(clip) * dst_pixsize;
164 vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
165
166 for (i = 0; i < lines; ++i) {
167 if (stmp)
168 sbuf = memcpy(stmp, vaddr, sbuf_len);
169 else
170 sbuf = vaddr;
171 xfrm_line(dst, sbuf, linepixels);
172 vaddr += fb->pitches[0];
173 dst += dst_pitch;
174 }
175
176 return 0;
177}
178
179/* TODO: Make this function work with multi-plane formats. */
180static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
181 const void *vaddr, const struct drm_framebuffer *fb,
182 const struct drm_rect *clip, bool vaddr_cached_hint,
183 struct drm_format_conv_state *state,
184 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
185{
186 unsigned long linepixels = drm_rect_width(clip);
187 unsigned long lines = drm_rect_height(clip);
188 size_t dbuf_len = linepixels * dst_pixsize;
189 size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */
190 size_t sbuf_len = linepixels * fb->format->cpp[0];
191 void *stmp = NULL;
192 unsigned long i;
193 const void *sbuf;
194 void *dbuf;
195
196 if (vaddr_cached_hint) {
197 dbuf = drm_format_conv_state_reserve(state, dbuf_len, GFP_KERNEL);
198 } else {
199 dbuf = drm_format_conv_state_reserve(state, stmp_off + sbuf_len, GFP_KERNEL);
200 stmp = dbuf + stmp_off;
201 }
202 if (!dbuf)
203 return -ENOMEM;
204
205 if (!dst_pitch)
206 dst_pitch = linepixels * dst_pixsize;
207 vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
208
209 for (i = 0; i < lines; ++i) {
210 if (stmp)
211 sbuf = memcpy(stmp, vaddr, sbuf_len);
212 else
213 sbuf = vaddr;
214 xfrm_line(dbuf, sbuf, linepixels);
215 memcpy_toio(dst, dbuf, dbuf_len);
216 vaddr += fb->pitches[0];
217 dst += dst_pitch;
218 }
219
220 return 0;
221}
222
223/* TODO: Make this function work with multi-plane formats. */
224static int drm_fb_xfrm(struct iosys_map *dst,
225 const unsigned int *dst_pitch, const u8 *dst_pixsize,
226 const struct iosys_map *src, const struct drm_framebuffer *fb,
227 const struct drm_rect *clip, bool vaddr_cached_hint,
228 struct drm_format_conv_state *state,
229 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
230{
231 static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
232 0, 0, 0, 0
233 };
234
235 if (!dst_pitch)
236 dst_pitch = default_dst_pitch;
237
238 /* TODO: handle src in I/O memory here */
239 if (dst[0].is_iomem)
240 return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0],
241 src[0].vaddr, fb, clip, vaddr_cached_hint, state,
242 xfrm_line);
243 else
244 return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0],
245 src[0].vaddr, fb, clip, vaddr_cached_hint, state,
246 xfrm_line);
247}
248
249#define ALIGN_DOWN_PIXELS(end, n, a) \
250 ((end) - ((n) & ((a) - 1)))
251
252static __always_inline void drm_fb_xfrm_line_32to8(void *dbuf, const void *sbuf,
253 unsigned int pixels,
254 u32 (*xfrm_pixel)(u32))
255{
256 __le32 *dbuf32 = dbuf;
257 u8 *dbuf8;
258 const __le32 *sbuf32 = sbuf;
259 const __le32 *send32 = sbuf32 + pixels;
260
261 /* write 4 pixels at once */
262 while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 4)) {
263 u32 pix[4] = {
264 le32_to_cpup(sbuf32),
265 le32_to_cpup(sbuf32 + 1),
266 le32_to_cpup(sbuf32 + 2),
267 le32_to_cpup(sbuf32 + 3),
268 };
269 /* write output bytes in reverse order for little endianness */
270 u32 val32 = xfrm_pixel(pix[0]) |
271 (xfrm_pixel(pix[1]) << 8) |
272 (xfrm_pixel(pix[2]) << 16) |
273 (xfrm_pixel(pix[3]) << 24);
274 *dbuf32++ = cpu_to_le32(val32);
275 sbuf32 += ARRAY_SIZE(pix);
276 }
277
278 /* write trailing pixels */
279 dbuf8 = (u8 __force *)dbuf32;
280 while (sbuf32 < send32)
281 *dbuf8++ = xfrm_pixel(le32_to_cpup(sbuf32++));
282}
283
284static __always_inline void drm_fb_xfrm_line_32to16(void *dbuf, const void *sbuf,
285 unsigned int pixels,
286 u32 (*xfrm_pixel)(u32))
287{
288 __le64 *dbuf64 = dbuf;
289 __le32 *dbuf32;
290 __le16 *dbuf16;
291 const __le32 *sbuf32 = sbuf;
292 const __le32 *send32 = sbuf32 + pixels;
293
294#if defined(CONFIG_64BIT)
295 /* write 4 pixels at once */
296 while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 4)) {
297 u32 pix[4] = {
298 le32_to_cpup(sbuf32),
299 le32_to_cpup(sbuf32 + 1),
300 le32_to_cpup(sbuf32 + 2),
301 le32_to_cpup(sbuf32 + 3),
302 };
303 /* write output bytes in reverse order for little endianness */
304 u64 val64 = ((u64)xfrm_pixel(pix[0])) |
305 ((u64)xfrm_pixel(pix[1]) << 16) |
306 ((u64)xfrm_pixel(pix[2]) << 32) |
307 ((u64)xfrm_pixel(pix[3]) << 48);
308 *dbuf64++ = cpu_to_le64(val64);
309 sbuf32 += ARRAY_SIZE(pix);
310 }
311#endif
312
313 /* write 2 pixels at once */
314 dbuf32 = (__le32 __force *)dbuf64;
315 while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 2)) {
316 u32 pix[2] = {
317 le32_to_cpup(sbuf32),
318 le32_to_cpup(sbuf32 + 1),
319 };
320 /* write output bytes in reverse order for little endianness */
321 u32 val32 = xfrm_pixel(pix[0]) |
322 (xfrm_pixel(pix[1]) << 16);
323 *dbuf32++ = cpu_to_le32(val32);
324 sbuf32 += ARRAY_SIZE(pix);
325 }
326
327 /* write trailing pixel */
328 dbuf16 = (__le16 __force *)dbuf32;
329 while (sbuf32 < send32)
330 *dbuf16++ = cpu_to_le16(xfrm_pixel(le32_to_cpup(sbuf32++)));
331}
332
333static __always_inline void drm_fb_xfrm_line_32to24(void *dbuf, const void *sbuf,
334 unsigned int pixels,
335 u32 (*xfrm_pixel)(u32))
336{
337 __le32 *dbuf32 = dbuf;
338 u8 *dbuf8;
339 const __le32 *sbuf32 = sbuf;
340 const __le32 *send32 = sbuf32 + pixels;
341
342 /* write pixels in chunks of 4 */
343 while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 4)) {
344 u32 val24[4] = {
345 xfrm_pixel(le32_to_cpup(sbuf32)),
346 xfrm_pixel(le32_to_cpup(sbuf32 + 1)),
347 xfrm_pixel(le32_to_cpup(sbuf32 + 2)),
348 xfrm_pixel(le32_to_cpup(sbuf32 + 3)),
349 };
350 u32 out32[3] = {
351 /* write output bytes in reverse order for little endianness */
352 ((val24[0] & 0x000000ff)) |
353 ((val24[0] & 0x0000ff00)) |
354 ((val24[0] & 0x00ff0000)) |
355 ((val24[1] & 0x000000ff) << 24),
356 ((val24[1] & 0x0000ff00) >> 8) |
357 ((val24[1] & 0x00ff0000) >> 8) |
358 ((val24[2] & 0x000000ff) << 16) |
359 ((val24[2] & 0x0000ff00) << 16),
360 ((val24[2] & 0x00ff0000) >> 16) |
361 ((val24[3] & 0x000000ff) << 8) |
362 ((val24[3] & 0x0000ff00) << 8) |
363 ((val24[3] & 0x00ff0000) << 8),
364 };
365
366 *dbuf32++ = cpu_to_le32(out32[0]);
367 *dbuf32++ = cpu_to_le32(out32[1]);
368 *dbuf32++ = cpu_to_le32(out32[2]);
369 sbuf32 += ARRAY_SIZE(val24);
370 }
371
372 /* write trailing pixel */
373 dbuf8 = (u8 __force *)dbuf32;
374 while (sbuf32 < send32) {
375 u32 val24 = xfrm_pixel(le32_to_cpup(sbuf32++));
376 /* write output in reverse order for little endianness */
377 *dbuf8++ = (val24 & 0x000000ff);
378 *dbuf8++ = (val24 & 0x0000ff00) >> 8;
379 *dbuf8++ = (val24 & 0x00ff0000) >> 16;
380 }
381}
382
383static __always_inline void drm_fb_xfrm_line_32to32(void *dbuf, const void *sbuf,
384 unsigned int pixels,
385 u32 (*xfrm_pixel)(u32))
386{
387 __le32 *dbuf32 = dbuf;
388 const __le32 *sbuf32 = sbuf;
389 const __le32 *send32 = sbuf32 + pixels;
390
391 while (sbuf32 < send32)
392 *dbuf32++ = cpu_to_le32(xfrm_pixel(le32_to_cpup(sbuf32++)));
393}
394
395/**
396 * drm_fb_memcpy - Copy clip buffer
397 * @dst: Array of destination buffers
398 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
399 * within @dst; can be NULL if scanlines are stored next to each other.
400 * @src: Array of source buffers
401 * @fb: DRM framebuffer
402 * @clip: Clip rectangle area to copy
403 *
404 * This function copies parts of a framebuffer to display memory. Destination and
405 * framebuffer formats must match. No conversion takes place. The parameters @dst,
406 * @dst_pitch and @src refer to arrays. Each array must have at least as many entries
407 * as there are planes in @fb's format. Each entry stores the value for the format's
408 * respective color plane at the same index.
409 *
410 * This function does not apply clipping on @dst (i.e. the destination is at the
411 * top-left corner).
412 */
413void drm_fb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch,
414 const struct iosys_map *src, const struct drm_framebuffer *fb,
415 const struct drm_rect *clip)
416{
417 static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
418 0, 0, 0, 0
419 };
420
421 const struct drm_format_info *format = fb->format;
422 unsigned int i, y, lines = drm_rect_height(clip);
423
424 if (!dst_pitch)
425 dst_pitch = default_dst_pitch;
426
427 for (i = 0; i < format->num_planes; ++i) {
428 unsigned int bpp_i = drm_format_info_bpp(format, i);
429 unsigned int cpp_i = DIV_ROUND_UP(bpp_i, 8);
430 size_t len_i = DIV_ROUND_UP(drm_rect_width(clip) * bpp_i, 8);
431 unsigned int dst_pitch_i = dst_pitch[i];
432 struct iosys_map dst_i = dst[i];
433 struct iosys_map src_i = src[i];
434
435 if (!dst_pitch_i)
436 dst_pitch_i = len_i;
437
438 iosys_map_incr(&src_i, clip_offset(clip, fb->pitches[i], cpp_i));
439 for (y = 0; y < lines; y++) {
440 /* TODO: handle src_i in I/O memory here */
441 iosys_map_memcpy_to(&dst_i, 0, src_i.vaddr, len_i);
442 iosys_map_incr(&src_i, fb->pitches[i]);
443 iosys_map_incr(&dst_i, dst_pitch_i);
444 }
445 }
446}
447EXPORT_SYMBOL(drm_fb_memcpy);
448
449static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels)
450{
451 u16 *dbuf16 = dbuf;
452 const u16 *sbuf16 = sbuf;
453 const u16 *send16 = sbuf16 + pixels;
454
455 while (sbuf16 < send16)
456 *dbuf16++ = swab16(*sbuf16++);
457}
458
459static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels)
460{
461 u32 *dbuf32 = dbuf;
462 const u32 *sbuf32 = sbuf;
463 const u32 *send32 = sbuf32 + pixels;
464
465 while (sbuf32 < send32)
466 *dbuf32++ = swab32(*sbuf32++);
467}
468
469/**
470 * drm_fb_swab - Swap bytes into clip buffer
471 * @dst: Array of destination buffers
472 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
473 * within @dst; can be NULL if scanlines are stored next to each other.
474 * @src: Array of source buffers
475 * @fb: DRM framebuffer
476 * @clip: Clip rectangle area to copy
477 * @cached: Source buffer is mapped cached (eg. not write-combined)
478 * @state: Transform and conversion state
479 *
480 * This function copies parts of a framebuffer to display memory and swaps per-pixel
481 * bytes during the process. Destination and framebuffer formats must match. The
482 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
483 * least as many entries as there are planes in @fb's format. Each entry stores the
484 * value for the format's respective color plane at the same index. If @cached is
485 * false a temporary buffer is used to cache one pixel line at a time to speed up
486 * slow uncached reads.
487 *
488 * This function does not apply clipping on @dst (i.e. the destination is at the
489 * top-left corner).
490 */
491void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
492 const struct iosys_map *src, const struct drm_framebuffer *fb,
493 const struct drm_rect *clip, bool cached,
494 struct drm_format_conv_state *state)
495{
496 const struct drm_format_info *format = fb->format;
497 u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8);
498 void (*swab_line)(void *dbuf, const void *sbuf, unsigned int npixels);
499
500 switch (cpp) {
501 case 4:
502 swab_line = drm_fb_swab32_line;
503 break;
504 case 2:
505 swab_line = drm_fb_swab16_line;
506 break;
507 default:
508 drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n",
509 &format->format);
510 return;
511 }
512
513 drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, state, swab_line);
514}
515EXPORT_SYMBOL(drm_fb_swab);
516
517static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
518{
519 drm_fb_xfrm_line_32to8(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb332);
520}
521
522/**
523 * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer
524 * @dst: Array of RGB332 destination buffers
525 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
526 * within @dst; can be NULL if scanlines are stored next to each other.
527 * @src: Array of XRGB8888 source buffers
528 * @fb: DRM framebuffer
529 * @clip: Clip rectangle area to copy
530 * @state: Transform and conversion state
531 *
532 * This function copies parts of a framebuffer to display memory and converts the
533 * color format during the process. Destination and framebuffer formats must match. The
534 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
535 * least as many entries as there are planes in @fb's format. Each entry stores the
536 * value for the format's respective color plane at the same index.
537 *
538 * This function does not apply clipping on @dst (i.e. the destination is at the
539 * top-left corner).
540 *
541 * Drivers can use this function for RGB332 devices that don't support XRGB8888 natively.
542 */
543void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
544 const struct iosys_map *src, const struct drm_framebuffer *fb,
545 const struct drm_rect *clip, struct drm_format_conv_state *state)
546{
547 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
548 1,
549 };
550
551 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
552 drm_fb_xrgb8888_to_rgb332_line);
553}
554EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);
555
556static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels)
557{
558 drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb565);
559}
560
561static __always_inline u32 drm_xrgb8888_to_rgb565_swab(u32 pix)
562{
563 return swab16(drm_pixel_xrgb8888_to_rgb565(pix));
564}
565
566/* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */
567static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
568 unsigned int pixels)
569{
570 drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_xrgb8888_to_rgb565_swab);
571}
572
573/**
574 * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
575 * @dst: Array of RGB565 destination buffers
576 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
577 * within @dst; can be NULL if scanlines are stored next to each other.
578 * @src: Array of XRGB8888 source buffer
579 * @fb: DRM framebuffer
580 * @clip: Clip rectangle area to copy
581 * @state: Transform and conversion state
582 * @swab: Swap bytes
583 *
584 * This function copies parts of a framebuffer to display memory and converts the
585 * color format during the process. Destination and framebuffer formats must match. The
586 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
587 * least as many entries as there are planes in @fb's format. Each entry stores the
588 * value for the format's respective color plane at the same index.
589 *
590 * This function does not apply clipping on @dst (i.e. the destination is at the
591 * top-left corner).
592 *
593 * Drivers can use this function for RGB565 devices that don't support XRGB8888 natively.
594 */
595void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
596 const struct iosys_map *src, const struct drm_framebuffer *fb,
597 const struct drm_rect *clip, struct drm_format_conv_state *state,
598 bool swab)
599{
600 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
601 2,
602 };
603
604 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels);
605
606 if (swab)
607 xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line;
608 else
609 xfrm_line = drm_fb_xrgb8888_to_rgb565_line;
610
611 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, xfrm_line);
612}
613EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
614
615static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
616{
617 drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xrgb1555);
618}
619
620/**
621 * drm_fb_xrgb8888_to_xrgb1555 - Convert XRGB8888 to XRGB1555 clip buffer
622 * @dst: Array of XRGB1555 destination buffers
623 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
624 * within @dst; can be NULL if scanlines are stored next to each other.
625 * @src: Array of XRGB8888 source buffer
626 * @fb: DRM framebuffer
627 * @clip: Clip rectangle area to copy
628 * @state: Transform and conversion state
629 *
630 * This function copies parts of a framebuffer to display memory and converts
631 * the color format during the process. The parameters @dst, @dst_pitch and
632 * @src refer to arrays. Each array must have at least as many entries as
633 * there are planes in @fb's format. Each entry stores the value for the
634 * format's respective color plane at the same index.
635 *
636 * This function does not apply clipping on @dst (i.e. the destination is at the
637 * top-left corner).
638 *
639 * Drivers can use this function for XRGB1555 devices that don't support
640 * XRGB8888 natively.
641 */
642void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
643 const struct iosys_map *src, const struct drm_framebuffer *fb,
644 const struct drm_rect *clip, struct drm_format_conv_state *state)
645{
646 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
647 2,
648 };
649
650 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
651 drm_fb_xrgb8888_to_xrgb1555_line);
652}
653EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555);
654
655static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
656{
657 drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_argb1555);
658}
659
660/**
661 * drm_fb_xrgb8888_to_argb1555 - Convert XRGB8888 to ARGB1555 clip buffer
662 * @dst: Array of ARGB1555 destination buffers
663 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
664 * within @dst; can be NULL if scanlines are stored next to each other.
665 * @src: Array of XRGB8888 source buffer
666 * @fb: DRM framebuffer
667 * @clip: Clip rectangle area to copy
668 * @state: Transform and conversion state
669 *
670 * This function copies parts of a framebuffer to display memory and converts
671 * the color format during the process. The parameters @dst, @dst_pitch and
672 * @src refer to arrays. Each array must have at least as many entries as
673 * there are planes in @fb's format. Each entry stores the value for the
674 * format's respective color plane at the same index.
675 *
676 * This function does not apply clipping on @dst (i.e. the destination is at the
677 * top-left corner).
678 *
679 * Drivers can use this function for ARGB1555 devices that don't support
680 * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
681 */
682void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
683 const struct iosys_map *src, const struct drm_framebuffer *fb,
684 const struct drm_rect *clip, struct drm_format_conv_state *state)
685{
686 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
687 2,
688 };
689
690 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
691 drm_fb_xrgb8888_to_argb1555_line);
692}
693EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555);
694
695static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsigned int pixels)
696{
697 drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgba5551);
698}
699
700/**
701 * drm_fb_xrgb8888_to_rgba5551 - Convert XRGB8888 to RGBA5551 clip buffer
702 * @dst: Array of RGBA5551 destination buffers
703 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
704 * within @dst; can be NULL if scanlines are stored next to each other.
705 * @src: Array of XRGB8888 source buffer
706 * @fb: DRM framebuffer
707 * @clip: Clip rectangle area to copy
708 * @state: Transform and conversion state
709 *
710 * This function copies parts of a framebuffer to display memory and converts
711 * the color format during the process. The parameters @dst, @dst_pitch and
712 * @src refer to arrays. Each array must have at least as many entries as
713 * there are planes in @fb's format. Each entry stores the value for the
714 * format's respective color plane at the same index.
715 *
716 * This function does not apply clipping on @dst (i.e. the destination is at the
717 * top-left corner).
718 *
719 * Drivers can use this function for RGBA5551 devices that don't support
720 * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
721 */
722void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch,
723 const struct iosys_map *src, const struct drm_framebuffer *fb,
724 const struct drm_rect *clip, struct drm_format_conv_state *state)
725{
726 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
727 2,
728 };
729
730 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
731 drm_fb_xrgb8888_to_rgba5551_line);
732}
733EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551);
734
735static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels)
736{
737 drm_fb_xfrm_line_32to24(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb888);
738}
739
740/**
741 * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer
742 * @dst: Array of RGB888 destination buffers
743 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
744 * within @dst; can be NULL if scanlines are stored next to each other.
745 * @src: Array of XRGB8888 source buffers
746 * @fb: DRM framebuffer
747 * @clip: Clip rectangle area to copy
748 * @state: Transform and conversion state
749 *
750 * This function copies parts of a framebuffer to display memory and converts the
751 * color format during the process. Destination and framebuffer formats must match. The
752 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
753 * least as many entries as there are planes in @fb's format. Each entry stores the
754 * value for the format's respective color plane at the same index.
755 *
756 * This function does not apply clipping on @dst (i.e. the destination is at the
757 * top-left corner).
758 *
759 * Drivers can use this function for RGB888 devices that don't natively
760 * support XRGB8888.
761 */
762void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch,
763 const struct iosys_map *src, const struct drm_framebuffer *fb,
764 const struct drm_rect *clip, struct drm_format_conv_state *state)
765{
766 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
767 3,
768 };
769
770 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
771 drm_fb_xrgb8888_to_rgb888_line);
772}
773EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
774
775static void drm_fb_xrgb8888_to_bgr888_line(void *dbuf, const void *sbuf, unsigned int pixels)
776{
777 drm_fb_xfrm_line_32to24(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_bgr888);
778}
779
780/**
781 * drm_fb_xrgb8888_to_bgr888 - Convert XRGB8888 to BGR888 clip buffer
782 * @dst: Array of BGR888 destination buffers
783 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
784 * within @dst; can be NULL if scanlines are stored next to each other.
785 * @src: Array of XRGB8888 source buffers
786 * @fb: DRM framebuffer
787 * @clip: Clip rectangle area to copy
788 * @state: Transform and conversion state
789 *
790 * This function copies parts of a framebuffer to display memory and converts the
791 * color format during the process. Destination and framebuffer formats must match. The
792 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
793 * least as many entries as there are planes in @fb's format. Each entry stores the
794 * value for the format's respective color plane at the same index.
795 *
796 * This function does not apply clipping on @dst (i.e. the destination is at the
797 * top-left corner).
798 *
799 * Drivers can use this function for BGR888 devices that don't natively
800 * support XRGB8888.
801 */
802void drm_fb_xrgb8888_to_bgr888(struct iosys_map *dst, const unsigned int *dst_pitch,
803 const struct iosys_map *src, const struct drm_framebuffer *fb,
804 const struct drm_rect *clip, struct drm_format_conv_state *state)
805{
806 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
807 3,
808 };
809
810 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
811 drm_fb_xrgb8888_to_bgr888_line);
812}
813EXPORT_SYMBOL(drm_fb_xrgb8888_to_bgr888);
814
815static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
816{
817 drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_argb8888);
818}
819
820/**
821 * drm_fb_xrgb8888_to_argb8888 - Convert XRGB8888 to ARGB8888 clip buffer
822 * @dst: Array of ARGB8888 destination buffers
823 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
824 * within @dst; can be NULL if scanlines are stored next to each other.
825 * @src: Array of XRGB8888 source buffer
826 * @fb: DRM framebuffer
827 * @clip: Clip rectangle area to copy
828 * @state: Transform and conversion state
829 *
830 * This function copies parts of a framebuffer to display memory and converts the
831 * color format during the process. The parameters @dst, @dst_pitch and @src refer
832 * to arrays. Each array must have at least as many entries as there are planes in
833 * @fb's format. Each entry stores the value for the format's respective color plane
834 * at the same index.
835 *
836 * This function does not apply clipping on @dst (i.e. the destination is at the
837 * top-left corner).
838 *
839 * Drivers can use this function for ARGB8888 devices that don't support XRGB8888
840 * natively. It sets an opaque alpha channel as part of the conversion.
841 */
842void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
843 const struct iosys_map *src, const struct drm_framebuffer *fb,
844 const struct drm_rect *clip, struct drm_format_conv_state *state)
845{
846 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
847 4,
848 };
849
850 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
851 drm_fb_xrgb8888_to_argb8888_line);
852}
853EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888);
854
855static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
856{
857 drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_abgr8888);
858}
859
860static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
861 const struct iosys_map *src,
862 const struct drm_framebuffer *fb,
863 const struct drm_rect *clip,
864 struct drm_format_conv_state *state)
865{
866 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
867 4,
868 };
869
870 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
871 drm_fb_xrgb8888_to_abgr8888_line);
872}
873
874static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
875{
876 drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xbgr8888);
877}
878
879static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
880 const struct iosys_map *src,
881 const struct drm_framebuffer *fb,
882 const struct drm_rect *clip,
883 struct drm_format_conv_state *state)
884{
885 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
886 4,
887 };
888
889 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
890 drm_fb_xrgb8888_to_xbgr8888_line);
891}
892
893static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
894{
895 drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xrgb2101010);
896}
897
898/**
899 * drm_fb_xrgb8888_to_xrgb2101010 - Convert XRGB8888 to XRGB2101010 clip buffer
900 * @dst: Array of XRGB2101010 destination buffers
901 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
902 * within @dst; can be NULL if scanlines are stored next to each other.
903 * @src: Array of XRGB8888 source buffers
904 * @fb: DRM framebuffer
905 * @clip: Clip rectangle area to copy
906 * @state: Transform and conversion state
907 *
908 * This function copies parts of a framebuffer to display memory and converts the
909 * color format during the process. Destination and framebuffer formats must match. The
910 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
911 * least as many entries as there are planes in @fb's format. Each entry stores the
912 * value for the format's respective color plane at the same index.
913 *
914 * This function does not apply clipping on @dst (i.e. the destination is at the
915 * top-left corner).
916 *
917 * Drivers can use this function for XRGB2101010 devices that don't support XRGB8888
918 * natively.
919 */
920void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
921 const struct iosys_map *src, const struct drm_framebuffer *fb,
922 const struct drm_rect *clip,
923 struct drm_format_conv_state *state)
924{
925 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
926 4,
927 };
928
929 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
930 drm_fb_xrgb8888_to_xrgb2101010_line);
931}
932EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010);
933
934static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
935{
936 drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_argb2101010);
937}
938
939/**
940 * drm_fb_xrgb8888_to_argb2101010 - Convert XRGB8888 to ARGB2101010 clip buffer
941 * @dst: Array of ARGB2101010 destination buffers
942 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
943 * within @dst; can be NULL if scanlines are stored next to each other.
944 * @src: Array of XRGB8888 source buffers
945 * @fb: DRM framebuffer
946 * @clip: Clip rectangle area to copy
947 * @state: Transform and conversion state
948 *
949 * This function copies parts of a framebuffer to display memory and converts
950 * the color format during the process. The parameters @dst, @dst_pitch and
951 * @src refer to arrays. Each array must have at least as many entries as
952 * there are planes in @fb's format. Each entry stores the value for the
953 * format's respective color plane at the same index.
954 *
955 * This function does not apply clipping on @dst (i.e. the destination is at the
956 * top-left corner).
957 *
958 * Drivers can use this function for ARGB2101010 devices that don't support XRGB8888
959 * natively.
960 */
961void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
962 const struct iosys_map *src, const struct drm_framebuffer *fb,
963 const struct drm_rect *clip,
964 struct drm_format_conv_state *state)
965{
966 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
967 4,
968 };
969
970 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
971 drm_fb_xrgb8888_to_argb2101010_line);
972}
973EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010);
974
975static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels)
976{
977 drm_fb_xfrm_line_32to8(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_r8_bt601);
978}
979
980/**
981 * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
982 * @dst: Array of 8-bit grayscale destination buffers
983 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
984 * within @dst; can be NULL if scanlines are stored next to each other.
985 * @src: Array of XRGB8888 source buffers
986 * @fb: DRM framebuffer
987 * @clip: Clip rectangle area to copy
988 * @state: Transform and conversion state
989 *
990 * This function copies parts of a framebuffer to display memory and converts the
991 * color format during the process. Destination and framebuffer formats must match. The
992 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
993 * least as many entries as there are planes in @fb's format. Each entry stores the
994 * value for the format's respective color plane at the same index.
995 *
996 * This function does not apply clipping on @dst (i.e. the destination is at the
997 * top-left corner).
998 *
999 * DRM doesn't have native monochrome or grayscale support. Drivers can use this
1000 * function for grayscale devices that don't support XRGB8888 natively.Such
1001 * drivers can announce the commonly supported XR24 format to userspace and use
1002 * this function to convert to the native format. Monochrome drivers will use the
1003 * most significant bit, where 1 means foreground color and 0 background color.
1004 * ITU BT.601 is being used for the RGB -> luma (brightness) conversion.
1005 */
1006void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch,
1007 const struct iosys_map *src, const struct drm_framebuffer *fb,
1008 const struct drm_rect *clip, struct drm_format_conv_state *state)
1009{
1010 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
1011 1,
1012 };
1013
1014 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
1015 drm_fb_xrgb8888_to_gray8_line);
1016}
1017EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
1018
1019static void drm_fb_argb8888_to_argb4444_line(void *dbuf, const void *sbuf, unsigned int pixels)
1020{
1021 drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_argb8888_to_argb4444);
1022}
1023
1024/**
1025 * drm_fb_argb8888_to_argb4444 - Convert ARGB8888 to ARGB4444 clip buffer
1026 * @dst: Array of ARGB4444 destination buffers
1027 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
1028 * within @dst; can be NULL if scanlines are stored next to each other.
1029 * @src: Array of ARGB8888 source buffer
1030 * @fb: DRM framebuffer
1031 * @clip: Clip rectangle area to copy
1032 * @state: Transform and conversion state
1033 *
1034 * This function copies parts of a framebuffer to display memory and converts
1035 * the color format during the process. The parameters @dst, @dst_pitch and
1036 * @src refer to arrays. Each array must have at least as many entries as
1037 * there are planes in @fb's format. Each entry stores the value for the
1038 * format's respective color plane at the same index.
1039 *
1040 * This function does not apply clipping on @dst (i.e. the destination is at the
1041 * top-left corner).
1042 *
1043 * Drivers can use this function for ARGB4444 devices that don't support
1044 * ARGB8888 natively.
1045 */
1046void drm_fb_argb8888_to_argb4444(struct iosys_map *dst, const unsigned int *dst_pitch,
1047 const struct iosys_map *src, const struct drm_framebuffer *fb,
1048 const struct drm_rect *clip, struct drm_format_conv_state *state)
1049{
1050 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
1051 2,
1052 };
1053
1054 drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
1055 drm_fb_argb8888_to_argb4444_line);
1056}
1057EXPORT_SYMBOL(drm_fb_argb8888_to_argb4444);
1058
1059/**
1060 * drm_fb_blit - Copy parts of a framebuffer to display memory
1061 * @dst: Array of display-memory addresses to copy to
1062 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
1063 * within @dst; can be NULL if scanlines are stored next to each other.
1064 * @dst_format: FOURCC code of the display's color format
1065 * @src: The framebuffer memory to copy from
1066 * @fb: The framebuffer to copy from
1067 * @clip: Clip rectangle area to copy
1068 * @state: Transform and conversion state
1069 *
1070 * This function copies parts of a framebuffer to display memory. If the
1071 * formats of the display and the framebuffer mismatch, the blit function
1072 * will attempt to convert between them during the process. The parameters @dst,
1073 * @dst_pitch and @src refer to arrays. Each array must have at least as many
1074 * entries as there are planes in @dst_format's format. Each entry stores the
1075 * value for the format's respective color plane at the same index.
1076 *
1077 * This function does not apply clipping on @dst (i.e. the destination is at the
1078 * top-left corner).
1079 *
1080 * Returns:
1081 * 0 on success, or
1082 * -EINVAL if the color-format conversion failed, or
1083 * a negative error code otherwise.
1084 */
1085int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format,
1086 const struct iosys_map *src, const struct drm_framebuffer *fb,
1087 const struct drm_rect *clip, struct drm_format_conv_state *state)
1088{
1089 uint32_t fb_format = fb->format->format;
1090
1091 if (fb_format == dst_format) {
1092 drm_fb_memcpy(dst, dst_pitch, src, fb, clip);
1093 return 0;
1094 } else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) {
1095 drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state);
1096 return 0;
1097 } else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) {
1098 drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state);
1099 return 0;
1100 } else if (fb_format == DRM_FORMAT_XRGB8888) {
1101 if (dst_format == DRM_FORMAT_RGB565) {
1102 drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state, false);
1103 return 0;
1104 } else if (dst_format == DRM_FORMAT_XRGB1555) {
1105 drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, state);
1106 return 0;
1107 } else if (dst_format == DRM_FORMAT_ARGB1555) {
1108 drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip, state);
1109 return 0;
1110 } else if (dst_format == DRM_FORMAT_RGBA5551) {
1111 drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip, state);
1112 return 0;
1113 } else if (dst_format == DRM_FORMAT_RGB888) {
1114 drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip, state);
1115 return 0;
1116 } else if (dst_format == DRM_FORMAT_BGR888) {
1117 drm_fb_xrgb8888_to_bgr888(dst, dst_pitch, src, fb, clip, state);
1118 return 0;
1119 } else if (dst_format == DRM_FORMAT_ARGB8888) {
1120 drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip, state);
1121 return 0;
1122 } else if (dst_format == DRM_FORMAT_XBGR8888) {
1123 drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip, state);
1124 return 0;
1125 } else if (dst_format == DRM_FORMAT_ABGR8888) {
1126 drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip, state);
1127 return 0;
1128 } else if (dst_format == DRM_FORMAT_XRGB2101010) {
1129 drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip, state);
1130 return 0;
1131 } else if (dst_format == DRM_FORMAT_ARGB2101010) {
1132 drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip, state);
1133 return 0;
1134 } else if (dst_format == DRM_FORMAT_BGRX8888) {
1135 drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state);
1136 return 0;
1137 }
1138 }
1139
1140 drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n",
1141 &fb_format, &dst_format);
1142
1143 return -EINVAL;
1144}
1145EXPORT_SYMBOL(drm_fb_blit);
1146
1147static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int pixels)
1148{
1149 u8 *dbuf8 = dbuf;
1150 const u8 *sbuf8 = sbuf;
1151
1152 while (pixels) {
1153 unsigned int i, bits = min(pixels, 8U);
1154 u8 byte = 0;
1155
1156 for (i = 0; i < bits; i++, pixels--) {
1157 if (*sbuf8++ >= 128)
1158 byte |= BIT(i);
1159 }
1160 *dbuf8++ = byte;
1161 }
1162}
1163
1164/**
1165 * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome
1166 * @dst: Array of monochrome destination buffers (0=black, 1=white)
1167 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
1168 * within @dst; can be NULL if scanlines are stored next to each other.
1169 * @src: Array of XRGB8888 source buffers
1170 * @fb: DRM framebuffer
1171 * @clip: Clip rectangle area to copy
1172 * @state: Transform and conversion state
1173 *
1174 * This function copies parts of a framebuffer to display memory and converts the
1175 * color format during the process. Destination and framebuffer formats must match. The
1176 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
1177 * least as many entries as there are planes in @fb's format. Each entry stores the
1178 * value for the format's respective color plane at the same index.
1179 *
1180 * This function does not apply clipping on @dst (i.e. the destination is at the
1181 * top-left corner). The first pixel (upper left corner of the clip rectangle) will
1182 * be converted and copied to the first bit (LSB) in the first byte of the monochrome
1183 * destination buffer. If the caller requires that the first pixel in a byte must
1184 * be located at an x-coordinate that is a multiple of 8, then the caller must take
1185 * care itself of supplying a suitable clip rectangle.
1186 *
1187 * DRM doesn't have native monochrome support. Drivers can use this function for
1188 * monochrome devices that don't support XRGB8888 natively. Such drivers can
1189 * announce the commonly supported XR24 format to userspace and use this function
1190 * to convert to the native format.
1191 *
1192 * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and
1193 * then the result is converted from grayscale to monochrome.
1194 */
1195void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch,
1196 const struct iosys_map *src, const struct drm_framebuffer *fb,
1197 const struct drm_rect *clip, struct drm_format_conv_state *state)
1198{
1199 static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
1200 0, 0, 0, 0
1201 };
1202 unsigned int linepixels = drm_rect_width(clip);
1203 unsigned int lines = drm_rect_height(clip);
1204 unsigned int cpp = fb->format->cpp[0];
1205 unsigned int len_src32 = linepixels * cpp;
1206 struct drm_device *dev = fb->dev;
1207 void *vaddr = src[0].vaddr;
1208 unsigned int dst_pitch_0;
1209 unsigned int y;
1210 u8 *mono = dst[0].vaddr, *gray8;
1211 u32 *src32;
1212
1213 if (drm_WARN_ON(dev, fb->format->format != DRM_FORMAT_XRGB8888))
1214 return;
1215
1216 if (!dst_pitch)
1217 dst_pitch = default_dst_pitch;
1218 dst_pitch_0 = dst_pitch[0];
1219
1220 /*
1221 * The mono destination buffer contains 1 bit per pixel
1222 */
1223 if (!dst_pitch_0)
1224 dst_pitch_0 = DIV_ROUND_UP(linepixels, 8);
1225
1226 /*
1227 * The dma memory is write-combined so reads are uncached.
1228 * Speed up by fetching one line at a time.
1229 *
1230 * Also, format conversion from XR24 to monochrome are done
1231 * line-by-line but are converted to 8-bit grayscale as an
1232 * intermediate step.
1233 *
1234 * Allocate a buffer to be used for both copying from the cma
1235 * memory and to store the intermediate grayscale line pixels.
1236 */
1237 src32 = drm_format_conv_state_reserve(state, len_src32 + linepixels, GFP_KERNEL);
1238 if (!src32)
1239 return;
1240
1241 gray8 = (u8 *)src32 + len_src32;
1242
1243 vaddr += clip_offset(clip, fb->pitches[0], cpp);
1244 for (y = 0; y < lines; y++) {
1245 src32 = memcpy(src32, vaddr, len_src32);
1246 drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels);
1247 drm_fb_gray8_to_mono_line(mono, gray8, linepixels);
1248 vaddr += fb->pitches[0];
1249 mono += dst_pitch_0;
1250 }
1251}
1252EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
1253
1254static uint32_t drm_fb_nonalpha_fourcc(uint32_t fourcc)
1255{
1256 /* only handle formats with depth != 0 and alpha channel */
1257 switch (fourcc) {
1258 case DRM_FORMAT_ARGB1555:
1259 return DRM_FORMAT_XRGB1555;
1260 case DRM_FORMAT_ABGR1555:
1261 return DRM_FORMAT_XBGR1555;
1262 case DRM_FORMAT_RGBA5551:
1263 return DRM_FORMAT_RGBX5551;
1264 case DRM_FORMAT_BGRA5551:
1265 return DRM_FORMAT_BGRX5551;
1266 case DRM_FORMAT_ARGB8888:
1267 return DRM_FORMAT_XRGB8888;
1268 case DRM_FORMAT_ABGR8888:
1269 return DRM_FORMAT_XBGR8888;
1270 case DRM_FORMAT_RGBA8888:
1271 return DRM_FORMAT_RGBX8888;
1272 case DRM_FORMAT_BGRA8888:
1273 return DRM_FORMAT_BGRX8888;
1274 case DRM_FORMAT_ARGB2101010:
1275 return DRM_FORMAT_XRGB2101010;
1276 case DRM_FORMAT_ABGR2101010:
1277 return DRM_FORMAT_XBGR2101010;
1278 case DRM_FORMAT_RGBA1010102:
1279 return DRM_FORMAT_RGBX1010102;
1280 case DRM_FORMAT_BGRA1010102:
1281 return DRM_FORMAT_BGRX1010102;
1282 }
1283
1284 return fourcc;
1285}
1286
1287static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc)
1288{
1289 const uint32_t *fourccs_end = fourccs + nfourccs;
1290
1291 while (fourccs < fourccs_end) {
1292 if (*fourccs == fourcc)
1293 return true;
1294 ++fourccs;
1295 }
1296 return false;
1297}
1298
1299/**
1300 * drm_fb_build_fourcc_list - Filters a list of supported color formats against
1301 * the device's native formats
1302 * @dev: DRM device
1303 * @native_fourccs: 4CC codes of natively supported color formats
1304 * @native_nfourccs: The number of entries in @native_fourccs
1305 * @fourccs_out: Returns 4CC codes of supported color formats
1306 * @nfourccs_out: The number of available entries in @fourccs_out
1307 *
1308 * This function create a list of supported color format from natively
1309 * supported formats and additional emulated formats.
1310 * At a minimum, most userspace programs expect at least support for
1311 * XRGB8888 on the primary plane. Devices that have to emulate the
1312 * format, and possibly others, can use drm_fb_build_fourcc_list() to
1313 * create a list of supported color formats. The returned list can
1314 * be handed over to drm_universal_plane_init() et al. Native formats
1315 * will go before emulated formats. Native formats with alpha channel
1316 * will be replaced by such without, as primary planes usually don't
1317 * support alpha. Other heuristics might be applied
1318 * to optimize the order. Formats near the beginning of the list are
1319 * usually preferred over formats near the end of the list.
1320 *
1321 * Returns:
1322 * The number of color-formats 4CC codes returned in @fourccs_out.
1323 */
1324size_t drm_fb_build_fourcc_list(struct drm_device *dev,
1325 const u32 *native_fourccs, size_t native_nfourccs,
1326 u32 *fourccs_out, size_t nfourccs_out)
1327{
1328 /*
1329 * XRGB8888 is the default fallback format for most of userspace
1330 * and it's currently the only format that should be emulated for
1331 * the primary plane. Only if there's ever another default fallback,
1332 * it should be added here.
1333 */
1334 static const uint32_t extra_fourccs[] = {
1335 DRM_FORMAT_XRGB8888,
1336 };
1337 static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs);
1338
1339 u32 *fourccs = fourccs_out;
1340 const u32 *fourccs_end = fourccs_out + nfourccs_out;
1341 size_t i;
1342
1343 /*
1344 * The device's native formats go first.
1345 */
1346
1347 for (i = 0; i < native_nfourccs; ++i) {
1348 /*
1349 * Several DTs, boot loaders and firmware report native
1350 * alpha formats that are non-alpha formats instead. So
1351 * replace alpha formats by non-alpha formats.
1352 */
1353 u32 fourcc = drm_fb_nonalpha_fourcc(native_fourccs[i]);
1354
1355 if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
1356 continue; /* skip duplicate entries */
1357 } else if (fourccs == fourccs_end) {
1358 drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc);
1359 continue; /* end of available output buffer */
1360 }
1361
1362 drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc);
1363
1364 *fourccs = fourcc;
1365 ++fourccs;
1366 }
1367
1368 /*
1369 * The extra formats, emulated by the driver, go second.
1370 */
1371
1372 for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) {
1373 u32 fourcc = extra_fourccs[i];
1374
1375 if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
1376 continue; /* skip duplicate and native entries */
1377 } else if (fourccs == fourccs_end) {
1378 drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc);
1379 continue; /* end of available output buffer */
1380 }
1381
1382 drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc);
1383
1384 *fourccs = fourcc;
1385 ++fourccs;
1386 }
1387
1388 return fourccs - fourccs_out;
1389}
1390EXPORT_SYMBOL(drm_fb_build_fourcc_list);