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