xref: /openbsd-src/sys/dev/pci/drm/drm_format_helper.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
1c349dbc7Sjsg // SPDX-License-Identifier: GPL-2.0 or MIT
2c349dbc7Sjsg /*
3c349dbc7Sjsg  * Copyright (C) 2016 Noralf Trønnes
4c349dbc7Sjsg  *
5c349dbc7Sjsg  * This program is free software; you can redistribute it and/or modify
6c349dbc7Sjsg  * it under the terms of the GNU General Public License as published by
7c349dbc7Sjsg  * the Free Software Foundation; either version 2 of the License, or
8c349dbc7Sjsg  * (at your option) any later version.
9c349dbc7Sjsg  */
10c349dbc7Sjsg 
111bb76ff1Sjsg #include <linux/io.h>
121bb76ff1Sjsg #include <linux/iosys-map.h>
13c349dbc7Sjsg #include <linux/module.h>
14c349dbc7Sjsg #include <linux/slab.h>
15c349dbc7Sjsg 
161bb76ff1Sjsg #include <drm/drm_device.h>
17c349dbc7Sjsg #include <drm/drm_format_helper.h>
18c349dbc7Sjsg #include <drm/drm_framebuffer.h>
19c349dbc7Sjsg #include <drm/drm_fourcc.h>
201bb76ff1Sjsg #include <drm/drm_print.h>
21c349dbc7Sjsg #include <drm/drm_rect.h>
22c349dbc7Sjsg 
clip_offset(const struct drm_rect * clip,unsigned int pitch,unsigned int cpp)231bb76ff1Sjsg static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
24c349dbc7Sjsg {
25c349dbc7Sjsg 	return clip->y1 * pitch + clip->x1 * cpp;
26c349dbc7Sjsg }
27c349dbc7Sjsg 
28c349dbc7Sjsg /**
291bb76ff1Sjsg  * drm_fb_clip_offset - Returns the clipping rectangles byte-offset in a framebuffer
301bb76ff1Sjsg  * @pitch: Framebuffer line pitch in byte
311bb76ff1Sjsg  * @format: Framebuffer format
321bb76ff1Sjsg  * @clip: Clip rectangle
331bb76ff1Sjsg  *
341bb76ff1Sjsg  * Returns:
351bb76ff1Sjsg  * The byte offset of the clip rectangle's top-left corner within the framebuffer.
361bb76ff1Sjsg  */
drm_fb_clip_offset(unsigned int pitch,const struct drm_format_info * format,const struct drm_rect * clip)371bb76ff1Sjsg unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
381bb76ff1Sjsg 				const struct drm_rect *clip)
391bb76ff1Sjsg {
401bb76ff1Sjsg 	return clip_offset(clip, pitch, format->cpp[0]);
411bb76ff1Sjsg }
421bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_clip_offset);
431bb76ff1Sjsg 
441bb76ff1Sjsg /* 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,void (* xfrm_line)(void * dbuf,const void * sbuf,unsigned int npixels))451bb76ff1Sjsg static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
461bb76ff1Sjsg 			 const void *vaddr, const struct drm_framebuffer *fb,
471bb76ff1Sjsg 			 const struct drm_rect *clip, bool vaddr_cached_hint,
481bb76ff1Sjsg 			 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
491bb76ff1Sjsg {
501bb76ff1Sjsg 	unsigned long linepixels = drm_rect_width(clip);
511bb76ff1Sjsg 	unsigned long lines = drm_rect_height(clip);
521bb76ff1Sjsg 	size_t sbuf_len = linepixels * fb->format->cpp[0];
531bb76ff1Sjsg 	void *stmp = NULL;
541bb76ff1Sjsg 	unsigned long i;
551bb76ff1Sjsg 	const void *sbuf;
561bb76ff1Sjsg 
571bb76ff1Sjsg 	/*
581bb76ff1Sjsg 	 * Some source buffers, such as DMA memory, use write-combine
591bb76ff1Sjsg 	 * caching, so reads are uncached. Speed up access by fetching
601bb76ff1Sjsg 	 * one line at a time.
611bb76ff1Sjsg 	 */
621bb76ff1Sjsg 	if (!vaddr_cached_hint) {
631bb76ff1Sjsg 		stmp = kmalloc(sbuf_len, GFP_KERNEL);
641bb76ff1Sjsg 		if (!stmp)
651bb76ff1Sjsg 			return -ENOMEM;
661bb76ff1Sjsg 	}
671bb76ff1Sjsg 
681bb76ff1Sjsg 	if (!dst_pitch)
691bb76ff1Sjsg 		dst_pitch = drm_rect_width(clip) * dst_pixsize;
701bb76ff1Sjsg 	vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
711bb76ff1Sjsg 
721bb76ff1Sjsg 	for (i = 0; i < lines; ++i) {
731bb76ff1Sjsg 		if (stmp)
741bb76ff1Sjsg 			sbuf = memcpy(stmp, vaddr, sbuf_len);
751bb76ff1Sjsg 		else
761bb76ff1Sjsg 			sbuf = vaddr;
771bb76ff1Sjsg 		xfrm_line(dst, sbuf, linepixels);
781bb76ff1Sjsg 		vaddr += fb->pitches[0];
791bb76ff1Sjsg 		dst += dst_pitch;
801bb76ff1Sjsg 	}
811bb76ff1Sjsg 
821bb76ff1Sjsg 	kfree(stmp);
831bb76ff1Sjsg 
841bb76ff1Sjsg 	return 0;
851bb76ff1Sjsg }
861bb76ff1Sjsg 
871bb76ff1Sjsg /* 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,void (* xfrm_line)(void * dbuf,const void * sbuf,unsigned int npixels))881bb76ff1Sjsg static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
891bb76ff1Sjsg 			      const void *vaddr, const struct drm_framebuffer *fb,
901bb76ff1Sjsg 			      const struct drm_rect *clip, bool vaddr_cached_hint,
911bb76ff1Sjsg 			      void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
921bb76ff1Sjsg {
931bb76ff1Sjsg 	unsigned long linepixels = drm_rect_width(clip);
941bb76ff1Sjsg 	unsigned long lines = drm_rect_height(clip);
951bb76ff1Sjsg 	size_t dbuf_len = linepixels * dst_pixsize;
961bb76ff1Sjsg 	size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */
971bb76ff1Sjsg 	size_t sbuf_len = linepixels * fb->format->cpp[0];
981bb76ff1Sjsg 	void *stmp = NULL;
991bb76ff1Sjsg 	unsigned long i;
1001bb76ff1Sjsg 	const void *sbuf;
1011bb76ff1Sjsg 	void *dbuf;
1021bb76ff1Sjsg 
1031bb76ff1Sjsg 	if (vaddr_cached_hint) {
1041bb76ff1Sjsg 		dbuf = kmalloc(dbuf_len, GFP_KERNEL);
1051bb76ff1Sjsg 	} else {
1061bb76ff1Sjsg 		dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL);
1071bb76ff1Sjsg 		stmp = dbuf + stmp_off;
1081bb76ff1Sjsg 	}
1091bb76ff1Sjsg 	if (!dbuf)
1101bb76ff1Sjsg 		return -ENOMEM;
1111bb76ff1Sjsg 
1121bb76ff1Sjsg 	if (!dst_pitch)
1131bb76ff1Sjsg 		dst_pitch = linepixels * dst_pixsize;
1141bb76ff1Sjsg 	vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
1151bb76ff1Sjsg 
1161bb76ff1Sjsg 	for (i = 0; i < lines; ++i) {
1171bb76ff1Sjsg 		if (stmp)
1181bb76ff1Sjsg 			sbuf = memcpy(stmp, vaddr, sbuf_len);
1191bb76ff1Sjsg 		else
1201bb76ff1Sjsg 			sbuf = vaddr;
1211bb76ff1Sjsg 		xfrm_line(dbuf, sbuf, linepixels);
1221bb76ff1Sjsg 		memcpy_toio(dst, dbuf, dbuf_len);
1231bb76ff1Sjsg 		vaddr += fb->pitches[0];
1241bb76ff1Sjsg 		dst += dst_pitch;
1251bb76ff1Sjsg 	}
1261bb76ff1Sjsg 
1271bb76ff1Sjsg 	kfree(dbuf);
1281bb76ff1Sjsg 
1291bb76ff1Sjsg 	return 0;
1301bb76ff1Sjsg }
1311bb76ff1Sjsg 
1321bb76ff1Sjsg /* 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,void (* xfrm_line)(void * dbuf,const void * sbuf,unsigned int npixels))1331bb76ff1Sjsg static int drm_fb_xfrm(struct iosys_map *dst,
1341bb76ff1Sjsg 		       const unsigned int *dst_pitch, const u8 *dst_pixsize,
1351bb76ff1Sjsg 		       const struct iosys_map *src, const struct drm_framebuffer *fb,
1361bb76ff1Sjsg 		       const struct drm_rect *clip, bool vaddr_cached_hint,
1371bb76ff1Sjsg 		       void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
1381bb76ff1Sjsg {
1391bb76ff1Sjsg 	static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
1401bb76ff1Sjsg 		0, 0, 0, 0
1411bb76ff1Sjsg 	};
1421bb76ff1Sjsg 
1431bb76ff1Sjsg 	if (!dst_pitch)
1441bb76ff1Sjsg 		dst_pitch = default_dst_pitch;
1451bb76ff1Sjsg 
1461bb76ff1Sjsg 	/* TODO: handle src in I/O memory here */
1471bb76ff1Sjsg 	if (dst[0].is_iomem)
1481bb76ff1Sjsg 		return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0],
1491bb76ff1Sjsg 					  src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line);
1501bb76ff1Sjsg 	else
1511bb76ff1Sjsg 		return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0],
1521bb76ff1Sjsg 				     src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line);
1531bb76ff1Sjsg }
1541bb76ff1Sjsg 
1551bb76ff1Sjsg /**
156c349dbc7Sjsg  * drm_fb_memcpy - Copy clip buffer
1571bb76ff1Sjsg  * @dst: Array of destination buffers
1581bb76ff1Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
1591bb76ff1Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
1601bb76ff1Sjsg  * @src: Array of source buffers
161c349dbc7Sjsg  * @fb: DRM framebuffer
162c349dbc7Sjsg  * @clip: Clip rectangle area to copy
163c349dbc7Sjsg  *
1641bb76ff1Sjsg  * This function copies parts of a framebuffer to display memory. Destination and
1651bb76ff1Sjsg  * framebuffer formats must match. No conversion takes place. The parameters @dst,
1661bb76ff1Sjsg  * @dst_pitch and @src refer to arrays. Each array must have at least as many entries
1671bb76ff1Sjsg  * as there are planes in @fb's format. Each entry stores the value for the format's
1681bb76ff1Sjsg  * respective color plane at the same index.
1691bb76ff1Sjsg  *
1701bb76ff1Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
1711bb76ff1Sjsg  * top-left corner).
172c349dbc7Sjsg  */
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)1731bb76ff1Sjsg void drm_fb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch,
1741bb76ff1Sjsg 		   const struct iosys_map *src, const struct drm_framebuffer *fb,
1751bb76ff1Sjsg 		   const struct drm_rect *clip)
176c349dbc7Sjsg {
1771bb76ff1Sjsg 	static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
1781bb76ff1Sjsg 		0, 0, 0, 0
1791bb76ff1Sjsg 	};
180c349dbc7Sjsg 
1811bb76ff1Sjsg 	const struct drm_format_info *format = fb->format;
1821bb76ff1Sjsg 	unsigned int i, y, lines = drm_rect_height(clip);
1831bb76ff1Sjsg 
1841bb76ff1Sjsg 	if (!dst_pitch)
1851bb76ff1Sjsg 		dst_pitch = default_dst_pitch;
1861bb76ff1Sjsg 
1871bb76ff1Sjsg 	for (i = 0; i < format->num_planes; ++i) {
1881bb76ff1Sjsg 		unsigned int bpp_i = drm_format_info_bpp(format, i);
1891bb76ff1Sjsg 		unsigned int cpp_i = DIV_ROUND_UP(bpp_i, 8);
1901bb76ff1Sjsg 		size_t len_i = DIV_ROUND_UP(drm_rect_width(clip) * bpp_i, 8);
1911bb76ff1Sjsg 		unsigned int dst_pitch_i = dst_pitch[i];
1921bb76ff1Sjsg 		struct iosys_map dst_i = dst[i];
1931bb76ff1Sjsg 		struct iosys_map src_i = src[i];
1941bb76ff1Sjsg 
1951bb76ff1Sjsg 		if (!dst_pitch_i)
1961bb76ff1Sjsg 			dst_pitch_i = len_i;
1971bb76ff1Sjsg 
1981bb76ff1Sjsg 		iosys_map_incr(&src_i, clip_offset(clip, fb->pitches[i], cpp_i));
199c349dbc7Sjsg 		for (y = 0; y < lines; y++) {
2001bb76ff1Sjsg 			/* TODO: handle src_i in I/O memory here */
2011bb76ff1Sjsg 			iosys_map_memcpy_to(&dst_i, 0, src_i.vaddr, len_i);
2021bb76ff1Sjsg 			iosys_map_incr(&src_i, fb->pitches[i]);
2031bb76ff1Sjsg 			iosys_map_incr(&dst_i, dst_pitch_i);
2041bb76ff1Sjsg 		}
205c349dbc7Sjsg 	}
206c349dbc7Sjsg }
207c349dbc7Sjsg EXPORT_SYMBOL(drm_fb_memcpy);
208c349dbc7Sjsg 
drm_fb_swab16_line(void * dbuf,const void * sbuf,unsigned int pixels)2091bb76ff1Sjsg static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels)
210c349dbc7Sjsg {
2111bb76ff1Sjsg 	u16 *dbuf16 = dbuf;
2121bb76ff1Sjsg 	const u16 *sbuf16 = sbuf;
2131bb76ff1Sjsg 	const u16 *send16 = sbuf16 + pixels;
214c349dbc7Sjsg 
2151bb76ff1Sjsg 	while (sbuf16 < send16)
2161bb76ff1Sjsg 		*dbuf16++ = swab16(*sbuf16++);
217c349dbc7Sjsg }
2181bb76ff1Sjsg 
drm_fb_swab32_line(void * dbuf,const void * sbuf,unsigned int pixels)2191bb76ff1Sjsg static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels)
2201bb76ff1Sjsg {
2211bb76ff1Sjsg 	u32 *dbuf32 = dbuf;
2221bb76ff1Sjsg 	const u32 *sbuf32 = sbuf;
2231bb76ff1Sjsg 	const u32 *send32 = sbuf32 + pixels;
2241bb76ff1Sjsg 
2251bb76ff1Sjsg 	while (sbuf32 < send32)
2261bb76ff1Sjsg 		*dbuf32++ = swab32(*sbuf32++);
227c349dbc7Sjsg }
228c349dbc7Sjsg 
229c349dbc7Sjsg /**
230ad8b1aafSjsg  * drm_fb_swab - Swap bytes into clip buffer
2311bb76ff1Sjsg  * @dst: Array of destination buffers
2321bb76ff1Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
2331bb76ff1Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
2341bb76ff1Sjsg  * @src: Array of source buffers
235c349dbc7Sjsg  * @fb: DRM framebuffer
236c349dbc7Sjsg  * @clip: Clip rectangle area to copy
237ad8b1aafSjsg  * @cached: Source buffer is mapped cached (eg. not write-combined)
238ad8b1aafSjsg  *
2391bb76ff1Sjsg  * This function copies parts of a framebuffer to display memory and swaps per-pixel
2401bb76ff1Sjsg  * bytes during the process. Destination and framebuffer formats must match. The
2411bb76ff1Sjsg  * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
2421bb76ff1Sjsg  * least as many entries as there are planes in @fb's format. Each entry stores the
2431bb76ff1Sjsg  * value for the format's respective color plane at the same index. If @cached is
2441bb76ff1Sjsg  * false a temporary buffer is used to cache one pixel line at a time to speed up
2451bb76ff1Sjsg  * slow uncached reads.
246ad8b1aafSjsg  *
2471bb76ff1Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
2481bb76ff1Sjsg  * top-left corner).
249c349dbc7Sjsg  */
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)2501bb76ff1Sjsg void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
2511bb76ff1Sjsg 		 const struct iosys_map *src, const struct drm_framebuffer *fb,
2521bb76ff1Sjsg 		 const struct drm_rect *clip, bool cached)
253c349dbc7Sjsg {
2541bb76ff1Sjsg 	const struct drm_format_info *format = fb->format;
2551bb76ff1Sjsg 	u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8);
2561bb76ff1Sjsg 	void (*swab_line)(void *dbuf, const void *sbuf, unsigned int npixels);
257c349dbc7Sjsg 
2581bb76ff1Sjsg 	switch (cpp) {
2591bb76ff1Sjsg 	case 4:
2601bb76ff1Sjsg 		swab_line = drm_fb_swab32_line;
2611bb76ff1Sjsg 		break;
2621bb76ff1Sjsg 	case 2:
2631bb76ff1Sjsg 		swab_line = drm_fb_swab16_line;
2641bb76ff1Sjsg 		break;
2651bb76ff1Sjsg 	default:
2661bb76ff1Sjsg 		drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n",
2671bb76ff1Sjsg 			      &format->format);
268c349dbc7Sjsg 		return;
269ad8b1aafSjsg 	}
270ad8b1aafSjsg 
2711bb76ff1Sjsg 	drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, swab_line);
272c349dbc7Sjsg }
273ad8b1aafSjsg EXPORT_SYMBOL(drm_fb_swab);
274c349dbc7Sjsg 
drm_fb_xrgb8888_to_rgb332_line(void * dbuf,const void * sbuf,unsigned int pixels)2751bb76ff1Sjsg static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
276c349dbc7Sjsg {
2771bb76ff1Sjsg 	u8 *dbuf8 = dbuf;
2781bb76ff1Sjsg 	const __le32 *sbuf32 = sbuf;
279c349dbc7Sjsg 	unsigned int x;
2801bb76ff1Sjsg 	u32 pix;
281c349dbc7Sjsg 
282c349dbc7Sjsg 	for (x = 0; x < pixels; x++) {
2831bb76ff1Sjsg 		pix = le32_to_cpu(sbuf32[x]);
2841bb76ff1Sjsg 		dbuf8[x] = ((pix & 0x00e00000) >> 16) |
2851bb76ff1Sjsg 			   ((pix & 0x0000e000) >> 11) |
2861bb76ff1Sjsg 			   ((pix & 0x000000c0) >> 6);
2871bb76ff1Sjsg 	}
2881bb76ff1Sjsg }
2891bb76ff1Sjsg 
2901bb76ff1Sjsg /**
2911bb76ff1Sjsg  * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer
2921bb76ff1Sjsg  * @dst: Array of RGB332 destination buffers
2931bb76ff1Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
2941bb76ff1Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
2951bb76ff1Sjsg  * @src: Array of XRGB8888 source buffers
2961bb76ff1Sjsg  * @fb: DRM framebuffer
2971bb76ff1Sjsg  * @clip: Clip rectangle area to copy
2981bb76ff1Sjsg  *
2991bb76ff1Sjsg  * This function copies parts of a framebuffer to display memory and converts the
3001bb76ff1Sjsg  * color format during the process. Destination and framebuffer formats must match. The
3011bb76ff1Sjsg  * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
3021bb76ff1Sjsg  * least as many entries as there are planes in @fb's format. Each entry stores the
3031bb76ff1Sjsg  * value for the format's respective color plane at the same index.
3041bb76ff1Sjsg  *
3051bb76ff1Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
3061bb76ff1Sjsg  * top-left corner).
3071bb76ff1Sjsg  *
3081bb76ff1Sjsg  * Drivers can use this function for RGB332 devices that don't support XRGB8888 natively.
3091bb76ff1Sjsg  */
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)3101bb76ff1Sjsg void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
3111bb76ff1Sjsg 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
3121bb76ff1Sjsg 			       const struct drm_rect *clip)
3131bb76ff1Sjsg {
3141bb76ff1Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
3151bb76ff1Sjsg 		1,
3161bb76ff1Sjsg 	};
3171bb76ff1Sjsg 
3181bb76ff1Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
3191bb76ff1Sjsg 		    drm_fb_xrgb8888_to_rgb332_line);
3201bb76ff1Sjsg }
3211bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);
3221bb76ff1Sjsg 
drm_fb_xrgb8888_to_rgb565_line(void * dbuf,const void * sbuf,unsigned int pixels)3231bb76ff1Sjsg static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels)
3241bb76ff1Sjsg {
325*f005ef32Sjsg 	__le16 *dbuf16 = dbuf;
3261bb76ff1Sjsg 	const __le32 *sbuf32 = sbuf;
3271bb76ff1Sjsg 	unsigned int x;
3281bb76ff1Sjsg 	u16 val16;
3291bb76ff1Sjsg 	u32 pix;
3301bb76ff1Sjsg 
3311bb76ff1Sjsg 	for (x = 0; x < pixels; x++) {
3321bb76ff1Sjsg 		pix = le32_to_cpu(sbuf32[x]);
3331bb76ff1Sjsg 		val16 = ((pix & 0x00F80000) >> 8) |
3341bb76ff1Sjsg 			((pix & 0x0000FC00) >> 5) |
3351bb76ff1Sjsg 			((pix & 0x000000F8) >> 3);
336*f005ef32Sjsg 		dbuf16[x] = cpu_to_le16(val16);
3371bb76ff1Sjsg 	}
3381bb76ff1Sjsg }
3391bb76ff1Sjsg 
340*f005ef32Sjsg /* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */
drm_fb_xrgb8888_to_rgb565_swab_line(void * dbuf,const void * sbuf,unsigned int pixels)3411bb76ff1Sjsg static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
3421bb76ff1Sjsg 						unsigned int pixels)
3431bb76ff1Sjsg {
344*f005ef32Sjsg 	__le16 *dbuf16 = dbuf;
3451bb76ff1Sjsg 	const __le32 *sbuf32 = sbuf;
3461bb76ff1Sjsg 	unsigned int x;
3471bb76ff1Sjsg 	u16 val16;
3481bb76ff1Sjsg 	u32 pix;
3491bb76ff1Sjsg 
3501bb76ff1Sjsg 	for (x = 0; x < pixels; x++) {
3511bb76ff1Sjsg 		pix = le32_to_cpu(sbuf32[x]);
3521bb76ff1Sjsg 		val16 = ((pix & 0x00F80000) >> 8) |
3531bb76ff1Sjsg 			((pix & 0x0000FC00) >> 5) |
3541bb76ff1Sjsg 			((pix & 0x000000F8) >> 3);
355*f005ef32Sjsg 		dbuf16[x] = cpu_to_le16(swab16(val16));
356c349dbc7Sjsg 	}
357c349dbc7Sjsg }
358c349dbc7Sjsg 
359c349dbc7Sjsg /**
360c349dbc7Sjsg  * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
3611bb76ff1Sjsg  * @dst: Array of RGB565 destination buffers
3621bb76ff1Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
3631bb76ff1Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
3641bb76ff1Sjsg  * @src: Array of XRGB8888 source buffer
365c349dbc7Sjsg  * @fb: DRM framebuffer
366c349dbc7Sjsg  * @clip: Clip rectangle area to copy
367c349dbc7Sjsg  * @swab: Swap bytes
368c349dbc7Sjsg  *
3691bb76ff1Sjsg  * This function copies parts of a framebuffer to display memory and converts the
3701bb76ff1Sjsg  * color format during the process. Destination and framebuffer formats must match. The
3711bb76ff1Sjsg  * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
3721bb76ff1Sjsg  * least as many entries as there are planes in @fb's format. Each entry stores the
3731bb76ff1Sjsg  * value for the format's respective color plane at the same index.
374c349dbc7Sjsg  *
3751bb76ff1Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
3761bb76ff1Sjsg  * top-left corner).
3771bb76ff1Sjsg  *
3781bb76ff1Sjsg  * Drivers can use this function for RGB565 devices that don't support XRGB8888 natively.
379c349dbc7Sjsg  */
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,bool swab)3801bb76ff1Sjsg void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
3811bb76ff1Sjsg 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
3821bb76ff1Sjsg 			       const struct drm_rect *clip, bool swab)
383c349dbc7Sjsg {
3841bb76ff1Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
3851bb76ff1Sjsg 		2,
3861bb76ff1Sjsg 	};
387c349dbc7Sjsg 
3881bb76ff1Sjsg 	void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels);
389c349dbc7Sjsg 
3901bb76ff1Sjsg 	if (swab)
3911bb76ff1Sjsg 		xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line;
3921bb76ff1Sjsg 	else
3931bb76ff1Sjsg 		xfrm_line = drm_fb_xrgb8888_to_rgb565_line;
394c349dbc7Sjsg 
3951bb76ff1Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm_line);
396c349dbc7Sjsg }
397c349dbc7Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
398c349dbc7Sjsg 
drm_fb_xrgb8888_to_xrgb1555_line(void * dbuf,const void * sbuf,unsigned int pixels)399*f005ef32Sjsg static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
400*f005ef32Sjsg {
401*f005ef32Sjsg 	__le16 *dbuf16 = dbuf;
402*f005ef32Sjsg 	const __le32 *sbuf32 = sbuf;
403*f005ef32Sjsg 	unsigned int x;
404*f005ef32Sjsg 	u16 val16;
405*f005ef32Sjsg 	u32 pix;
406*f005ef32Sjsg 
407*f005ef32Sjsg 	for (x = 0; x < pixels; x++) {
408*f005ef32Sjsg 		pix = le32_to_cpu(sbuf32[x]);
409*f005ef32Sjsg 		val16 = ((pix & 0x00f80000) >> 9) |
410*f005ef32Sjsg 			((pix & 0x0000f800) >> 6) |
411*f005ef32Sjsg 			((pix & 0x000000f8) >> 3);
412*f005ef32Sjsg 		dbuf16[x] = cpu_to_le16(val16);
413*f005ef32Sjsg 	}
414*f005ef32Sjsg }
415*f005ef32Sjsg 
416*f005ef32Sjsg /**
417*f005ef32Sjsg  * drm_fb_xrgb8888_to_xrgb1555 - Convert XRGB8888 to XRGB1555 clip buffer
418*f005ef32Sjsg  * @dst: Array of XRGB1555 destination buffers
419*f005ef32Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
420*f005ef32Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
421*f005ef32Sjsg  * @src: Array of XRGB8888 source buffer
422*f005ef32Sjsg  * @fb: DRM framebuffer
423*f005ef32Sjsg  * @clip: Clip rectangle area to copy
424*f005ef32Sjsg  *
425*f005ef32Sjsg  * This function copies parts of a framebuffer to display memory and converts
426*f005ef32Sjsg  * the color format during the process. The parameters @dst, @dst_pitch and
427*f005ef32Sjsg  * @src refer to arrays. Each array must have at least as many entries as
428*f005ef32Sjsg  * there are planes in @fb's format. Each entry stores the value for the
429*f005ef32Sjsg  * format's respective color plane at the same index.
430*f005ef32Sjsg  *
431*f005ef32Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
432*f005ef32Sjsg  * top-left corner).
433*f005ef32Sjsg  *
434*f005ef32Sjsg  * Drivers can use this function for XRGB1555 devices that don't support
435*f005ef32Sjsg  * XRGB8888 natively.
436*f005ef32Sjsg  */
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)437*f005ef32Sjsg void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
438*f005ef32Sjsg 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
439*f005ef32Sjsg 				 const struct drm_rect *clip)
440*f005ef32Sjsg {
441*f005ef32Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
442*f005ef32Sjsg 		2,
443*f005ef32Sjsg 	};
444*f005ef32Sjsg 
445*f005ef32Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
446*f005ef32Sjsg 		    drm_fb_xrgb8888_to_xrgb1555_line);
447*f005ef32Sjsg }
448*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555);
449*f005ef32Sjsg 
drm_fb_xrgb8888_to_argb1555_line(void * dbuf,const void * sbuf,unsigned int pixels)450*f005ef32Sjsg static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
451*f005ef32Sjsg {
452*f005ef32Sjsg 	__le16 *dbuf16 = dbuf;
453*f005ef32Sjsg 	const __le32 *sbuf32 = sbuf;
454*f005ef32Sjsg 	unsigned int x;
455*f005ef32Sjsg 	u16 val16;
456*f005ef32Sjsg 	u32 pix;
457*f005ef32Sjsg 
458*f005ef32Sjsg 	for (x = 0; x < pixels; x++) {
459*f005ef32Sjsg 		pix = le32_to_cpu(sbuf32[x]);
460*f005ef32Sjsg 		val16 = BIT(15) | /* set alpha bit */
461*f005ef32Sjsg 			((pix & 0x00f80000) >> 9) |
462*f005ef32Sjsg 			((pix & 0x0000f800) >> 6) |
463*f005ef32Sjsg 			((pix & 0x000000f8) >> 3);
464*f005ef32Sjsg 		dbuf16[x] = cpu_to_le16(val16);
465*f005ef32Sjsg 	}
466*f005ef32Sjsg }
467*f005ef32Sjsg 
468*f005ef32Sjsg /**
469*f005ef32Sjsg  * drm_fb_xrgb8888_to_argb1555 - Convert XRGB8888 to ARGB1555 clip buffer
470*f005ef32Sjsg  * @dst: Array of ARGB1555 destination buffers
471*f005ef32Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
472*f005ef32Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
473*f005ef32Sjsg  * @src: Array of XRGB8888 source buffer
474*f005ef32Sjsg  * @fb: DRM framebuffer
475*f005ef32Sjsg  * @clip: Clip rectangle area to copy
476*f005ef32Sjsg  *
477*f005ef32Sjsg  * This function copies parts of a framebuffer to display memory and converts
478*f005ef32Sjsg  * the color format during the process. The parameters @dst, @dst_pitch and
479*f005ef32Sjsg  * @src refer to arrays. Each array must have at least as many entries as
480*f005ef32Sjsg  * there are planes in @fb's format. Each entry stores the value for the
481*f005ef32Sjsg  * format's respective color plane at the same index.
482*f005ef32Sjsg  *
483*f005ef32Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
484*f005ef32Sjsg  * top-left corner).
485*f005ef32Sjsg  *
486*f005ef32Sjsg  * Drivers can use this function for ARGB1555 devices that don't support
487*f005ef32Sjsg  * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
488*f005ef32Sjsg  */
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)489*f005ef32Sjsg void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
490*f005ef32Sjsg 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
491*f005ef32Sjsg 				 const struct drm_rect *clip)
492*f005ef32Sjsg {
493*f005ef32Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
494*f005ef32Sjsg 		2,
495*f005ef32Sjsg 	};
496*f005ef32Sjsg 
497*f005ef32Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
498*f005ef32Sjsg 		    drm_fb_xrgb8888_to_argb1555_line);
499*f005ef32Sjsg }
500*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555);
501*f005ef32Sjsg 
drm_fb_xrgb8888_to_rgba5551_line(void * dbuf,const void * sbuf,unsigned int pixels)502*f005ef32Sjsg static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsigned int pixels)
503*f005ef32Sjsg {
504*f005ef32Sjsg 	__le16 *dbuf16 = dbuf;
505*f005ef32Sjsg 	const __le32 *sbuf32 = sbuf;
506*f005ef32Sjsg 	unsigned int x;
507*f005ef32Sjsg 	u16 val16;
508*f005ef32Sjsg 	u32 pix;
509*f005ef32Sjsg 
510*f005ef32Sjsg 	for (x = 0; x < pixels; x++) {
511*f005ef32Sjsg 		pix = le32_to_cpu(sbuf32[x]);
512*f005ef32Sjsg 		val16 = ((pix & 0x00f80000) >> 8) |
513*f005ef32Sjsg 			((pix & 0x0000f800) >> 5) |
514*f005ef32Sjsg 			((pix & 0x000000f8) >> 2) |
515*f005ef32Sjsg 			BIT(0); /* set alpha bit */
516*f005ef32Sjsg 		dbuf16[x] = cpu_to_le16(val16);
517*f005ef32Sjsg 	}
518*f005ef32Sjsg }
519*f005ef32Sjsg 
520*f005ef32Sjsg /**
521*f005ef32Sjsg  * drm_fb_xrgb8888_to_rgba5551 - Convert XRGB8888 to RGBA5551 clip buffer
522*f005ef32Sjsg  * @dst: Array of RGBA5551 destination buffers
523*f005ef32Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
524*f005ef32Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
525*f005ef32Sjsg  * @src: Array of XRGB8888 source buffer
526*f005ef32Sjsg  * @fb: DRM framebuffer
527*f005ef32Sjsg  * @clip: Clip rectangle area to copy
528*f005ef32Sjsg  *
529*f005ef32Sjsg  * This function copies parts of a framebuffer to display memory and converts
530*f005ef32Sjsg  * the color format during the process. The parameters @dst, @dst_pitch and
531*f005ef32Sjsg  * @src refer to arrays. Each array must have at least as many entries as
532*f005ef32Sjsg  * there are planes in @fb's format. Each entry stores the value for the
533*f005ef32Sjsg  * format's respective color plane at the same index.
534*f005ef32Sjsg  *
535*f005ef32Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
536*f005ef32Sjsg  * top-left corner).
537*f005ef32Sjsg  *
538*f005ef32Sjsg  * Drivers can use this function for RGBA5551 devices that don't support
539*f005ef32Sjsg  * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
540*f005ef32Sjsg  */
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)541*f005ef32Sjsg void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch,
542*f005ef32Sjsg 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
543*f005ef32Sjsg 				 const struct drm_rect *clip)
544*f005ef32Sjsg {
545*f005ef32Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
546*f005ef32Sjsg 		2,
547*f005ef32Sjsg 	};
548*f005ef32Sjsg 
549*f005ef32Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
550*f005ef32Sjsg 		    drm_fb_xrgb8888_to_rgba5551_line);
551*f005ef32Sjsg }
552*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551);
553*f005ef32Sjsg 
drm_fb_xrgb8888_to_rgb888_line(void * dbuf,const void * sbuf,unsigned int pixels)5541bb76ff1Sjsg static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels)
555c349dbc7Sjsg {
5561bb76ff1Sjsg 	u8 *dbuf8 = dbuf;
5571bb76ff1Sjsg 	const __le32 *sbuf32 = sbuf;
558c349dbc7Sjsg 	unsigned int x;
5591bb76ff1Sjsg 	u32 pix;
560c349dbc7Sjsg 
561c349dbc7Sjsg 	for (x = 0; x < pixels; x++) {
5621bb76ff1Sjsg 		pix = le32_to_cpu(sbuf32[x]);
563*f005ef32Sjsg 		/* write blue-green-red to output in little endianness */
5641bb76ff1Sjsg 		*dbuf8++ = (pix & 0x000000FF) >>  0;
5651bb76ff1Sjsg 		*dbuf8++ = (pix & 0x0000FF00) >>  8;
5661bb76ff1Sjsg 		*dbuf8++ = (pix & 0x00FF0000) >> 16;
567c349dbc7Sjsg 	}
568c349dbc7Sjsg }
569c349dbc7Sjsg 
570c349dbc7Sjsg /**
5711bb76ff1Sjsg  * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer
5721bb76ff1Sjsg  * @dst: Array of RGB888 destination buffers
5731bb76ff1Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
5741bb76ff1Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
5751bb76ff1Sjsg  * @src: Array of XRGB8888 source buffers
576c349dbc7Sjsg  * @fb: DRM framebuffer
577c349dbc7Sjsg  * @clip: Clip rectangle area to copy
578c349dbc7Sjsg  *
5791bb76ff1Sjsg  * This function copies parts of a framebuffer to display memory and converts the
5801bb76ff1Sjsg  * color format during the process. Destination and framebuffer formats must match. The
5811bb76ff1Sjsg  * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
5821bb76ff1Sjsg  * least as many entries as there are planes in @fb's format. Each entry stores the
5831bb76ff1Sjsg  * value for the format's respective color plane at the same index.
5841bb76ff1Sjsg  *
5851bb76ff1Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
5861bb76ff1Sjsg  * top-left corner).
5871bb76ff1Sjsg  *
588c349dbc7Sjsg  * Drivers can use this function for RGB888 devices that don't natively
589c349dbc7Sjsg  * support XRGB8888.
590c349dbc7Sjsg  */
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)5911bb76ff1Sjsg void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch,
5921bb76ff1Sjsg 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
5931bb76ff1Sjsg 			       const struct drm_rect *clip)
594c349dbc7Sjsg {
5951bb76ff1Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
5961bb76ff1Sjsg 		3,
5971bb76ff1Sjsg 	};
598c349dbc7Sjsg 
5991bb76ff1Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
6001bb76ff1Sjsg 		    drm_fb_xrgb8888_to_rgb888_line);
6011bb76ff1Sjsg }
6021bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
603c349dbc7Sjsg 
drm_fb_xrgb8888_to_argb8888_line(void * dbuf,const void * sbuf,unsigned int pixels)604*f005ef32Sjsg static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
6051bb76ff1Sjsg {
6061bb76ff1Sjsg 	__le32 *dbuf32 = dbuf;
607*f005ef32Sjsg 	const __le32 *sbuf32 = sbuf;
6081bb76ff1Sjsg 	unsigned int x;
609*f005ef32Sjsg 	u32 pix;
6101bb76ff1Sjsg 
6111bb76ff1Sjsg 	for (x = 0; x < pixels; x++) {
612*f005ef32Sjsg 		pix = le32_to_cpu(sbuf32[x]);
613*f005ef32Sjsg 		pix |= GENMASK(31, 24); /* fill alpha bits */
6141bb76ff1Sjsg 		dbuf32[x] = cpu_to_le32(pix);
6151bb76ff1Sjsg 	}
6161bb76ff1Sjsg }
6171bb76ff1Sjsg 
618*f005ef32Sjsg /**
619*f005ef32Sjsg  * drm_fb_xrgb8888_to_argb8888 - Convert XRGB8888 to ARGB8888 clip buffer
620*f005ef32Sjsg  * @dst: Array of ARGB8888 destination buffers
621*f005ef32Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
622*f005ef32Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
623*f005ef32Sjsg  * @src: Array of XRGB8888 source buffer
624*f005ef32Sjsg  * @fb: DRM framebuffer
625*f005ef32Sjsg  * @clip: Clip rectangle area to copy
626*f005ef32Sjsg  *
627*f005ef32Sjsg  * This function copies parts of a framebuffer to display memory and converts the
628*f005ef32Sjsg  * color format during the process. The parameters @dst, @dst_pitch and @src refer
629*f005ef32Sjsg  * to arrays. Each array must have at least as many entries as there are planes in
630*f005ef32Sjsg  * @fb's format. Each entry stores the value for the format's respective color plane
631*f005ef32Sjsg  * at the same index.
632*f005ef32Sjsg  *
633*f005ef32Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
634*f005ef32Sjsg  * top-left corner).
635*f005ef32Sjsg  *
636*f005ef32Sjsg  * Drivers can use this function for ARGB8888 devices that don't support XRGB8888
637*f005ef32Sjsg  * natively. It sets an opaque alpha channel as part of the conversion.
638*f005ef32Sjsg  */
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)639*f005ef32Sjsg void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
640*f005ef32Sjsg 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
641*f005ef32Sjsg 				 const struct drm_rect *clip)
642*f005ef32Sjsg {
643*f005ef32Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
644*f005ef32Sjsg 		4,
645*f005ef32Sjsg 	};
646*f005ef32Sjsg 
647*f005ef32Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
648*f005ef32Sjsg 		    drm_fb_xrgb8888_to_argb8888_line);
649*f005ef32Sjsg }
650*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888);
651*f005ef32Sjsg 
drm_fb_xrgb8888_to_abgr8888_line(void * dbuf,const void * sbuf,unsigned int pixels)652*f005ef32Sjsg static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
653*f005ef32Sjsg {
654*f005ef32Sjsg 	__le32 *dbuf32 = dbuf;
655*f005ef32Sjsg 	const __le32 *sbuf32 = sbuf;
656*f005ef32Sjsg 	unsigned int x;
657*f005ef32Sjsg 	u32 pix;
658*f005ef32Sjsg 
659*f005ef32Sjsg 	for (x = 0; x < pixels; x++) {
660*f005ef32Sjsg 		pix = le32_to_cpu(sbuf32[x]);
661*f005ef32Sjsg 		pix = ((pix & 0x00ff0000) >> 16) <<  0 |
662*f005ef32Sjsg 		      ((pix & 0x0000ff00) >>  8) <<  8 |
663*f005ef32Sjsg 		      ((pix & 0x000000ff) >>  0) << 16 |
664*f005ef32Sjsg 		      GENMASK(31, 24); /* fill alpha bits */
665*f005ef32Sjsg 		*dbuf32++ = cpu_to_le32(pix);
666*f005ef32Sjsg 	}
667*f005ef32Sjsg }
668*f005ef32Sjsg 
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)669*f005ef32Sjsg static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
6701bb76ff1Sjsg 					const struct iosys_map *src,
6711bb76ff1Sjsg 					const struct drm_framebuffer *fb,
6721bb76ff1Sjsg 					const struct drm_rect *clip)
6731bb76ff1Sjsg {
6741bb76ff1Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
6751bb76ff1Sjsg 		4,
6761bb76ff1Sjsg 	};
6771bb76ff1Sjsg 
6781bb76ff1Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
679*f005ef32Sjsg 		    drm_fb_xrgb8888_to_abgr8888_line);
680*f005ef32Sjsg }
681*f005ef32Sjsg 
drm_fb_xrgb8888_to_xbgr8888_line(void * dbuf,const void * sbuf,unsigned int pixels)682*f005ef32Sjsg static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
683*f005ef32Sjsg {
684*f005ef32Sjsg 	__le32 *dbuf32 = dbuf;
685*f005ef32Sjsg 	const __le32 *sbuf32 = sbuf;
686*f005ef32Sjsg 	unsigned int x;
687*f005ef32Sjsg 	u32 pix;
688*f005ef32Sjsg 
689*f005ef32Sjsg 	for (x = 0; x < pixels; x++) {
690*f005ef32Sjsg 		pix = le32_to_cpu(sbuf32[x]);
691*f005ef32Sjsg 		pix = ((pix & 0x00ff0000) >> 16) <<  0 |
692*f005ef32Sjsg 		      ((pix & 0x0000ff00) >>  8) <<  8 |
693*f005ef32Sjsg 		      ((pix & 0x000000ff) >>  0) << 16 |
694*f005ef32Sjsg 		      ((pix & 0xff000000) >> 24) << 24;
695*f005ef32Sjsg 		*dbuf32++ = cpu_to_le32(pix);
696*f005ef32Sjsg 	}
697*f005ef32Sjsg }
698*f005ef32Sjsg 
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)699*f005ef32Sjsg static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
700*f005ef32Sjsg 					const struct iosys_map *src,
701*f005ef32Sjsg 					const struct drm_framebuffer *fb,
702*f005ef32Sjsg 					const struct drm_rect *clip)
703*f005ef32Sjsg {
704*f005ef32Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
705*f005ef32Sjsg 		4,
706*f005ef32Sjsg 	};
707*f005ef32Sjsg 
708*f005ef32Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
709*f005ef32Sjsg 		    drm_fb_xrgb8888_to_xbgr8888_line);
7101bb76ff1Sjsg }
7111bb76ff1Sjsg 
drm_fb_xrgb8888_to_xrgb2101010_line(void * dbuf,const void * sbuf,unsigned int pixels)7121bb76ff1Sjsg static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
7131bb76ff1Sjsg {
7141bb76ff1Sjsg 	__le32 *dbuf32 = dbuf;
7151bb76ff1Sjsg 	const __le32 *sbuf32 = sbuf;
7161bb76ff1Sjsg 	unsigned int x;
7171bb76ff1Sjsg 	u32 val32;
7181bb76ff1Sjsg 	u32 pix;
7191bb76ff1Sjsg 
7201bb76ff1Sjsg 	for (x = 0; x < pixels; x++) {
7211bb76ff1Sjsg 		pix = le32_to_cpu(sbuf32[x]);
7221bb76ff1Sjsg 		val32 = ((pix & 0x000000FF) << 2) |
7231bb76ff1Sjsg 			((pix & 0x0000FF00) << 4) |
7241bb76ff1Sjsg 			((pix & 0x00FF0000) << 6);
7251bb76ff1Sjsg 		pix = val32 | ((val32 >> 8) & 0x00300C03);
7261bb76ff1Sjsg 		*dbuf32++ = cpu_to_le32(pix);
7271bb76ff1Sjsg 	}
7281bb76ff1Sjsg }
729c349dbc7Sjsg 
730c349dbc7Sjsg /**
7311bb76ff1Sjsg  * drm_fb_xrgb8888_to_xrgb2101010 - Convert XRGB8888 to XRGB2101010 clip buffer
7321bb76ff1Sjsg  * @dst: Array of XRGB2101010 destination buffers
7331bb76ff1Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
7341bb76ff1Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
7351bb76ff1Sjsg  * @src: Array of XRGB8888 source buffers
736c349dbc7Sjsg  * @fb: DRM framebuffer
737c349dbc7Sjsg  * @clip: Clip rectangle area to copy
738c349dbc7Sjsg  *
7391bb76ff1Sjsg  * This function copies parts of a framebuffer to display memory and converts the
7401bb76ff1Sjsg  * color format during the process. Destination and framebuffer formats must match. The
7411bb76ff1Sjsg  * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
7421bb76ff1Sjsg  * least as many entries as there are planes in @fb's format. Each entry stores the
7431bb76ff1Sjsg  * value for the format's respective color plane at the same index.
744c349dbc7Sjsg  *
7451bb76ff1Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
7461bb76ff1Sjsg  * top-left corner).
747c349dbc7Sjsg  *
7481bb76ff1Sjsg  * Drivers can use this function for XRGB2101010 devices that don't support XRGB8888
7491bb76ff1Sjsg  * natively.
750c349dbc7Sjsg  */
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)7511bb76ff1Sjsg void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
7521bb76ff1Sjsg 				    const struct iosys_map *src, const struct drm_framebuffer *fb,
7531bb76ff1Sjsg 				    const struct drm_rect *clip)
754c349dbc7Sjsg {
7551bb76ff1Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
7561bb76ff1Sjsg 		4,
7571bb76ff1Sjsg 	};
758c349dbc7Sjsg 
7591bb76ff1Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
7601bb76ff1Sjsg 		    drm_fb_xrgb8888_to_xrgb2101010_line);
7611bb76ff1Sjsg }
7621bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010);
763c349dbc7Sjsg 
drm_fb_xrgb8888_to_argb2101010_line(void * dbuf,const void * sbuf,unsigned int pixels)764*f005ef32Sjsg static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
765*f005ef32Sjsg {
766*f005ef32Sjsg 	__le32 *dbuf32 = dbuf;
767*f005ef32Sjsg 	const __le32 *sbuf32 = sbuf;
768*f005ef32Sjsg 	unsigned int x;
769*f005ef32Sjsg 	u32 val32;
770*f005ef32Sjsg 	u32 pix;
771*f005ef32Sjsg 
772*f005ef32Sjsg 	for (x = 0; x < pixels; x++) {
773*f005ef32Sjsg 		pix = le32_to_cpu(sbuf32[x]);
774*f005ef32Sjsg 		val32 = ((pix & 0x000000ff) << 2) |
775*f005ef32Sjsg 			((pix & 0x0000ff00) << 4) |
776*f005ef32Sjsg 			((pix & 0x00ff0000) << 6);
777*f005ef32Sjsg 		pix = GENMASK(31, 30) | /* set alpha bits */
778*f005ef32Sjsg 		      val32 | ((val32 >> 8) & 0x00300c03);
779*f005ef32Sjsg 		*dbuf32++ = cpu_to_le32(pix);
780*f005ef32Sjsg 	}
781*f005ef32Sjsg }
782*f005ef32Sjsg 
783*f005ef32Sjsg /**
784*f005ef32Sjsg  * drm_fb_xrgb8888_to_argb2101010 - Convert XRGB8888 to ARGB2101010 clip buffer
785*f005ef32Sjsg  * @dst: Array of ARGB2101010 destination buffers
786*f005ef32Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
787*f005ef32Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
788*f005ef32Sjsg  * @src: Array of XRGB8888 source buffers
789*f005ef32Sjsg  * @fb: DRM framebuffer
790*f005ef32Sjsg  * @clip: Clip rectangle area to copy
791*f005ef32Sjsg  *
792*f005ef32Sjsg  * This function copies parts of a framebuffer to display memory and converts
793*f005ef32Sjsg  * the color format during the process. The parameters @dst, @dst_pitch and
794*f005ef32Sjsg  * @src refer to arrays. Each array must have at least as many entries as
795*f005ef32Sjsg  * there are planes in @fb's format. Each entry stores the value for the
796*f005ef32Sjsg  * format's respective color plane at the same index.
797*f005ef32Sjsg  *
798*f005ef32Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
799*f005ef32Sjsg  * top-left corner).
800*f005ef32Sjsg  *
801*f005ef32Sjsg  * Drivers can use this function for ARGB2101010 devices that don't support XRGB8888
802*f005ef32Sjsg  * natively.
803*f005ef32Sjsg  */
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)804*f005ef32Sjsg void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
805*f005ef32Sjsg 				    const struct iosys_map *src, const struct drm_framebuffer *fb,
806*f005ef32Sjsg 				    const struct drm_rect *clip)
807*f005ef32Sjsg {
808*f005ef32Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
809*f005ef32Sjsg 		4,
810*f005ef32Sjsg 	};
811*f005ef32Sjsg 
812*f005ef32Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
813*f005ef32Sjsg 		    drm_fb_xrgb8888_to_argb2101010_line);
814*f005ef32Sjsg }
815*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010);
816*f005ef32Sjsg 
drm_fb_xrgb8888_to_gray8_line(void * dbuf,const void * sbuf,unsigned int pixels)8171bb76ff1Sjsg static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels)
8181bb76ff1Sjsg {
8191bb76ff1Sjsg 	u8 *dbuf8 = dbuf;
8201bb76ff1Sjsg 	const __le32 *sbuf32 = sbuf;
8211bb76ff1Sjsg 	unsigned int x;
8221bb76ff1Sjsg 
8231bb76ff1Sjsg 	for (x = 0; x < pixels; x++) {
8241bb76ff1Sjsg 		u32 pix = le32_to_cpu(sbuf32[x]);
8251bb76ff1Sjsg 		u8 r = (pix & 0x00ff0000) >> 16;
8261bb76ff1Sjsg 		u8 g = (pix & 0x0000ff00) >> 8;
8271bb76ff1Sjsg 		u8 b =  pix & 0x000000ff;
828c349dbc7Sjsg 
829c349dbc7Sjsg 		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
8301bb76ff1Sjsg 		*dbuf8++ = (3 * r + 6 * g + b) / 10;
831c349dbc7Sjsg 	}
832c349dbc7Sjsg }
833c349dbc7Sjsg 
8341bb76ff1Sjsg /**
8351bb76ff1Sjsg  * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
8361bb76ff1Sjsg  * @dst: Array of 8-bit grayscale destination buffers
8371bb76ff1Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
8381bb76ff1Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
8391bb76ff1Sjsg  * @src: Array of XRGB8888 source buffers
8401bb76ff1Sjsg  * @fb: DRM framebuffer
8411bb76ff1Sjsg  * @clip: Clip rectangle area to copy
8421bb76ff1Sjsg  *
8431bb76ff1Sjsg  * This function copies parts of a framebuffer to display memory and converts the
8441bb76ff1Sjsg  * color format during the process. Destination and framebuffer formats must match. The
8451bb76ff1Sjsg  * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
8461bb76ff1Sjsg  * least as many entries as there are planes in @fb's format. Each entry stores the
8471bb76ff1Sjsg  * value for the format's respective color plane at the same index.
8481bb76ff1Sjsg  *
8491bb76ff1Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
8501bb76ff1Sjsg  * top-left corner).
8511bb76ff1Sjsg  *
8521bb76ff1Sjsg  * DRM doesn't have native monochrome or grayscale support. Drivers can use this
8531bb76ff1Sjsg  * function for grayscale devices that don't support XRGB8888 natively.Such
8541bb76ff1Sjsg  * drivers can announce the commonly supported XR24 format to userspace and use
8551bb76ff1Sjsg  * this function to convert to the native format. Monochrome drivers will use the
8561bb76ff1Sjsg  * most significant bit, where 1 means foreground color and 0 background color.
8571bb76ff1Sjsg  * ITU BT.601 is being used for the RGB -> luma (brightness) conversion.
8581bb76ff1Sjsg  */
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)8591bb76ff1Sjsg void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch,
8601bb76ff1Sjsg 			      const struct iosys_map *src, const struct drm_framebuffer *fb,
8611bb76ff1Sjsg 			      const struct drm_rect *clip)
8621bb76ff1Sjsg {
8631bb76ff1Sjsg 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
8641bb76ff1Sjsg 		1,
8651bb76ff1Sjsg 	};
8661bb76ff1Sjsg 
8671bb76ff1Sjsg 	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
8681bb76ff1Sjsg 		    drm_fb_xrgb8888_to_gray8_line);
869c349dbc7Sjsg }
870c349dbc7Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
871c349dbc7Sjsg 
8725ca02815Sjsg /**
8731bb76ff1Sjsg  * drm_fb_blit - Copy parts of a framebuffer to display memory
8741bb76ff1Sjsg  * @dst:	Array of display-memory addresses to copy to
8751bb76ff1Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
8761bb76ff1Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
8775ca02815Sjsg  * @dst_format:	FOURCC code of the display's color format
8781bb76ff1Sjsg  * @src:	The framebuffer memory to copy from
8795ca02815Sjsg  * @fb:		The framebuffer to copy from
8805ca02815Sjsg  * @clip:	Clip rectangle area to copy
8815ca02815Sjsg  *
8825ca02815Sjsg  * This function copies parts of a framebuffer to display memory. If the
8835ca02815Sjsg  * formats of the display and the framebuffer mismatch, the blit function
8841bb76ff1Sjsg  * will attempt to convert between them during the process. The parameters @dst,
8851bb76ff1Sjsg  * @dst_pitch and @src refer to arrays. Each array must have at least as many
8861bb76ff1Sjsg  * entries as there are planes in @dst_format's format. Each entry stores the
8871bb76ff1Sjsg  * value for the format's respective color plane at the same index.
8885ca02815Sjsg  *
8891bb76ff1Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
8901bb76ff1Sjsg  * top-left corner).
8915ca02815Sjsg  *
8925ca02815Sjsg  * Returns:
8935ca02815Sjsg  * 0 on success, or
8945ca02815Sjsg  * -EINVAL if the color-format conversion failed, or
8955ca02815Sjsg  * a negative error code otherwise.
8965ca02815Sjsg  */
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)8971bb76ff1Sjsg int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format,
8981bb76ff1Sjsg 		const struct iosys_map *src, const struct drm_framebuffer *fb,
8991bb76ff1Sjsg 		const struct drm_rect *clip)
9005ca02815Sjsg {
9015ca02815Sjsg 	uint32_t fb_format = fb->format->format;
9025ca02815Sjsg 
903*f005ef32Sjsg 	if (fb_format == dst_format) {
9041bb76ff1Sjsg 		drm_fb_memcpy(dst, dst_pitch, src, fb, clip);
9055ca02815Sjsg 		return 0;
906*f005ef32Sjsg 	} else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) {
907*f005ef32Sjsg 		drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
908*f005ef32Sjsg 		return 0;
909*f005ef32Sjsg 	} else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) {
910*f005ef32Sjsg 		drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
911*f005ef32Sjsg 		return 0;
912*f005ef32Sjsg 	} else if (fb_format == DRM_FORMAT_XRGB8888) {
913*f005ef32Sjsg 		if (dst_format == DRM_FORMAT_RGB565) {
9141bb76ff1Sjsg 			drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false);
9155ca02815Sjsg 			return 0;
916*f005ef32Sjsg 		} else if (dst_format == DRM_FORMAT_XRGB1555) {
917*f005ef32Sjsg 			drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip);
918*f005ef32Sjsg 			return 0;
919*f005ef32Sjsg 		} else if (dst_format == DRM_FORMAT_ARGB1555) {
920*f005ef32Sjsg 			drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip);
921*f005ef32Sjsg 			return 0;
922*f005ef32Sjsg 		} else if (dst_format == DRM_FORMAT_RGBA5551) {
923*f005ef32Sjsg 			drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip);
924*f005ef32Sjsg 			return 0;
9255ca02815Sjsg 		} else if (dst_format == DRM_FORMAT_RGB888) {
9261bb76ff1Sjsg 			drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip);
9271bb76ff1Sjsg 			return 0;
928*f005ef32Sjsg 		} else if (dst_format == DRM_FORMAT_ARGB8888) {
929*f005ef32Sjsg 			drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip);
9301bb76ff1Sjsg 			return 0;
931*f005ef32Sjsg 		} else if (dst_format == DRM_FORMAT_XBGR8888) {
932*f005ef32Sjsg 			drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip);
9331bb76ff1Sjsg 			return 0;
934*f005ef32Sjsg 		} else if (dst_format == DRM_FORMAT_ABGR8888) {
935*f005ef32Sjsg 			drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip);
936*f005ef32Sjsg 			return 0;
9371bb76ff1Sjsg 		} else if (dst_format == DRM_FORMAT_XRGB2101010) {
9381bb76ff1Sjsg 			drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip);
9395ca02815Sjsg 			return 0;
940*f005ef32Sjsg 		} else if (dst_format == DRM_FORMAT_ARGB2101010) {
941*f005ef32Sjsg 			drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip);
942*f005ef32Sjsg 			return 0;
943*f005ef32Sjsg 		} else if (dst_format == DRM_FORMAT_BGRX8888) {
944*f005ef32Sjsg 			drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
945*f005ef32Sjsg 			return 0;
9465ca02815Sjsg 		}
9475ca02815Sjsg 	}
9485ca02815Sjsg 
9491bb76ff1Sjsg 	drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n",
9501bb76ff1Sjsg 		      &fb_format, &dst_format);
9511bb76ff1Sjsg 
9525ca02815Sjsg 	return -EINVAL;
9535ca02815Sjsg }
9541bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_blit);
9551bb76ff1Sjsg 
drm_fb_gray8_to_mono_line(void * dbuf,const void * sbuf,unsigned int pixels)9561bb76ff1Sjsg static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int pixels)
9571bb76ff1Sjsg {
9581bb76ff1Sjsg 	u8 *dbuf8 = dbuf;
9591bb76ff1Sjsg 	const u8 *sbuf8 = sbuf;
9601bb76ff1Sjsg 
9611bb76ff1Sjsg 	while (pixels) {
9621bb76ff1Sjsg 		unsigned int i, bits = min(pixels, 8U);
9631bb76ff1Sjsg 		u8 byte = 0;
9641bb76ff1Sjsg 
9651bb76ff1Sjsg 		for (i = 0; i < bits; i++, pixels--) {
9661bb76ff1Sjsg 			if (*sbuf8++ >= 128)
9671bb76ff1Sjsg 				byte |= BIT(i);
9681bb76ff1Sjsg 		}
9691bb76ff1Sjsg 		*dbuf8++ = byte;
9701bb76ff1Sjsg 	}
9711bb76ff1Sjsg }
9725ca02815Sjsg 
9735ca02815Sjsg /**
9741bb76ff1Sjsg  * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome
9751bb76ff1Sjsg  * @dst: Array of monochrome destination buffers (0=black, 1=white)
9761bb76ff1Sjsg  * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
9771bb76ff1Sjsg  *             within @dst; can be NULL if scanlines are stored next to each other.
9781bb76ff1Sjsg  * @src: Array of XRGB8888 source buffers
9791bb76ff1Sjsg  * @fb: DRM framebuffer
9801bb76ff1Sjsg  * @clip: Clip rectangle area to copy
9815ca02815Sjsg  *
9821bb76ff1Sjsg  * This function copies parts of a framebuffer to display memory and converts the
9831bb76ff1Sjsg  * color format during the process. Destination and framebuffer formats must match. The
9841bb76ff1Sjsg  * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
9851bb76ff1Sjsg  * least as many entries as there are planes in @fb's format. Each entry stores the
9861bb76ff1Sjsg  * value for the format's respective color plane at the same index.
9875ca02815Sjsg  *
9881bb76ff1Sjsg  * This function does not apply clipping on @dst (i.e. the destination is at the
9891bb76ff1Sjsg  * top-left corner). The first pixel (upper left corner of the clip rectangle) will
9901bb76ff1Sjsg  * be converted and copied to the first bit (LSB) in the first byte of the monochrome
9911bb76ff1Sjsg  * destination buffer. If the caller requires that the first pixel in a byte must
9921bb76ff1Sjsg  * be located at an x-coordinate that is a multiple of 8, then the caller must take
9931bb76ff1Sjsg  * care itself of supplying a suitable clip rectangle.
9941bb76ff1Sjsg  *
9951bb76ff1Sjsg  * DRM doesn't have native monochrome support. Drivers can use this function for
9961bb76ff1Sjsg  * monochrome devices that don't support XRGB8888 natively. Such drivers can
9971bb76ff1Sjsg  * announce the commonly supported XR24 format to userspace and use this function
9981bb76ff1Sjsg  * to convert to the native format.
9991bb76ff1Sjsg  *
10001bb76ff1Sjsg  * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and
10011bb76ff1Sjsg  * then the result is converted from grayscale to monochrome.
10021bb76ff1Sjsg  */
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)10031bb76ff1Sjsg void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch,
10041bb76ff1Sjsg 			     const struct iosys_map *src, const struct drm_framebuffer *fb,
10051bb76ff1Sjsg 			     const struct drm_rect *clip)
10061bb76ff1Sjsg {
10071bb76ff1Sjsg 	static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
10081bb76ff1Sjsg 		0, 0, 0, 0
10091bb76ff1Sjsg 	};
10101bb76ff1Sjsg 	unsigned int linepixels = drm_rect_width(clip);
10111bb76ff1Sjsg 	unsigned int lines = drm_rect_height(clip);
10121bb76ff1Sjsg 	unsigned int cpp = fb->format->cpp[0];
10131bb76ff1Sjsg 	unsigned int len_src32 = linepixels * cpp;
10141bb76ff1Sjsg 	struct drm_device *dev = fb->dev;
10151bb76ff1Sjsg 	void *vaddr = src[0].vaddr;
10161bb76ff1Sjsg 	unsigned int dst_pitch_0;
10171bb76ff1Sjsg 	unsigned int y;
10181bb76ff1Sjsg 	u8 *mono = dst[0].vaddr, *gray8;
10191bb76ff1Sjsg 	u32 *src32;
10201bb76ff1Sjsg 
10211bb76ff1Sjsg 	if (drm_WARN_ON(dev, fb->format->format != DRM_FORMAT_XRGB8888))
10221bb76ff1Sjsg 		return;
10231bb76ff1Sjsg 
10241bb76ff1Sjsg 	if (!dst_pitch)
10251bb76ff1Sjsg 		dst_pitch = default_dst_pitch;
10261bb76ff1Sjsg 	dst_pitch_0 = dst_pitch[0];
10271bb76ff1Sjsg 
10281bb76ff1Sjsg 	/*
10291bb76ff1Sjsg 	 * The mono destination buffer contains 1 bit per pixel
10301bb76ff1Sjsg 	 */
10311bb76ff1Sjsg 	if (!dst_pitch_0)
10321bb76ff1Sjsg 		dst_pitch_0 = DIV_ROUND_UP(linepixels, 8);
10331bb76ff1Sjsg 
10341bb76ff1Sjsg 	/*
10351bb76ff1Sjsg 	 * The dma memory is write-combined so reads are uncached.
10361bb76ff1Sjsg 	 * Speed up by fetching one line at a time.
10371bb76ff1Sjsg 	 *
10381bb76ff1Sjsg 	 * Also, format conversion from XR24 to monochrome are done
10391bb76ff1Sjsg 	 * line-by-line but are converted to 8-bit grayscale as an
10401bb76ff1Sjsg 	 * intermediate step.
10411bb76ff1Sjsg 	 *
10421bb76ff1Sjsg 	 * Allocate a buffer to be used for both copying from the cma
10431bb76ff1Sjsg 	 * memory and to store the intermediate grayscale line pixels.
10441bb76ff1Sjsg 	 */
10451bb76ff1Sjsg 	src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);
10461bb76ff1Sjsg 	if (!src32)
10471bb76ff1Sjsg 		return;
10481bb76ff1Sjsg 
10491bb76ff1Sjsg 	gray8 = (u8 *)src32 + len_src32;
10501bb76ff1Sjsg 
10511bb76ff1Sjsg 	vaddr += clip_offset(clip, fb->pitches[0], cpp);
10521bb76ff1Sjsg 	for (y = 0; y < lines; y++) {
10531bb76ff1Sjsg 		src32 = memcpy(src32, vaddr, len_src32);
10541bb76ff1Sjsg 		drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels);
10551bb76ff1Sjsg 		drm_fb_gray8_to_mono_line(mono, gray8, linepixels);
10561bb76ff1Sjsg 		vaddr += fb->pitches[0];
10571bb76ff1Sjsg 		mono += dst_pitch_0;
10581bb76ff1Sjsg 	}
10591bb76ff1Sjsg 
10601bb76ff1Sjsg 	kfree(src32);
10611bb76ff1Sjsg }
10621bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
10631bb76ff1Sjsg 
drm_fb_nonalpha_fourcc(uint32_t fourcc)1064*f005ef32Sjsg static uint32_t drm_fb_nonalpha_fourcc(uint32_t fourcc)
1065*f005ef32Sjsg {
1066*f005ef32Sjsg 	/* only handle formats with depth != 0 and alpha channel */
1067*f005ef32Sjsg 	switch (fourcc) {
1068*f005ef32Sjsg 	case DRM_FORMAT_ARGB1555:
1069*f005ef32Sjsg 		return DRM_FORMAT_XRGB1555;
1070*f005ef32Sjsg 	case DRM_FORMAT_ABGR1555:
1071*f005ef32Sjsg 		return DRM_FORMAT_XBGR1555;
1072*f005ef32Sjsg 	case DRM_FORMAT_RGBA5551:
1073*f005ef32Sjsg 		return DRM_FORMAT_RGBX5551;
1074*f005ef32Sjsg 	case DRM_FORMAT_BGRA5551:
1075*f005ef32Sjsg 		return DRM_FORMAT_BGRX5551;
1076*f005ef32Sjsg 	case DRM_FORMAT_ARGB8888:
1077*f005ef32Sjsg 		return DRM_FORMAT_XRGB8888;
1078*f005ef32Sjsg 	case DRM_FORMAT_ABGR8888:
1079*f005ef32Sjsg 		return DRM_FORMAT_XBGR8888;
1080*f005ef32Sjsg 	case DRM_FORMAT_RGBA8888:
1081*f005ef32Sjsg 		return DRM_FORMAT_RGBX8888;
1082*f005ef32Sjsg 	case DRM_FORMAT_BGRA8888:
1083*f005ef32Sjsg 		return DRM_FORMAT_BGRX8888;
1084*f005ef32Sjsg 	case DRM_FORMAT_ARGB2101010:
1085*f005ef32Sjsg 		return DRM_FORMAT_XRGB2101010;
1086*f005ef32Sjsg 	case DRM_FORMAT_ABGR2101010:
1087*f005ef32Sjsg 		return DRM_FORMAT_XBGR2101010;
1088*f005ef32Sjsg 	case DRM_FORMAT_RGBA1010102:
1089*f005ef32Sjsg 		return DRM_FORMAT_RGBX1010102;
1090*f005ef32Sjsg 	case DRM_FORMAT_BGRA1010102:
1091*f005ef32Sjsg 		return DRM_FORMAT_BGRX1010102;
1092*f005ef32Sjsg 	}
1093*f005ef32Sjsg 
1094*f005ef32Sjsg 	return fourcc;
1095*f005ef32Sjsg }
1096*f005ef32Sjsg 
is_listed_fourcc(const uint32_t * fourccs,size_t nfourccs,uint32_t fourcc)10971bb76ff1Sjsg static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc)
10981bb76ff1Sjsg {
10991bb76ff1Sjsg 	const uint32_t *fourccs_end = fourccs + nfourccs;
11001bb76ff1Sjsg 
11011bb76ff1Sjsg 	while (fourccs < fourccs_end) {
11021bb76ff1Sjsg 		if (*fourccs == fourcc)
11031bb76ff1Sjsg 			return true;
11041bb76ff1Sjsg 		++fourccs;
11051bb76ff1Sjsg 	}
11061bb76ff1Sjsg 	return false;
11071bb76ff1Sjsg }
11081bb76ff1Sjsg 
11091bb76ff1Sjsg /**
11101bb76ff1Sjsg  * drm_fb_build_fourcc_list - Filters a list of supported color formats against
11111bb76ff1Sjsg  *                            the device's native formats
11121bb76ff1Sjsg  * @dev: DRM device
11131bb76ff1Sjsg  * @native_fourccs: 4CC codes of natively supported color formats
11141bb76ff1Sjsg  * @native_nfourccs: The number of entries in @native_fourccs
11151bb76ff1Sjsg  * @fourccs_out: Returns 4CC codes of supported color formats
11161bb76ff1Sjsg  * @nfourccs_out: The number of available entries in @fourccs_out
11171bb76ff1Sjsg  *
11181bb76ff1Sjsg  * This function create a list of supported color format from natively
1119*f005ef32Sjsg  * supported formats and additional emulated formats.
11201bb76ff1Sjsg  * At a minimum, most userspace programs expect at least support for
11211bb76ff1Sjsg  * XRGB8888 on the primary plane. Devices that have to emulate the
11221bb76ff1Sjsg  * format, and possibly others, can use drm_fb_build_fourcc_list() to
11231bb76ff1Sjsg  * create a list of supported color formats. The returned list can
11241bb76ff1Sjsg  * be handed over to drm_universal_plane_init() et al. Native formats
1125*f005ef32Sjsg  * will go before emulated formats. Native formats with alpha channel
1126*f005ef32Sjsg  * will be replaced by such without, as primary planes usually don't
1127*f005ef32Sjsg  * support alpha. Other heuristics might be applied
11281bb76ff1Sjsg  * to optimize the order. Formats near the beginning of the list are
1129*f005ef32Sjsg  * usually preferred over formats near the end of the list.
11305ca02815Sjsg  *
11315ca02815Sjsg  * Returns:
11321bb76ff1Sjsg  * The number of color-formats 4CC codes returned in @fourccs_out.
11335ca02815Sjsg  */
drm_fb_build_fourcc_list(struct drm_device * dev,const u32 * native_fourccs,size_t native_nfourccs,u32 * fourccs_out,size_t nfourccs_out)11341bb76ff1Sjsg size_t drm_fb_build_fourcc_list(struct drm_device *dev,
11351bb76ff1Sjsg 				const u32 *native_fourccs, size_t native_nfourccs,
11361bb76ff1Sjsg 				u32 *fourccs_out, size_t nfourccs_out)
11375ca02815Sjsg {
1138*f005ef32Sjsg 	/*
1139*f005ef32Sjsg 	 * XRGB8888 is the default fallback format for most of userspace
1140*f005ef32Sjsg 	 * and it's currently the only format that should be emulated for
1141*f005ef32Sjsg 	 * the primary plane. Only if there's ever another default fallback,
1142*f005ef32Sjsg 	 * it should be added here.
1143*f005ef32Sjsg 	 */
1144*f005ef32Sjsg 	static const uint32_t extra_fourccs[] = {
1145*f005ef32Sjsg 		DRM_FORMAT_XRGB8888,
1146*f005ef32Sjsg 	};
1147*f005ef32Sjsg 	static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs);
1148*f005ef32Sjsg 
11491bb76ff1Sjsg 	u32 *fourccs = fourccs_out;
11501bb76ff1Sjsg 	const u32 *fourccs_end = fourccs_out + nfourccs_out;
11511bb76ff1Sjsg 	size_t i;
11521bb76ff1Sjsg 
11531bb76ff1Sjsg 	/*
11541bb76ff1Sjsg 	 * The device's native formats go first.
11551bb76ff1Sjsg 	 */
11561bb76ff1Sjsg 
11571bb76ff1Sjsg 	for (i = 0; i < native_nfourccs; ++i) {
1158*f005ef32Sjsg 		/*
1159*f005ef32Sjsg 		 * Several DTs, boot loaders and firmware report native
1160*f005ef32Sjsg 		 * alpha formats that are non-alpha formats instead. So
1161*f005ef32Sjsg 		 * replace alpha formats by non-alpha formats.
1162*f005ef32Sjsg 		 */
1163*f005ef32Sjsg 		u32 fourcc = drm_fb_nonalpha_fourcc(native_fourccs[i]);
11641bb76ff1Sjsg 
11651bb76ff1Sjsg 		if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
11661bb76ff1Sjsg 			continue; /* skip duplicate entries */
11671bb76ff1Sjsg 		} else if (fourccs == fourccs_end) {
11681bb76ff1Sjsg 			drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc);
11691bb76ff1Sjsg 			continue; /* end of available output buffer */
11705ca02815Sjsg 		}
11711bb76ff1Sjsg 
11721bb76ff1Sjsg 		drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc);
11731bb76ff1Sjsg 
11741bb76ff1Sjsg 		*fourccs = fourcc;
11751bb76ff1Sjsg 		++fourccs;
11761bb76ff1Sjsg 	}
11771bb76ff1Sjsg 
11781bb76ff1Sjsg 	/*
11791bb76ff1Sjsg 	 * The extra formats, emulated by the driver, go second.
11801bb76ff1Sjsg 	 */
11811bb76ff1Sjsg 
1182*f005ef32Sjsg 	for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) {
1183*f005ef32Sjsg 		u32 fourcc = extra_fourccs[i];
11841bb76ff1Sjsg 
11851bb76ff1Sjsg 		if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
11861bb76ff1Sjsg 			continue; /* skip duplicate and native entries */
11871bb76ff1Sjsg 		} else if (fourccs == fourccs_end) {
11881bb76ff1Sjsg 			drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc);
11891bb76ff1Sjsg 			continue; /* end of available output buffer */
11901bb76ff1Sjsg 		}
11911bb76ff1Sjsg 
11921bb76ff1Sjsg 		drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc);
11931bb76ff1Sjsg 
11941bb76ff1Sjsg 		*fourccs = fourcc;
11951bb76ff1Sjsg 		++fourccs;
11961bb76ff1Sjsg 	}
11971bb76ff1Sjsg 
11981bb76ff1Sjsg 	return fourccs - fourccs_out;
11991bb76ff1Sjsg }
12001bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_build_fourcc_list);
1201