LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_format_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 253 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 25 0.0 %

          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/module.h>
      12             : #include <linux/slab.h>
      13             : #include <linux/io.h>
      14             : 
      15             : #include <drm/drm_device.h>
      16             : #include <drm/drm_format_helper.h>
      17             : #include <drm/drm_framebuffer.h>
      18             : #include <drm/drm_fourcc.h>
      19             : #include <drm/drm_print.h>
      20             : #include <drm/drm_rect.h>
      21             : 
      22             : static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
      23             : {
      24           0 :         return clip->y1 * pitch + clip->x1 * cpp;
      25             : }
      26             : 
      27             : /**
      28             :  * drm_fb_clip_offset - Returns the clipping rectangles byte-offset in a framebuffer
      29             :  * @pitch: Framebuffer line pitch in byte
      30             :  * @format: Framebuffer format
      31             :  * @clip: Clip rectangle
      32             :  *
      33             :  * Returns:
      34             :  * The byte offset of the clip rectangle's top-left corner within the framebuffer.
      35             :  */
      36           0 : unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
      37             :                                 const struct drm_rect *clip)
      38             : {
      39           0 :         return clip_offset(clip, pitch, format->cpp[0]);
      40             : }
      41             : EXPORT_SYMBOL(drm_fb_clip_offset);
      42             : 
      43             : /* TODO: Make this functon work with multi-plane formats. */
      44           0 : static int drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
      45             :                        const void *vaddr, const struct drm_framebuffer *fb,
      46             :                        const struct drm_rect *clip, bool vaddr_cached_hint,
      47             :                        void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
      48             : {
      49           0 :         unsigned long linepixels = drm_rect_width(clip);
      50           0 :         unsigned long lines = drm_rect_height(clip);
      51           0 :         size_t sbuf_len = linepixels * fb->format->cpp[0];
      52           0 :         void *stmp = NULL;
      53             :         unsigned long i;
      54             :         const void *sbuf;
      55             : 
      56             :         /*
      57             :          * Some source buffers, such as CMA memory, use write-combine
      58             :          * caching, so reads are uncached. Speed up access by fetching
      59             :          * one line at a time.
      60             :          */
      61           0 :         if (!vaddr_cached_hint) {
      62           0 :                 stmp = kmalloc(sbuf_len, GFP_KERNEL);
      63           0 :                 if (!stmp)
      64             :                         return -ENOMEM;
      65             :         }
      66             : 
      67           0 :         if (!dst_pitch)
      68           0 :                 dst_pitch = drm_rect_width(clip) * dst_pixsize;
      69           0 :         vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
      70             : 
      71           0 :         for (i = 0; i < lines; ++i) {
      72           0 :                 if (stmp)
      73           0 :                         sbuf = memcpy(stmp, vaddr, sbuf_len);
      74             :                 else
      75             :                         sbuf = vaddr;
      76           0 :                 xfrm_line(dst, sbuf, linepixels);
      77           0 :                 vaddr += fb->pitches[0];
      78           0 :                 dst += dst_pitch;
      79             :         }
      80             : 
      81           0 :         kfree(stmp);
      82             : 
      83           0 :         return 0;
      84             : }
      85             : 
      86             : /* TODO: Make this functon work with multi-plane formats. */
      87           0 : static int drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
      88             :                             const void *vaddr, const struct drm_framebuffer *fb,
      89             :                             const struct drm_rect *clip, bool vaddr_cached_hint,
      90             :                             void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
      91             : {
      92           0 :         unsigned long linepixels = drm_rect_width(clip);
      93           0 :         unsigned long lines = drm_rect_height(clip);
      94           0 :         size_t dbuf_len = linepixels * dst_pixsize;
      95           0 :         size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */
      96           0 :         size_t sbuf_len = linepixels * fb->format->cpp[0];
      97           0 :         void *stmp = NULL;
      98             :         unsigned long i;
      99             :         const void *sbuf;
     100             :         void *dbuf;
     101             : 
     102           0 :         if (vaddr_cached_hint) {
     103             :                 dbuf = kmalloc(dbuf_len, GFP_KERNEL);
     104             :         } else {
     105           0 :                 dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL);
     106           0 :                 stmp = dbuf + stmp_off;
     107             :         }
     108           0 :         if (!dbuf)
     109             :                 return -ENOMEM;
     110             : 
     111           0 :         if (!dst_pitch)
     112           0 :                 dst_pitch = linepixels * dst_pixsize;
     113           0 :         vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
     114             : 
     115           0 :         for (i = 0; i < lines; ++i) {
     116           0 :                 if (stmp)
     117           0 :                         sbuf = memcpy(stmp, vaddr, sbuf_len);
     118             :                 else
     119             :                         sbuf = vaddr;
     120           0 :                 xfrm_line(dbuf, sbuf, linepixels);
     121           0 :                 memcpy_toio(dst, dbuf, dbuf_len);
     122           0 :                 vaddr += fb->pitches[0];
     123           0 :                 dst += dst_pitch;
     124             :         }
     125             : 
     126           0 :         kfree(dbuf);
     127             : 
     128           0 :         return 0;
     129             : }
     130             : 
     131             : /**
     132             :  * drm_fb_memcpy - Copy clip buffer
     133             :  * @dst: Destination buffer
     134             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     135             :  * @vaddr: Source buffer
     136             :  * @fb: DRM framebuffer
     137             :  * @clip: Clip rectangle area to copy
     138             :  *
     139             :  * This function does not apply clipping on dst, i.e. the destination
     140             :  * is at the top-left corner.
     141             :  */
     142           0 : void drm_fb_memcpy(void *dst, unsigned int dst_pitch, const void *vaddr,
     143             :                    const struct drm_framebuffer *fb, const struct drm_rect *clip)
     144             : {
     145           0 :         unsigned int cpp = fb->format->cpp[0];
     146           0 :         size_t len = (clip->x2 - clip->x1) * cpp;
     147           0 :         unsigned int y, lines = clip->y2 - clip->y1;
     148             : 
     149           0 :         if (!dst_pitch)
     150           0 :                 dst_pitch = len;
     151             : 
     152           0 :         vaddr += clip_offset(clip, fb->pitches[0], cpp);
     153           0 :         for (y = 0; y < lines; y++) {
     154           0 :                 memcpy(dst, vaddr, len);
     155           0 :                 vaddr += fb->pitches[0];
     156           0 :                 dst += dst_pitch;
     157             :         }
     158           0 : }
     159             : EXPORT_SYMBOL(drm_fb_memcpy);
     160             : 
     161             : /**
     162             :  * drm_fb_memcpy_toio - Copy clip buffer
     163             :  * @dst: Destination buffer (iomem)
     164             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     165             :  * @vaddr: Source buffer
     166             :  * @fb: DRM framebuffer
     167             :  * @clip: Clip rectangle area to copy
     168             :  *
     169             :  * This function does not apply clipping on dst, i.e. the destination
     170             :  * is at the top-left corner.
     171             :  */
     172           0 : void drm_fb_memcpy_toio(void __iomem *dst, unsigned int dst_pitch, const void *vaddr,
     173             :                         const struct drm_framebuffer *fb, const struct drm_rect *clip)
     174             : {
     175           0 :         unsigned int cpp = fb->format->cpp[0];
     176           0 :         size_t len = (clip->x2 - clip->x1) * cpp;
     177           0 :         unsigned int y, lines = clip->y2 - clip->y1;
     178             : 
     179           0 :         if (!dst_pitch)
     180           0 :                 dst_pitch = len;
     181             : 
     182           0 :         vaddr += clip_offset(clip, fb->pitches[0], cpp);
     183           0 :         for (y = 0; y < lines; y++) {
     184           0 :                 memcpy_toio(dst, vaddr, len);
     185           0 :                 vaddr += fb->pitches[0];
     186           0 :                 dst += dst_pitch;
     187             :         }
     188           0 : }
     189             : EXPORT_SYMBOL(drm_fb_memcpy_toio);
     190             : 
     191           0 : static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels)
     192             : {
     193           0 :         u16 *dbuf16 = dbuf;
     194           0 :         const u16 *sbuf16 = sbuf;
     195           0 :         const u16 *send16 = sbuf16 + pixels;
     196             : 
     197           0 :         while (sbuf16 < send16)
     198           0 :                 *dbuf16++ = swab16(*sbuf16++);
     199           0 : }
     200             : 
     201           0 : static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels)
     202             : {
     203           0 :         u32 *dbuf32 = dbuf;
     204           0 :         const u32 *sbuf32 = sbuf;
     205           0 :         const u32 *send32 = sbuf32 + pixels;
     206             : 
     207           0 :         while (sbuf32 < send32)
     208           0 :                 *dbuf32++ = swab32(*sbuf32++);
     209           0 : }
     210             : 
     211             : /**
     212             :  * drm_fb_swab - Swap bytes into clip buffer
     213             :  * @dst: Destination buffer
     214             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     215             :  * @src: Source buffer
     216             :  * @fb: DRM framebuffer
     217             :  * @clip: Clip rectangle area to copy
     218             :  * @cached: Source buffer is mapped cached (eg. not write-combined)
     219             :  *
     220             :  * If @cached is false a temporary buffer is used to cache one pixel line at a
     221             :  * time to speed up slow uncached reads.
     222             :  *
     223             :  * This function does not apply clipping on dst, i.e. the destination
     224             :  * is at the top-left corner.
     225             :  */
     226           0 : void drm_fb_swab(void *dst, unsigned int dst_pitch, const void *src,
     227             :                  const struct drm_framebuffer *fb, const struct drm_rect *clip,
     228             :                  bool cached)
     229             : {
     230           0 :         u8 cpp = fb->format->cpp[0];
     231             : 
     232           0 :         switch (cpp) {
     233             :         case 4:
     234           0 :                 drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab32_line);
     235           0 :                 break;
     236             :         case 2:
     237           0 :                 drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab16_line);
     238           0 :                 break;
     239             :         default:
     240           0 :                 drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n",
     241             :                               &fb->format->format);
     242             :                 break;
     243             :         }
     244           0 : }
     245             : EXPORT_SYMBOL(drm_fb_swab);
     246             : 
     247           0 : static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
     248             : {
     249           0 :         u8 *dbuf8 = dbuf;
     250           0 :         const __le32 *sbuf32 = sbuf;
     251             :         unsigned int x;
     252             :         u32 pix;
     253             : 
     254           0 :         for (x = 0; x < pixels; x++) {
     255           0 :                 pix = le32_to_cpu(sbuf32[x]);
     256           0 :                 dbuf8[x] = ((pix & 0x00e00000) >> 16) |
     257           0 :                            ((pix & 0x0000e000) >> 11) |
     258           0 :                            ((pix & 0x000000c0) >> 6);
     259             :         }
     260           0 : }
     261             : 
     262             : /**
     263             :  * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer
     264             :  * @dst: RGB332 destination buffer
     265             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     266             :  * @src: XRGB8888 source buffer
     267             :  * @fb: DRM framebuffer
     268             :  * @clip: Clip rectangle area to copy
     269             :  *
     270             :  * Drivers can use this function for RGB332 devices that don't natively support XRGB8888.
     271             :  */
     272           0 : void drm_fb_xrgb8888_to_rgb332(void *dst, unsigned int dst_pitch, const void *src,
     273             :                                const struct drm_framebuffer *fb, const struct drm_rect *clip)
     274             : {
     275           0 :         drm_fb_xfrm(dst, dst_pitch, 1, src, fb, clip, false, drm_fb_xrgb8888_to_rgb332_line);
     276           0 : }
     277             : EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);
     278             : 
     279           0 : static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels)
     280             : {
     281           0 :         u16 *dbuf16 = dbuf;
     282           0 :         const u32 *sbuf32 = sbuf;
     283             :         unsigned int x;
     284             :         u16 val16;
     285             : 
     286           0 :         for (x = 0; x < pixels; x++) {
     287           0 :                 val16 = ((sbuf32[x] & 0x00F80000) >> 8) |
     288           0 :                         ((sbuf32[x] & 0x0000FC00) >> 5) |
     289           0 :                         ((sbuf32[x] & 0x000000F8) >> 3);
     290           0 :                 dbuf16[x] = val16;
     291             :         }
     292           0 : }
     293             : 
     294           0 : static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
     295             :                                                 unsigned int pixels)
     296             : {
     297           0 :         u16 *dbuf16 = dbuf;
     298           0 :         const u32 *sbuf32 = sbuf;
     299             :         unsigned int x;
     300             :         u16 val16;
     301             : 
     302           0 :         for (x = 0; x < pixels; x++) {
     303           0 :                 val16 = ((sbuf32[x] & 0x00F80000) >> 8) |
     304           0 :                         ((sbuf32[x] & 0x0000FC00) >> 5) |
     305           0 :                         ((sbuf32[x] & 0x000000F8) >> 3);
     306           0 :                 dbuf16[x] = swab16(val16);
     307             :         }
     308           0 : }
     309             : 
     310             : /**
     311             :  * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
     312             :  * @dst: RGB565 destination buffer
     313             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     314             :  * @vaddr: XRGB8888 source buffer
     315             :  * @fb: DRM framebuffer
     316             :  * @clip: Clip rectangle area to copy
     317             :  * @swab: Swap bytes
     318             :  *
     319             :  * Drivers can use this function for RGB565 devices that don't natively
     320             :  * support XRGB8888.
     321             :  */
     322           0 : void drm_fb_xrgb8888_to_rgb565(void *dst, unsigned int dst_pitch, const void *vaddr,
     323             :                                const struct drm_framebuffer *fb, const struct drm_rect *clip,
     324             :                                bool swab)
     325             : {
     326           0 :         if (swab)
     327           0 :                 drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false,
     328             :                             drm_fb_xrgb8888_to_rgb565_swab_line);
     329             :         else
     330           0 :                 drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false,
     331             :                             drm_fb_xrgb8888_to_rgb565_line);
     332           0 : }
     333             : EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
     334             : 
     335             : /**
     336             :  * drm_fb_xrgb8888_to_rgb565_toio - Convert XRGB8888 to RGB565 clip buffer
     337             :  * @dst: RGB565 destination buffer (iomem)
     338             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     339             :  * @vaddr: XRGB8888 source buffer
     340             :  * @fb: DRM framebuffer
     341             :  * @clip: Clip rectangle area to copy
     342             :  * @swab: Swap bytes
     343             :  *
     344             :  * Drivers can use this function for RGB565 devices that don't natively
     345             :  * support XRGB8888.
     346             :  */
     347           0 : void drm_fb_xrgb8888_to_rgb565_toio(void __iomem *dst, unsigned int dst_pitch,
     348             :                                     const void *vaddr, const struct drm_framebuffer *fb,
     349             :                                     const struct drm_rect *clip, bool swab)
     350             : {
     351           0 :         if (swab)
     352           0 :                 drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false,
     353             :                                  drm_fb_xrgb8888_to_rgb565_swab_line);
     354             :         else
     355           0 :                 drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false,
     356             :                                  drm_fb_xrgb8888_to_rgb565_line);
     357           0 : }
     358             : EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_toio);
     359             : 
     360           0 : static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels)
     361             : {
     362           0 :         u8 *dbuf8 = dbuf;
     363           0 :         const u32 *sbuf32 = sbuf;
     364             :         unsigned int x;
     365             : 
     366           0 :         for (x = 0; x < pixels; x++) {
     367           0 :                 *dbuf8++ = (sbuf32[x] & 0x000000FF) >>  0;
     368           0 :                 *dbuf8++ = (sbuf32[x] & 0x0000FF00) >>  8;
     369           0 :                 *dbuf8++ = (sbuf32[x] & 0x00FF0000) >> 16;
     370             :         }
     371           0 : }
     372             : 
     373             : /**
     374             :  * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer
     375             :  * @dst: RGB888 destination buffer
     376             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     377             :  * @src: XRGB8888 source buffer
     378             :  * @fb: DRM framebuffer
     379             :  * @clip: Clip rectangle area to copy
     380             :  *
     381             :  * Drivers can use this function for RGB888 devices that don't natively
     382             :  * support XRGB8888.
     383             :  */
     384           0 : void drm_fb_xrgb8888_to_rgb888(void *dst, unsigned int dst_pitch, const void *src,
     385             :                                const struct drm_framebuffer *fb, const struct drm_rect *clip)
     386             : {
     387           0 :         drm_fb_xfrm(dst, dst_pitch, 3, src, fb, clip, false, drm_fb_xrgb8888_to_rgb888_line);
     388           0 : }
     389             : EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
     390             : 
     391             : /**
     392             :  * drm_fb_xrgb8888_to_rgb888_toio - Convert XRGB8888 to RGB888 clip buffer
     393             :  * @dst: RGB565 destination buffer (iomem)
     394             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     395             :  * @vaddr: XRGB8888 source buffer
     396             :  * @fb: DRM framebuffer
     397             :  * @clip: Clip rectangle area to copy
     398             :  *
     399             :  * Drivers can use this function for RGB888 devices that don't natively
     400             :  * support XRGB8888.
     401             :  */
     402           0 : void drm_fb_xrgb8888_to_rgb888_toio(void __iomem *dst, unsigned int dst_pitch,
     403             :                                     const void *vaddr, const struct drm_framebuffer *fb,
     404             :                                     const struct drm_rect *clip)
     405             : {
     406           0 :         drm_fb_xfrm_toio(dst, dst_pitch, 3, vaddr, fb, clip, false,
     407             :                          drm_fb_xrgb8888_to_rgb888_line);
     408           0 : }
     409             : EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_toio);
     410             : 
     411           0 : static void drm_fb_rgb565_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
     412             : {
     413           0 :         u32 *dbuf32 = dbuf;
     414           0 :         const u16 *sbuf16 = sbuf;
     415             :         unsigned int x;
     416             : 
     417           0 :         for (x = 0; x < pixels; x++, ++sbuf16, ++dbuf32) {
     418           0 :                 u32 val32 = ((*sbuf16 & 0xf800) << 8) |
     419           0 :                             ((*sbuf16 & 0x07e0) << 5) |
     420           0 :                             ((*sbuf16 & 0x001f) << 3);
     421           0 :                 *dbuf32 = 0xff000000 | val32 |
     422           0 :                           ((val32 >> 3) & 0x00070007) |
     423           0 :                           ((val32 >> 2) & 0x00000300);
     424             :         }
     425           0 : }
     426             : 
     427             : static void drm_fb_rgb565_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_pitch,
     428             :                                            const void *vaddr, const struct drm_framebuffer *fb,
     429             :                                            const struct drm_rect *clip)
     430             : {
     431           0 :         drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false,
     432             :                          drm_fb_rgb565_to_xrgb8888_line);
     433             : }
     434             : 
     435           0 : static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
     436             : {
     437           0 :         u32 *dbuf32 = dbuf;
     438           0 :         const u8 *sbuf8 = sbuf;
     439             :         unsigned int x;
     440             : 
     441           0 :         for (x = 0; x < pixels; x++) {
     442           0 :                 u8 r = *sbuf8++;
     443           0 :                 u8 g = *sbuf8++;
     444           0 :                 u8 b = *sbuf8++;
     445           0 :                 *dbuf32++ = 0xff000000 | (r << 16) | (g << 8) | b;
     446             :         }
     447           0 : }
     448             : 
     449             : static void drm_fb_rgb888_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_pitch,
     450             :                                            const void *vaddr, const struct drm_framebuffer *fb,
     451             :                                            const struct drm_rect *clip)
     452             : {
     453           0 :         drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false,
     454             :                          drm_fb_rgb888_to_xrgb8888_line);
     455             : }
     456             : 
     457           0 : static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
     458             : {
     459           0 :         u32 *dbuf32 = dbuf;
     460           0 :         const u32 *sbuf32 = sbuf;
     461             :         unsigned int x;
     462             :         u32 val32;
     463             : 
     464           0 :         for (x = 0; x < pixels; x++) {
     465           0 :                 val32 = ((sbuf32[x] & 0x000000FF) << 2) |
     466           0 :                         ((sbuf32[x] & 0x0000FF00) << 4) |
     467           0 :                         ((sbuf32[x] & 0x00FF0000) << 6);
     468           0 :                 *dbuf32++ = val32 | ((val32 >> 8) & 0x00300C03);
     469             :         }
     470           0 : }
     471             : 
     472             : /**
     473             :  * drm_fb_xrgb8888_to_xrgb2101010_toio - Convert XRGB8888 to XRGB2101010 clip
     474             :  * buffer
     475             :  * @dst: XRGB2101010 destination buffer (iomem)
     476             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     477             :  * @vaddr: XRGB8888 source buffer
     478             :  * @fb: DRM framebuffer
     479             :  * @clip: Clip rectangle area to copy
     480             :  *
     481             :  * Drivers can use this function for XRGB2101010 devices that don't natively
     482             :  * support XRGB8888.
     483             :  */
     484           0 : void drm_fb_xrgb8888_to_xrgb2101010_toio(void __iomem *dst,
     485             :                                          unsigned int dst_pitch, const void *vaddr,
     486             :                                          const struct drm_framebuffer *fb,
     487             :                                          const struct drm_rect *clip)
     488             : {
     489           0 :         drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false,
     490             :                          drm_fb_xrgb8888_to_xrgb2101010_line);
     491           0 : }
     492             : EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio);
     493             : 
     494           0 : static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels)
     495             : {
     496           0 :         u8 *dbuf8 = dbuf;
     497           0 :         const u32 *sbuf32 = sbuf;
     498             :         unsigned int x;
     499             : 
     500           0 :         for (x = 0; x < pixels; x++) {
     501           0 :                 u8 r = (*sbuf32 & 0x00ff0000) >> 16;
     502           0 :                 u8 g = (*sbuf32 & 0x0000ff00) >> 8;
     503           0 :                 u8 b =  *sbuf32 & 0x000000ff;
     504             : 
     505             :                 /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
     506           0 :                 *dbuf8++ = (3 * r + 6 * g + b) / 10;
     507           0 :                 sbuf32++;
     508             :         }
     509           0 : }
     510             : 
     511             : /**
     512             :  * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
     513             :  * @dst: 8-bit grayscale destination buffer
     514             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     515             :  * @vaddr: XRGB8888 source buffer
     516             :  * @fb: DRM framebuffer
     517             :  * @clip: Clip rectangle area to copy
     518             :  *
     519             :  * Drm doesn't have native monochrome or grayscale support.
     520             :  * Such drivers can announce the commonly supported XR24 format to userspace
     521             :  * and use this function to convert to the native format.
     522             :  *
     523             :  * Monochrome drivers will use the most significant bit,
     524             :  * where 1 means foreground color and 0 background color.
     525             :  *
     526             :  * ITU BT.601 is used for the RGB -> luma (brightness) conversion.
     527             :  */
     528           0 : void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vaddr,
     529             :                               const struct drm_framebuffer *fb, const struct drm_rect *clip)
     530             : {
     531           0 :         drm_fb_xfrm(dst, dst_pitch, 1, vaddr, fb, clip, false, drm_fb_xrgb8888_to_gray8_line);
     532           0 : }
     533             : EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
     534             : 
     535             : /**
     536             :  * drm_fb_blit_toio - Copy parts of a framebuffer to display memory
     537             :  * @dst:        The display memory to copy to
     538             :  * @dst_pitch:  Number of bytes between two consecutive scanlines within dst
     539             :  * @dst_format: FOURCC code of the display's color format
     540             :  * @vmap:       The framebuffer memory to copy from
     541             :  * @fb:         The framebuffer to copy from
     542             :  * @clip:       Clip rectangle area to copy
     543             :  *
     544             :  * This function copies parts of a framebuffer to display memory. If the
     545             :  * formats of the display and the framebuffer mismatch, the blit function
     546             :  * will attempt to convert between them.
     547             :  *
     548             :  * Returns:
     549             :  * 0 on success, or
     550             :  * -EINVAL if the color-format conversion failed, or
     551             :  * a negative error code otherwise.
     552             :  */
     553           0 : int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_format,
     554             :                      const void *vmap, const struct drm_framebuffer *fb,
     555             :                      const struct drm_rect *clip)
     556             : {
     557           0 :         uint32_t fb_format = fb->format->format;
     558             : 
     559             :         /* treat alpha channel like filler bits */
     560           0 :         if (fb_format == DRM_FORMAT_ARGB8888)
     561           0 :                 fb_format = DRM_FORMAT_XRGB8888;
     562           0 :         if (dst_format == DRM_FORMAT_ARGB8888)
     563           0 :                 dst_format = DRM_FORMAT_XRGB8888;
     564           0 :         if (fb_format == DRM_FORMAT_ARGB2101010)
     565           0 :                 fb_format = DRM_FORMAT_XRGB2101010;
     566           0 :         if (dst_format == DRM_FORMAT_ARGB2101010)
     567           0 :                 dst_format = DRM_FORMAT_XRGB2101010;
     568             : 
     569           0 :         if (dst_format == fb_format) {
     570           0 :                 drm_fb_memcpy_toio(dst, dst_pitch, vmap, fb, clip);
     571           0 :                 return 0;
     572             : 
     573           0 :         } else if (dst_format == DRM_FORMAT_RGB565) {
     574           0 :                 if (fb_format == DRM_FORMAT_XRGB8888) {
     575           0 :                         drm_fb_xrgb8888_to_rgb565_toio(dst, dst_pitch, vmap, fb, clip, false);
     576           0 :                         return 0;
     577             :                 }
     578           0 :         } else if (dst_format == DRM_FORMAT_RGB888) {
     579           0 :                 if (fb_format == DRM_FORMAT_XRGB8888) {
     580           0 :                         drm_fb_xrgb8888_to_rgb888_toio(dst, dst_pitch, vmap, fb, clip);
     581           0 :                         return 0;
     582             :                 }
     583           0 :         } else if (dst_format == DRM_FORMAT_XRGB8888) {
     584           0 :                 if (fb_format == DRM_FORMAT_RGB888) {
     585           0 :                         drm_fb_rgb888_to_xrgb8888_toio(dst, dst_pitch, vmap, fb, clip);
     586           0 :                         return 0;
     587           0 :                 } else if (fb_format == DRM_FORMAT_RGB565) {
     588           0 :                         drm_fb_rgb565_to_xrgb8888_toio(dst, dst_pitch, vmap, fb, clip);
     589           0 :                         return 0;
     590             :                 }
     591           0 :         } else if (dst_format == DRM_FORMAT_XRGB2101010) {
     592           0 :                 if (fb_format == DRM_FORMAT_XRGB8888) {
     593           0 :                         drm_fb_xrgb8888_to_xrgb2101010_toio(dst, dst_pitch, vmap, fb, clip);
     594           0 :                         return 0;
     595             :                 }
     596             :         }
     597             : 
     598           0 :         drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n",
     599             :                       &fb_format, &dst_format);
     600             : 
     601             :         return -EINVAL;
     602             : }
     603             : EXPORT_SYMBOL(drm_fb_blit_toio);
     604             : 
     605             : 
     606             : static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int pixels)
     607             : {
     608             :         u8 *dbuf8 = dbuf;
     609             :         const u8 *sbuf8 = sbuf;
     610             : 
     611           0 :         while (pixels) {
     612           0 :                 unsigned int i, bits = min(pixels, 8U);
     613           0 :                 u8 byte = 0;
     614             : 
     615           0 :                 for (i = 0; i < bits; i++, pixels--) {
     616           0 :                         if (*sbuf8++ >= 128)
     617           0 :                                 byte |= BIT(i);
     618             :                 }
     619           0 :                 *dbuf8++ = byte;
     620             :         }
     621             : }
     622             : 
     623             : /**
     624             :  * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome
     625             :  * @dst: monochrome destination buffer (0=black, 1=white)
     626             :  * @dst_pitch: Number of bytes between two consecutive scanlines within dst
     627             :  * @vaddr: XRGB8888 source buffer
     628             :  * @fb: DRM framebuffer
     629             :  * @clip: Clip rectangle area to copy
     630             :  *
     631             :  * DRM doesn't have native monochrome support.
     632             :  * Such drivers can announce the commonly supported XR24 format to userspace
     633             :  * and use this function to convert to the native format.
     634             :  *
     635             :  * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and
     636             :  * then the result is converted from grayscale to monochrome.
     637             :  *
     638             :  * The first pixel (upper left corner of the clip rectangle) will be converted
     639             :  * and copied to the first bit (LSB) in the first byte of the monochrome
     640             :  * destination buffer.
     641             :  * If the caller requires that the first pixel in a byte must be located at an
     642             :  * x-coordinate that is a multiple of 8, then the caller must take care itself
     643             :  * of supplying a suitable clip rectangle.
     644             :  */
     645           0 : void drm_fb_xrgb8888_to_mono(void *dst, unsigned int dst_pitch, const void *vaddr,
     646             :                              const struct drm_framebuffer *fb, const struct drm_rect *clip)
     647             : {
     648           0 :         unsigned int linepixels = drm_rect_width(clip);
     649           0 :         unsigned int lines = drm_rect_height(clip);
     650           0 :         unsigned int cpp = fb->format->cpp[0];
     651           0 :         unsigned int len_src32 = linepixels * cpp;
     652           0 :         struct drm_device *dev = fb->dev;
     653             :         unsigned int y;
     654           0 :         u8 *mono = dst, *gray8;
     655             :         u32 *src32;
     656             : 
     657           0 :         if (drm_WARN_ON(dev, fb->format->format != DRM_FORMAT_XRGB8888))
     658             :                 return;
     659             : 
     660             :         /*
     661             :          * The mono destination buffer contains 1 bit per pixel
     662             :          */
     663           0 :         if (!dst_pitch)
     664           0 :                 dst_pitch = DIV_ROUND_UP(linepixels, 8);
     665             : 
     666             :         /*
     667             :          * The cma memory is write-combined so reads are uncached.
     668             :          * Speed up by fetching one line at a time.
     669             :          *
     670             :          * Also, format conversion from XR24 to monochrome are done
     671             :          * line-by-line but are converted to 8-bit grayscale as an
     672             :          * intermediate step.
     673             :          *
     674             :          * Allocate a buffer to be used for both copying from the cma
     675             :          * memory and to store the intermediate grayscale line pixels.
     676             :          */
     677           0 :         src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);
     678           0 :         if (!src32)
     679             :                 return;
     680             : 
     681           0 :         gray8 = (u8 *)src32 + len_src32;
     682             : 
     683           0 :         vaddr += clip_offset(clip, fb->pitches[0], cpp);
     684           0 :         for (y = 0; y < lines; y++) {
     685           0 :                 src32 = memcpy(src32, vaddr, len_src32);
     686             :                 drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels);
     687           0 :                 drm_fb_gray8_to_mono_line(mono, gray8, linepixels);
     688           0 :                 vaddr += fb->pitches[0];
     689           0 :                 mono += dst_pitch;
     690             :         }
     691             : 
     692           0 :         kfree(src32);
     693             : }
     694             : EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);

Generated by: LCOV version 1.14