LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_format_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 197 380 51.8 %
Date: 2023-03-27 20:00:47 Functions: 24 35 68.6 %

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

Generated by: LCOV version 1.14