brintos

brintos / linux-shallow public Read only

0
0
Text · 44.4 KiB · b1be458 Raw
1310 lines · c
1// SPDX-License-Identifier: GPL-2.0 or MIT2/*3 * Copyright (C) 2016 Noralf Trønnes4 *5 * This program is free software; you can redistribute it and/or modify6 * it under the terms of the GNU General Public License as published by7 * the Free Software Foundation; either version 2 of the License, or8 * (at your option) any later version.9 */10 11#include <linux/io.h>12#include <linux/iosys-map.h>13#include <linux/module.h>14#include <linux/slab.h>15 16#include <drm/drm_device.h>17#include <drm/drm_format_helper.h>18#include <drm/drm_framebuffer.h>19#include <drm/drm_fourcc.h>20#include <drm/drm_print.h>21#include <drm/drm_rect.h>22 23/**24 * drm_format_conv_state_init - Initialize format-conversion state25 * @state: The state to initialize26 *27 * Clears all fields in struct drm_format_conv_state. The state will28 * be empty with no preallocated resources.29 */30void drm_format_conv_state_init(struct drm_format_conv_state *state)31{32	state->tmp.mem = NULL;33	state->tmp.size = 0;34	state->tmp.preallocated = false;35}36EXPORT_SYMBOL(drm_format_conv_state_init);37 38/**39 * drm_format_conv_state_copy - Copy format-conversion state40 * @state: Destination state41 * @old_state: Source state42 *43 * Copies format-conversion state from @old_state to @state; except for44 * temporary storage.45 */46void drm_format_conv_state_copy(struct drm_format_conv_state *state,47				const struct drm_format_conv_state *old_state)48{49	/*50	 * So far, there's only temporary storage here, which we don't51	 * duplicate. Just clear the fields.52	 */53	state->tmp.mem = NULL;54	state->tmp.size = 0;55	state->tmp.preallocated = false;56}57EXPORT_SYMBOL(drm_format_conv_state_copy);58 59/**60 * drm_format_conv_state_reserve - Allocates storage for format conversion61 * @state: The format-conversion state62 * @new_size: The minimum allocation size63 * @flags: Flags for kmalloc()64 *65 * Allocates at least @new_size bytes and returns a pointer to the memory66 * range. After calling this function, previously returned memory blocks67 * are invalid. It's best to collect all memory requirements of a format68 * conversion and call this function once to allocate the range.69 *70 * Returns:71 * A pointer to the allocated memory range, or NULL otherwise.72 */73void *drm_format_conv_state_reserve(struct drm_format_conv_state *state,74				    size_t new_size, gfp_t flags)75{76	void *mem;77 78	if (new_size <= state->tmp.size)79		goto out;80	else if (state->tmp.preallocated)81		return NULL;82 83	mem = krealloc(state->tmp.mem, new_size, flags);84	if (!mem)85		return NULL;86 87	state->tmp.mem = mem;88	state->tmp.size = new_size;89 90out:91	return state->tmp.mem;92}93EXPORT_SYMBOL(drm_format_conv_state_reserve);94 95/**96 * drm_format_conv_state_release - Releases an format-conversion storage97 * @state: The format-conversion state98 *99 * Releases the memory range references by the format-conversion state.100 * After this call, all pointers to the memory are invalid. Prefer101 * drm_format_conv_state_init() for cleaning up and unloading a driver.102 */103void drm_format_conv_state_release(struct drm_format_conv_state *state)104{105	if (state->tmp.preallocated)106		return;107 108	kfree(state->tmp.mem);109	state->tmp.mem = NULL;110	state->tmp.size = 0;111}112EXPORT_SYMBOL(drm_format_conv_state_release);113 114static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)115{116	return clip->y1 * pitch + clip->x1 * cpp;117}118 119/**120 * drm_fb_clip_offset - Returns the clipping rectangles byte-offset in a framebuffer121 * @pitch: Framebuffer line pitch in byte122 * @format: Framebuffer format123 * @clip: Clip rectangle124 *125 * Returns:126 * The byte offset of the clip rectangle's top-left corner within the framebuffer.127 */128unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,129				const struct drm_rect *clip)130{131	return clip_offset(clip, pitch, format->cpp[0]);132}133EXPORT_SYMBOL(drm_fb_clip_offset);134 135/* TODO: Make this function work with multi-plane formats. */136static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize,137			 const void *vaddr, const struct drm_framebuffer *fb,138			 const struct drm_rect *clip, bool vaddr_cached_hint,139			 struct drm_format_conv_state *state,140			 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))141{142	unsigned long linepixels = drm_rect_width(clip);143	unsigned long lines = drm_rect_height(clip);144	size_t sbuf_len = linepixels * fb->format->cpp[0];145	void *stmp = NULL;146	unsigned long i;147	const void *sbuf;148 149	/*150	 * Some source buffers, such as DMA memory, use write-combine151	 * caching, so reads are uncached. Speed up access by fetching152	 * one line at a time.153	 */154	if (!vaddr_cached_hint) {155		stmp = drm_format_conv_state_reserve(state, sbuf_len, GFP_KERNEL);156		if (!stmp)157			return -ENOMEM;158	}159 160	if (!dst_pitch)161		dst_pitch = drm_rect_width(clip) * dst_pixsize;162	vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);163 164	for (i = 0; i < lines; ++i) {165		if (stmp)166			sbuf = memcpy(stmp, vaddr, sbuf_len);167		else168			sbuf = vaddr;169		xfrm_line(dst, sbuf, linepixels);170		vaddr += fb->pitches[0];171		dst += dst_pitch;172	}173 174	return 0;175}176 177/* TODO: Make this function work with multi-plane formats. */178static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize,179			      const void *vaddr, const struct drm_framebuffer *fb,180			      const struct drm_rect *clip, bool vaddr_cached_hint,181			      struct drm_format_conv_state *state,182			      void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))183{184	unsigned long linepixels = drm_rect_width(clip);185	unsigned long lines = drm_rect_height(clip);186	size_t dbuf_len = linepixels * dst_pixsize;187	size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */188	size_t sbuf_len = linepixels * fb->format->cpp[0];189	void *stmp = NULL;190	unsigned long i;191	const void *sbuf;192	void *dbuf;193 194	if (vaddr_cached_hint) {195		dbuf = drm_format_conv_state_reserve(state, dbuf_len, GFP_KERNEL);196	} else {197		dbuf = drm_format_conv_state_reserve(state, stmp_off + sbuf_len, GFP_KERNEL);198		stmp = dbuf + stmp_off;199	}200	if (!dbuf)201		return -ENOMEM;202 203	if (!dst_pitch)204		dst_pitch = linepixels * dst_pixsize;205	vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);206 207	for (i = 0; i < lines; ++i) {208		if (stmp)209			sbuf = memcpy(stmp, vaddr, sbuf_len);210		else211			sbuf = vaddr;212		xfrm_line(dbuf, sbuf, linepixels);213		memcpy_toio(dst, dbuf, dbuf_len);214		vaddr += fb->pitches[0];215		dst += dst_pitch;216	}217 218	return 0;219}220 221/* TODO: Make this function work with multi-plane formats. */222static int drm_fb_xfrm(struct iosys_map *dst,223		       const unsigned int *dst_pitch, const u8 *dst_pixsize,224		       const struct iosys_map *src, const struct drm_framebuffer *fb,225		       const struct drm_rect *clip, bool vaddr_cached_hint,226		       struct drm_format_conv_state *state,227		       void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))228{229	static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {230		0, 0, 0, 0231	};232 233	if (!dst_pitch)234		dst_pitch = default_dst_pitch;235 236	/* TODO: handle src in I/O memory here */237	if (dst[0].is_iomem)238		return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0],239					  src[0].vaddr, fb, clip, vaddr_cached_hint, state,240					  xfrm_line);241	else242		return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0],243				     src[0].vaddr, fb, clip, vaddr_cached_hint, state,244				     xfrm_line);245}246 247/**248 * drm_fb_memcpy - Copy clip buffer249 * @dst: Array of destination buffers250 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines251 *             within @dst; can be NULL if scanlines are stored next to each other.252 * @src: Array of source buffers253 * @fb: DRM framebuffer254 * @clip: Clip rectangle area to copy255 *256 * This function copies parts of a framebuffer to display memory. Destination and257 * framebuffer formats must match. No conversion takes place. The parameters @dst,258 * @dst_pitch and @src refer to arrays. Each array must have at least as many entries259 * as there are planes in @fb's format. Each entry stores the value for the format's260 * respective color plane at the same index.261 *262 * This function does not apply clipping on @dst (i.e. the destination is at the263 * top-left corner).264 */265void drm_fb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch,266		   const struct iosys_map *src, const struct drm_framebuffer *fb,267		   const struct drm_rect *clip)268{269	static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {270		0, 0, 0, 0271	};272 273	const struct drm_format_info *format = fb->format;274	unsigned int i, y, lines = drm_rect_height(clip);275 276	if (!dst_pitch)277		dst_pitch = default_dst_pitch;278 279	for (i = 0; i < format->num_planes; ++i) {280		unsigned int bpp_i = drm_format_info_bpp(format, i);281		unsigned int cpp_i = DIV_ROUND_UP(bpp_i, 8);282		size_t len_i = DIV_ROUND_UP(drm_rect_width(clip) * bpp_i, 8);283		unsigned int dst_pitch_i = dst_pitch[i];284		struct iosys_map dst_i = dst[i];285		struct iosys_map src_i = src[i];286 287		if (!dst_pitch_i)288			dst_pitch_i = len_i;289 290		iosys_map_incr(&src_i, clip_offset(clip, fb->pitches[i], cpp_i));291		for (y = 0; y < lines; y++) {292			/* TODO: handle src_i in I/O memory here */293			iosys_map_memcpy_to(&dst_i, 0, src_i.vaddr, len_i);294			iosys_map_incr(&src_i, fb->pitches[i]);295			iosys_map_incr(&dst_i, dst_pitch_i);296		}297	}298}299EXPORT_SYMBOL(drm_fb_memcpy);300 301static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels)302{303	u16 *dbuf16 = dbuf;304	const u16 *sbuf16 = sbuf;305	const u16 *send16 = sbuf16 + pixels;306 307	while (sbuf16 < send16)308		*dbuf16++ = swab16(*sbuf16++);309}310 311static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels)312{313	u32 *dbuf32 = dbuf;314	const u32 *sbuf32 = sbuf;315	const u32 *send32 = sbuf32 + pixels;316 317	while (sbuf32 < send32)318		*dbuf32++ = swab32(*sbuf32++);319}320 321/**322 * drm_fb_swab - Swap bytes into clip buffer323 * @dst: Array of destination buffers324 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines325 *             within @dst; can be NULL if scanlines are stored next to each other.326 * @src: Array of source buffers327 * @fb: DRM framebuffer328 * @clip: Clip rectangle area to copy329 * @cached: Source buffer is mapped cached (eg. not write-combined)330 * @state: Transform and conversion state331 *332 * This function copies parts of a framebuffer to display memory and swaps per-pixel333 * bytes during the process. Destination and framebuffer formats must match. The334 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at335 * least as many entries as there are planes in @fb's format. Each entry stores the336 * value for the format's respective color plane at the same index. If @cached is337 * false a temporary buffer is used to cache one pixel line at a time to speed up338 * slow uncached reads.339 *340 * This function does not apply clipping on @dst (i.e. the destination is at the341 * top-left corner).342 */343void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,344		 const struct iosys_map *src, const struct drm_framebuffer *fb,345		 const struct drm_rect *clip, bool cached,346		 struct drm_format_conv_state *state)347{348	const struct drm_format_info *format = fb->format;349	u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8);350	void (*swab_line)(void *dbuf, const void *sbuf, unsigned int npixels);351 352	switch (cpp) {353	case 4:354		swab_line = drm_fb_swab32_line;355		break;356	case 2:357		swab_line = drm_fb_swab16_line;358		break;359	default:360		drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n",361			      &format->format);362		return;363	}364 365	drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, state, swab_line);366}367EXPORT_SYMBOL(drm_fb_swab);368 369static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)370{371	u8 *dbuf8 = dbuf;372	const __le32 *sbuf32 = sbuf;373	unsigned int x;374	u32 pix;375 376	for (x = 0; x < pixels; x++) {377		pix = le32_to_cpu(sbuf32[x]);378		dbuf8[x] = ((pix & 0x00e00000) >> 16) |379			   ((pix & 0x0000e000) >> 11) |380			   ((pix & 0x000000c0) >> 6);381	}382}383 384/**385 * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer386 * @dst: Array of RGB332 destination buffers387 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines388 *             within @dst; can be NULL if scanlines are stored next to each other.389 * @src: Array of XRGB8888 source buffers390 * @fb: DRM framebuffer391 * @clip: Clip rectangle area to copy392 * @state: Transform and conversion state393 *394 * This function copies parts of a framebuffer to display memory and converts the395 * color format during the process. Destination and framebuffer formats must match. The396 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at397 * least as many entries as there are planes in @fb's format. Each entry stores the398 * value for the format's respective color plane at the same index.399 *400 * This function does not apply clipping on @dst (i.e. the destination is at the401 * top-left corner).402 *403 * Drivers can use this function for RGB332 devices that don't support XRGB8888 natively.404 */405void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,406			       const struct iosys_map *src, const struct drm_framebuffer *fb,407			       const struct drm_rect *clip, struct drm_format_conv_state *state)408{409	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {410		1,411	};412 413	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,414		    drm_fb_xrgb8888_to_rgb332_line);415}416EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);417 418static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels)419{420	__le16 *dbuf16 = dbuf;421	const __le32 *sbuf32 = sbuf;422	unsigned int x;423	u16 val16;424	u32 pix;425 426	for (x = 0; x < pixels; x++) {427		pix = le32_to_cpu(sbuf32[x]);428		val16 = ((pix & 0x00F80000) >> 8) |429			((pix & 0x0000FC00) >> 5) |430			((pix & 0x000000F8) >> 3);431		dbuf16[x] = cpu_to_le16(val16);432	}433}434 435/* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */436static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,437						unsigned int pixels)438{439	__le16 *dbuf16 = dbuf;440	const __le32 *sbuf32 = sbuf;441	unsigned int x;442	u16 val16;443	u32 pix;444 445	for (x = 0; x < pixels; x++) {446		pix = le32_to_cpu(sbuf32[x]);447		val16 = ((pix & 0x00F80000) >> 8) |448			((pix & 0x0000FC00) >> 5) |449			((pix & 0x000000F8) >> 3);450		dbuf16[x] = cpu_to_le16(swab16(val16));451	}452}453 454/**455 * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer456 * @dst: Array of RGB565 destination buffers457 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines458 *             within @dst; can be NULL if scanlines are stored next to each other.459 * @src: Array of XRGB8888 source buffer460 * @fb: DRM framebuffer461 * @clip: Clip rectangle area to copy462 * @state: Transform and conversion state463 * @swab: Swap bytes464 *465 * This function copies parts of a framebuffer to display memory and converts the466 * color format during the process. Destination and framebuffer formats must match. The467 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at468 * least as many entries as there are planes in @fb's format. Each entry stores the469 * value for the format's respective color plane at the same index.470 *471 * This function does not apply clipping on @dst (i.e. the destination is at the472 * top-left corner).473 *474 * Drivers can use this function for RGB565 devices that don't support XRGB8888 natively.475 */476void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,477			       const struct iosys_map *src, const struct drm_framebuffer *fb,478			       const struct drm_rect *clip, struct drm_format_conv_state *state,479			       bool swab)480{481	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {482		2,483	};484 485	void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels);486 487	if (swab)488		xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line;489	else490		xfrm_line = drm_fb_xrgb8888_to_rgb565_line;491 492	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, xfrm_line);493}494EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);495 496static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)497{498	__le16 *dbuf16 = dbuf;499	const __le32 *sbuf32 = sbuf;500	unsigned int x;501	u16 val16;502	u32 pix;503 504	for (x = 0; x < pixels; x++) {505		pix = le32_to_cpu(sbuf32[x]);506		val16 = ((pix & 0x00f80000) >> 9) |507			((pix & 0x0000f800) >> 6) |508			((pix & 0x000000f8) >> 3);509		dbuf16[x] = cpu_to_le16(val16);510	}511}512 513/**514 * drm_fb_xrgb8888_to_xrgb1555 - Convert XRGB8888 to XRGB1555 clip buffer515 * @dst: Array of XRGB1555 destination buffers516 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines517 *             within @dst; can be NULL if scanlines are stored next to each other.518 * @src: Array of XRGB8888 source buffer519 * @fb: DRM framebuffer520 * @clip: Clip rectangle area to copy521 * @state: Transform and conversion state522 *523 * This function copies parts of a framebuffer to display memory and converts524 * the color format during the process. The parameters @dst, @dst_pitch and525 * @src refer to arrays. Each array must have at least as many entries as526 * there are planes in @fb's format. Each entry stores the value for the527 * format's respective color plane at the same index.528 *529 * This function does not apply clipping on @dst (i.e. the destination is at the530 * top-left corner).531 *532 * Drivers can use this function for XRGB1555 devices that don't support533 * XRGB8888 natively.534 */535void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,536				 const struct iosys_map *src, const struct drm_framebuffer *fb,537				 const struct drm_rect *clip, struct drm_format_conv_state *state)538{539	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {540		2,541	};542 543	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,544		    drm_fb_xrgb8888_to_xrgb1555_line);545}546EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555);547 548static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)549{550	__le16 *dbuf16 = dbuf;551	const __le32 *sbuf32 = sbuf;552	unsigned int x;553	u16 val16;554	u32 pix;555 556	for (x = 0; x < pixels; x++) {557		pix = le32_to_cpu(sbuf32[x]);558		val16 = BIT(15) | /* set alpha bit */559			((pix & 0x00f80000) >> 9) |560			((pix & 0x0000f800) >> 6) |561			((pix & 0x000000f8) >> 3);562		dbuf16[x] = cpu_to_le16(val16);563	}564}565 566/**567 * drm_fb_xrgb8888_to_argb1555 - Convert XRGB8888 to ARGB1555 clip buffer568 * @dst: Array of ARGB1555 destination buffers569 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines570 *             within @dst; can be NULL if scanlines are stored next to each other.571 * @src: Array of XRGB8888 source buffer572 * @fb: DRM framebuffer573 * @clip: Clip rectangle area to copy574 * @state: Transform and conversion state575 *576 * This function copies parts of a framebuffer to display memory and converts577 * the color format during the process. The parameters @dst, @dst_pitch and578 * @src refer to arrays. Each array must have at least as many entries as579 * there are planes in @fb's format. Each entry stores the value for the580 * format's respective color plane at the same index.581 *582 * This function does not apply clipping on @dst (i.e. the destination is at the583 * top-left corner).584 *585 * Drivers can use this function for ARGB1555 devices that don't support586 * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.587 */588void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch,589				 const struct iosys_map *src, const struct drm_framebuffer *fb,590				 const struct drm_rect *clip, struct drm_format_conv_state *state)591{592	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {593		2,594	};595 596	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,597		    drm_fb_xrgb8888_to_argb1555_line);598}599EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555);600 601static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsigned int pixels)602{603	__le16 *dbuf16 = dbuf;604	const __le32 *sbuf32 = sbuf;605	unsigned int x;606	u16 val16;607	u32 pix;608 609	for (x = 0; x < pixels; x++) {610		pix = le32_to_cpu(sbuf32[x]);611		val16 = ((pix & 0x00f80000) >> 8) |612			((pix & 0x0000f800) >> 5) |613			((pix & 0x000000f8) >> 2) |614			BIT(0); /* set alpha bit */615		dbuf16[x] = cpu_to_le16(val16);616	}617}618 619/**620 * drm_fb_xrgb8888_to_rgba5551 - Convert XRGB8888 to RGBA5551 clip buffer621 * @dst: Array of RGBA5551 destination buffers622 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines623 *             within @dst; can be NULL if scanlines are stored next to each other.624 * @src: Array of XRGB8888 source buffer625 * @fb: DRM framebuffer626 * @clip: Clip rectangle area to copy627 * @state: Transform and conversion state628 *629 * This function copies parts of a framebuffer to display memory and converts630 * the color format during the process. The parameters @dst, @dst_pitch and631 * @src refer to arrays. Each array must have at least as many entries as632 * there are planes in @fb's format. Each entry stores the value for the633 * format's respective color plane at the same index.634 *635 * This function does not apply clipping on @dst (i.e. the destination is at the636 * top-left corner).637 *638 * Drivers can use this function for RGBA5551 devices that don't support639 * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.640 */641void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch,642				 const struct iosys_map *src, const struct drm_framebuffer *fb,643				 const struct drm_rect *clip, struct drm_format_conv_state *state)644{645	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {646		2,647	};648 649	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,650		    drm_fb_xrgb8888_to_rgba5551_line);651}652EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551);653 654static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels)655{656	u8 *dbuf8 = dbuf;657	const __le32 *sbuf32 = sbuf;658	unsigned int x;659	u32 pix;660 661	for (x = 0; x < pixels; x++) {662		pix = le32_to_cpu(sbuf32[x]);663		/* write blue-green-red to output in little endianness */664		*dbuf8++ = (pix & 0x000000FF) >>  0;665		*dbuf8++ = (pix & 0x0000FF00) >>  8;666		*dbuf8++ = (pix & 0x00FF0000) >> 16;667	}668}669 670/**671 * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer672 * @dst: Array of RGB888 destination buffers673 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines674 *             within @dst; can be NULL if scanlines are stored next to each other.675 * @src: Array of XRGB8888 source buffers676 * @fb: DRM framebuffer677 * @clip: Clip rectangle area to copy678 * @state: Transform and conversion state679 *680 * This function copies parts of a framebuffer to display memory and converts the681 * color format during the process. Destination and framebuffer formats must match. The682 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at683 * least as many entries as there are planes in @fb's format. Each entry stores the684 * value for the format's respective color plane at the same index.685 *686 * This function does not apply clipping on @dst (i.e. the destination is at the687 * top-left corner).688 *689 * Drivers can use this function for RGB888 devices that don't natively690 * support XRGB8888.691 */692void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch,693			       const struct iosys_map *src, const struct drm_framebuffer *fb,694			       const struct drm_rect *clip, struct drm_format_conv_state *state)695{696	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {697		3,698	};699 700	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,701		    drm_fb_xrgb8888_to_rgb888_line);702}703EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);704 705static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)706{707	__le32 *dbuf32 = dbuf;708	const __le32 *sbuf32 = sbuf;709	unsigned int x;710	u32 pix;711 712	for (x = 0; x < pixels; x++) {713		pix = le32_to_cpu(sbuf32[x]);714		pix |= GENMASK(31, 24); /* fill alpha bits */715		dbuf32[x] = cpu_to_le32(pix);716	}717}718 719/**720 * drm_fb_xrgb8888_to_argb8888 - Convert XRGB8888 to ARGB8888 clip buffer721 * @dst: Array of ARGB8888 destination buffers722 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines723 *             within @dst; can be NULL if scanlines are stored next to each other.724 * @src: Array of XRGB8888 source buffer725 * @fb: DRM framebuffer726 * @clip: Clip rectangle area to copy727 * @state: Transform and conversion state728 *729 * This function copies parts of a framebuffer to display memory and converts the730 * color format during the process. The parameters @dst, @dst_pitch and @src refer731 * to arrays. Each array must have at least as many entries as there are planes in732 * @fb's format. Each entry stores the value for the format's respective color plane733 * at the same index.734 *735 * This function does not apply clipping on @dst (i.e. the destination is at the736 * top-left corner).737 *738 * Drivers can use this function for ARGB8888 devices that don't support XRGB8888739 * natively. It sets an opaque alpha channel as part of the conversion.740 */741void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,742				 const struct iosys_map *src, const struct drm_framebuffer *fb,743				 const struct drm_rect *clip, struct drm_format_conv_state *state)744{745	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {746		4,747	};748 749	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,750		    drm_fb_xrgb8888_to_argb8888_line);751}752EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888);753 754static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)755{756	__le32 *dbuf32 = dbuf;757	const __le32 *sbuf32 = sbuf;758	unsigned int x;759	u32 pix;760 761	for (x = 0; x < pixels; x++) {762		pix = le32_to_cpu(sbuf32[x]);763		pix = ((pix & 0x00ff0000) >> 16) <<  0 |764		      ((pix & 0x0000ff00) >>  8) <<  8 |765		      ((pix & 0x000000ff) >>  0) << 16 |766		      GENMASK(31, 24); /* fill alpha bits */767		*dbuf32++ = cpu_to_le32(pix);768	}769}770 771static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,772					const struct iosys_map *src,773					const struct drm_framebuffer *fb,774					const struct drm_rect *clip,775					struct drm_format_conv_state *state)776{777	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {778		4,779	};780 781	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,782		    drm_fb_xrgb8888_to_abgr8888_line);783}784 785static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)786{787	__le32 *dbuf32 = dbuf;788	const __le32 *sbuf32 = sbuf;789	unsigned int x;790	u32 pix;791 792	for (x = 0; x < pixels; x++) {793		pix = le32_to_cpu(sbuf32[x]);794		pix = ((pix & 0x00ff0000) >> 16) <<  0 |795		      ((pix & 0x0000ff00) >>  8) <<  8 |796		      ((pix & 0x000000ff) >>  0) << 16 |797		      ((pix & 0xff000000) >> 24) << 24;798		*dbuf32++ = cpu_to_le32(pix);799	}800}801 802static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,803					const struct iosys_map *src,804					const struct drm_framebuffer *fb,805					const struct drm_rect *clip,806					struct drm_format_conv_state *state)807{808	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {809		4,810	};811 812	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,813		    drm_fb_xrgb8888_to_xbgr8888_line);814}815 816static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)817{818	__le32 *dbuf32 = dbuf;819	const __le32 *sbuf32 = sbuf;820	unsigned int x;821	u32 val32;822	u32 pix;823 824	for (x = 0; x < pixels; x++) {825		pix = le32_to_cpu(sbuf32[x]);826		val32 = ((pix & 0x000000FF) << 2) |827			((pix & 0x0000FF00) << 4) |828			((pix & 0x00FF0000) << 6);829		pix = val32 | ((val32 >> 8) & 0x00300C03);830		*dbuf32++ = cpu_to_le32(pix);831	}832}833 834/**835 * drm_fb_xrgb8888_to_xrgb2101010 - Convert XRGB8888 to XRGB2101010 clip buffer836 * @dst: Array of XRGB2101010 destination buffers837 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines838 *             within @dst; can be NULL if scanlines are stored next to each other.839 * @src: Array of XRGB8888 source buffers840 * @fb: DRM framebuffer841 * @clip: Clip rectangle area to copy842 * @state: Transform and conversion state843 *844 * This function copies parts of a framebuffer to display memory and converts the845 * color format during the process. Destination and framebuffer formats must match. The846 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at847 * least as many entries as there are planes in @fb's format. Each entry stores the848 * value for the format's respective color plane at the same index.849 *850 * This function does not apply clipping on @dst (i.e. the destination is at the851 * top-left corner).852 *853 * Drivers can use this function for XRGB2101010 devices that don't support XRGB8888854 * natively.855 */856void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,857				    const struct iosys_map *src, const struct drm_framebuffer *fb,858				    const struct drm_rect *clip,859				    struct drm_format_conv_state *state)860{861	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {862		4,863	};864 865	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,866		    drm_fb_xrgb8888_to_xrgb2101010_line);867}868EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010);869 870static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)871{872	__le32 *dbuf32 = dbuf;873	const __le32 *sbuf32 = sbuf;874	unsigned int x;875	u32 val32;876	u32 pix;877 878	for (x = 0; x < pixels; x++) {879		pix = le32_to_cpu(sbuf32[x]);880		val32 = ((pix & 0x000000ff) << 2) |881			((pix & 0x0000ff00) << 4) |882			((pix & 0x00ff0000) << 6);883		pix = GENMASK(31, 30) | /* set alpha bits */884		      val32 | ((val32 >> 8) & 0x00300c03);885		*dbuf32++ = cpu_to_le32(pix);886	}887}888 889/**890 * drm_fb_xrgb8888_to_argb2101010 - Convert XRGB8888 to ARGB2101010 clip buffer891 * @dst: Array of ARGB2101010 destination buffers892 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines893 *             within @dst; can be NULL if scanlines are stored next to each other.894 * @src: Array of XRGB8888 source buffers895 * @fb: DRM framebuffer896 * @clip: Clip rectangle area to copy897 * @state: Transform and conversion state898 *899 * This function copies parts of a framebuffer to display memory and converts900 * the color format during the process. The parameters @dst, @dst_pitch and901 * @src refer to arrays. Each array must have at least as many entries as902 * there are planes in @fb's format. Each entry stores the value for the903 * format's respective color plane at the same index.904 *905 * This function does not apply clipping on @dst (i.e. the destination is at the906 * top-left corner).907 *908 * Drivers can use this function for ARGB2101010 devices that don't support XRGB8888909 * natively.910 */911void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,912				    const struct iosys_map *src, const struct drm_framebuffer *fb,913				    const struct drm_rect *clip,914				    struct drm_format_conv_state *state)915{916	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {917		4,918	};919 920	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,921		    drm_fb_xrgb8888_to_argb2101010_line);922}923EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010);924 925static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels)926{927	u8 *dbuf8 = dbuf;928	const __le32 *sbuf32 = sbuf;929	unsigned int x;930 931	for (x = 0; x < pixels; x++) {932		u32 pix = le32_to_cpu(sbuf32[x]);933		u8 r = (pix & 0x00ff0000) >> 16;934		u8 g = (pix & 0x0000ff00) >> 8;935		u8 b =  pix & 0x000000ff;936 937		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */938		*dbuf8++ = (3 * r + 6 * g + b) / 10;939	}940}941 942/**943 * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale944 * @dst: Array of 8-bit grayscale destination buffers945 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines946 *             within @dst; can be NULL if scanlines are stored next to each other.947 * @src: Array of XRGB8888 source buffers948 * @fb: DRM framebuffer949 * @clip: Clip rectangle area to copy950 * @state: Transform and conversion state951 *952 * This function copies parts of a framebuffer to display memory and converts the953 * color format during the process. Destination and framebuffer formats must match. The954 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at955 * least as many entries as there are planes in @fb's format. Each entry stores the956 * value for the format's respective color plane at the same index.957 *958 * This function does not apply clipping on @dst (i.e. the destination is at the959 * top-left corner).960 *961 * DRM doesn't have native monochrome or grayscale support. Drivers can use this962 * function for grayscale devices that don't support XRGB8888 natively.Such963 * drivers can announce the commonly supported XR24 format to userspace and use964 * this function to convert to the native format. Monochrome drivers will use the965 * most significant bit, where 1 means foreground color and 0 background color.966 * ITU BT.601 is being used for the RGB -> luma (brightness) conversion.967 */968void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch,969			      const struct iosys_map *src, const struct drm_framebuffer *fb,970			      const struct drm_rect *clip, struct drm_format_conv_state *state)971{972	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {973		1,974	};975 976	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,977		    drm_fb_xrgb8888_to_gray8_line);978}979EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);980 981/**982 * drm_fb_blit - Copy parts of a framebuffer to display memory983 * @dst:	Array of display-memory addresses to copy to984 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines985 *             within @dst; can be NULL if scanlines are stored next to each other.986 * @dst_format:	FOURCC code of the display's color format987 * @src:	The framebuffer memory to copy from988 * @fb:		The framebuffer to copy from989 * @clip:	Clip rectangle area to copy990 * @state: Transform and conversion state991 *992 * This function copies parts of a framebuffer to display memory. If the993 * formats of the display and the framebuffer mismatch, the blit function994 * will attempt to convert between them during the process. The parameters @dst,995 * @dst_pitch and @src refer to arrays. Each array must have at least as many996 * entries as there are planes in @dst_format's format. Each entry stores the997 * value for the format's respective color plane at the same index.998 *999 * This function does not apply clipping on @dst (i.e. the destination is at the1000 * top-left corner).1001 *1002 * Returns:1003 * 0 on success, or1004 * -EINVAL if the color-format conversion failed, or1005 * a negative error code otherwise.1006 */1007int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format,1008		const struct iosys_map *src, const struct drm_framebuffer *fb,1009		const struct drm_rect *clip, struct drm_format_conv_state *state)1010{1011	uint32_t fb_format = fb->format->format;1012 1013	if (fb_format == dst_format) {1014		drm_fb_memcpy(dst, dst_pitch, src, fb, clip);1015		return 0;1016	} else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) {1017		drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state);1018		return 0;1019	} else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) {1020		drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state);1021		return 0;1022	} else if (fb_format == DRM_FORMAT_XRGB8888) {1023		if (dst_format == DRM_FORMAT_RGB565) {1024			drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state, false);1025			return 0;1026		} else if (dst_format == DRM_FORMAT_XRGB1555) {1027			drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, state);1028			return 0;1029		} else if (dst_format == DRM_FORMAT_ARGB1555) {1030			drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip, state);1031			return 0;1032		} else if (dst_format == DRM_FORMAT_RGBA5551) {1033			drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip, state);1034			return 0;1035		} else if (dst_format == DRM_FORMAT_RGB888) {1036			drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip, state);1037			return 0;1038		} else if (dst_format == DRM_FORMAT_ARGB8888) {1039			drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip, state);1040			return 0;1041		} else if (dst_format == DRM_FORMAT_XBGR8888) {1042			drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip, state);1043			return 0;1044		} else if (dst_format == DRM_FORMAT_ABGR8888) {1045			drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip, state);1046			return 0;1047		} else if (dst_format == DRM_FORMAT_XRGB2101010) {1048			drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip, state);1049			return 0;1050		} else if (dst_format == DRM_FORMAT_ARGB2101010) {1051			drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip, state);1052			return 0;1053		} else if (dst_format == DRM_FORMAT_BGRX8888) {1054			drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state);1055			return 0;1056		}1057	}1058 1059	drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n",1060		      &fb_format, &dst_format);1061 1062	return -EINVAL;1063}1064EXPORT_SYMBOL(drm_fb_blit);1065 1066static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int pixels)1067{1068	u8 *dbuf8 = dbuf;1069	const u8 *sbuf8 = sbuf;1070 1071	while (pixels) {1072		unsigned int i, bits = min(pixels, 8U);1073		u8 byte = 0;1074 1075		for (i = 0; i < bits; i++, pixels--) {1076			if (*sbuf8++ >= 128)1077				byte |= BIT(i);1078		}1079		*dbuf8++ = byte;1080	}1081}1082 1083/**1084 * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome1085 * @dst: Array of monochrome destination buffers (0=black, 1=white)1086 * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines1087 *             within @dst; can be NULL if scanlines are stored next to each other.1088 * @src: Array of XRGB8888 source buffers1089 * @fb: DRM framebuffer1090 * @clip: Clip rectangle area to copy1091 * @state: Transform and conversion state1092 *1093 * This function copies parts of a framebuffer to display memory and converts the1094 * color format during the process. Destination and framebuffer formats must match. The1095 * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at1096 * least as many entries as there are planes in @fb's format. Each entry stores the1097 * value for the format's respective color plane at the same index.1098 *1099 * This function does not apply clipping on @dst (i.e. the destination is at the1100 * top-left corner). The first pixel (upper left corner of the clip rectangle) will1101 * be converted and copied to the first bit (LSB) in the first byte of the monochrome1102 * destination buffer. If the caller requires that the first pixel in a byte must1103 * be located at an x-coordinate that is a multiple of 8, then the caller must take1104 * care itself of supplying a suitable clip rectangle.1105 *1106 * DRM doesn't have native monochrome support. Drivers can use this function for1107 * monochrome devices that don't support XRGB8888 natively. Such drivers can1108 * announce the commonly supported XR24 format to userspace and use this function1109 * to convert to the native format.1110 *1111 * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and1112 * then the result is converted from grayscale to monochrome.1113 */1114void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch,1115			     const struct iosys_map *src, const struct drm_framebuffer *fb,1116			     const struct drm_rect *clip, struct drm_format_conv_state *state)1117{1118	static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {1119		0, 0, 0, 01120	};1121	unsigned int linepixels = drm_rect_width(clip);1122	unsigned int lines = drm_rect_height(clip);1123	unsigned int cpp = fb->format->cpp[0];1124	unsigned int len_src32 = linepixels * cpp;1125	struct drm_device *dev = fb->dev;1126	void *vaddr = src[0].vaddr;1127	unsigned int dst_pitch_0;1128	unsigned int y;1129	u8 *mono = dst[0].vaddr, *gray8;1130	u32 *src32;1131 1132	if (drm_WARN_ON(dev, fb->format->format != DRM_FORMAT_XRGB8888))1133		return;1134 1135	if (!dst_pitch)1136		dst_pitch = default_dst_pitch;1137	dst_pitch_0 = dst_pitch[0];1138 1139	/*1140	 * The mono destination buffer contains 1 bit per pixel1141	 */1142	if (!dst_pitch_0)1143		dst_pitch_0 = DIV_ROUND_UP(linepixels, 8);1144 1145	/*1146	 * The dma memory is write-combined so reads are uncached.1147	 * Speed up by fetching one line at a time.1148	 *1149	 * Also, format conversion from XR24 to monochrome are done1150	 * line-by-line but are converted to 8-bit grayscale as an1151	 * intermediate step.1152	 *1153	 * Allocate a buffer to be used for both copying from the cma1154	 * memory and to store the intermediate grayscale line pixels.1155	 */1156	src32 = drm_format_conv_state_reserve(state, len_src32 + linepixels, GFP_KERNEL);1157	if (!src32)1158		return;1159 1160	gray8 = (u8 *)src32 + len_src32;1161 1162	vaddr += clip_offset(clip, fb->pitches[0], cpp);1163	for (y = 0; y < lines; y++) {1164		src32 = memcpy(src32, vaddr, len_src32);1165		drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels);1166		drm_fb_gray8_to_mono_line(mono, gray8, linepixels);1167		vaddr += fb->pitches[0];1168		mono += dst_pitch_0;1169	}1170}1171EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);1172 1173static uint32_t drm_fb_nonalpha_fourcc(uint32_t fourcc)1174{1175	/* only handle formats with depth != 0 and alpha channel */1176	switch (fourcc) {1177	case DRM_FORMAT_ARGB1555:1178		return DRM_FORMAT_XRGB1555;1179	case DRM_FORMAT_ABGR1555:1180		return DRM_FORMAT_XBGR1555;1181	case DRM_FORMAT_RGBA5551:1182		return DRM_FORMAT_RGBX5551;1183	case DRM_FORMAT_BGRA5551:1184		return DRM_FORMAT_BGRX5551;1185	case DRM_FORMAT_ARGB8888:1186		return DRM_FORMAT_XRGB8888;1187	case DRM_FORMAT_ABGR8888:1188		return DRM_FORMAT_XBGR8888;1189	case DRM_FORMAT_RGBA8888:1190		return DRM_FORMAT_RGBX8888;1191	case DRM_FORMAT_BGRA8888:1192		return DRM_FORMAT_BGRX8888;1193	case DRM_FORMAT_ARGB2101010:1194		return DRM_FORMAT_XRGB2101010;1195	case DRM_FORMAT_ABGR2101010:1196		return DRM_FORMAT_XBGR2101010;1197	case DRM_FORMAT_RGBA1010102:1198		return DRM_FORMAT_RGBX1010102;1199	case DRM_FORMAT_BGRA1010102:1200		return DRM_FORMAT_BGRX1010102;1201	}1202 1203	return fourcc;1204}1205 1206static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc)1207{1208	const uint32_t *fourccs_end = fourccs + nfourccs;1209 1210	while (fourccs < fourccs_end) {1211		if (*fourccs == fourcc)1212			return true;1213		++fourccs;1214	}1215	return false;1216}1217 1218/**1219 * drm_fb_build_fourcc_list - Filters a list of supported color formats against1220 *                            the device's native formats1221 * @dev: DRM device1222 * @native_fourccs: 4CC codes of natively supported color formats1223 * @native_nfourccs: The number of entries in @native_fourccs1224 * @fourccs_out: Returns 4CC codes of supported color formats1225 * @nfourccs_out: The number of available entries in @fourccs_out1226 *1227 * This function create a list of supported color format from natively1228 * supported formats and additional emulated formats.1229 * At a minimum, most userspace programs expect at least support for1230 * XRGB8888 on the primary plane. Devices that have to emulate the1231 * format, and possibly others, can use drm_fb_build_fourcc_list() to1232 * create a list of supported color formats. The returned list can1233 * be handed over to drm_universal_plane_init() et al. Native formats1234 * will go before emulated formats. Native formats with alpha channel1235 * will be replaced by such without, as primary planes usually don't1236 * support alpha. Other heuristics might be applied1237 * to optimize the order. Formats near the beginning of the list are1238 * usually preferred over formats near the end of the list.1239 *1240 * Returns:1241 * The number of color-formats 4CC codes returned in @fourccs_out.1242 */1243size_t drm_fb_build_fourcc_list(struct drm_device *dev,1244				const u32 *native_fourccs, size_t native_nfourccs,1245				u32 *fourccs_out, size_t nfourccs_out)1246{1247	/*1248	 * XRGB8888 is the default fallback format for most of userspace1249	 * and it's currently the only format that should be emulated for1250	 * the primary plane. Only if there's ever another default fallback,1251	 * it should be added here.1252	 */1253	static const uint32_t extra_fourccs[] = {1254		DRM_FORMAT_XRGB8888,1255	};1256	static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs);1257 1258	u32 *fourccs = fourccs_out;1259	const u32 *fourccs_end = fourccs_out + nfourccs_out;1260	size_t i;1261 1262	/*1263	 * The device's native formats go first.1264	 */1265 1266	for (i = 0; i < native_nfourccs; ++i) {1267		/*1268		 * Several DTs, boot loaders and firmware report native1269		 * alpha formats that are non-alpha formats instead. So1270		 * replace alpha formats by non-alpha formats.1271		 */1272		u32 fourcc = drm_fb_nonalpha_fourcc(native_fourccs[i]);1273 1274		if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {1275			continue; /* skip duplicate entries */1276		} else if (fourccs == fourccs_end) {1277			drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc);1278			continue; /* end of available output buffer */1279		}1280 1281		drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc);1282 1283		*fourccs = fourcc;1284		++fourccs;1285	}1286 1287	/*1288	 * The extra formats, emulated by the driver, go second.1289	 */1290 1291	for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) {1292		u32 fourcc = extra_fourccs[i];1293 1294		if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {1295			continue; /* skip duplicate and native entries */1296		} else if (fourccs == fourccs_end) {1297			drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc);1298			continue; /* end of available output buffer */1299		}1300 1301		drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc);1302 1303		*fourccs = fourcc;1304		++fourccs;1305	}1306 1307	return fourccs - fourccs_out;1308}1309EXPORT_SYMBOL(drm_fb_build_fourcc_list);1310