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