LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_format_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 274 383 71.5 %
Date: 2023-07-19 18:55:55 Functions: 30 35 85.7 %

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

Generated by: LCOV version 1.14