1c349dbc7Sjsg // SPDX-License-Identifier: GPL-2.0 or MIT
2c349dbc7Sjsg /*
3c349dbc7Sjsg * Copyright (C) 2016 Noralf Trønnes
4c349dbc7Sjsg *
5c349dbc7Sjsg * This program is free software; you can redistribute it and/or modify
6c349dbc7Sjsg * it under the terms of the GNU General Public License as published by
7c349dbc7Sjsg * the Free Software Foundation; either version 2 of the License, or
8c349dbc7Sjsg * (at your option) any later version.
9c349dbc7Sjsg */
10c349dbc7Sjsg
111bb76ff1Sjsg #include <linux/io.h>
121bb76ff1Sjsg #include <linux/iosys-map.h>
13c349dbc7Sjsg #include <linux/module.h>
14c349dbc7Sjsg #include <linux/slab.h>
15c349dbc7Sjsg
161bb76ff1Sjsg #include <drm/drm_device.h>
17c349dbc7Sjsg #include <drm/drm_format_helper.h>
18c349dbc7Sjsg #include <drm/drm_framebuffer.h>
19c349dbc7Sjsg #include <drm/drm_fourcc.h>
201bb76ff1Sjsg #include <drm/drm_print.h>
21c349dbc7Sjsg #include <drm/drm_rect.h>
22c349dbc7Sjsg
clip_offset(const struct drm_rect * clip,unsigned int pitch,unsigned int cpp)231bb76ff1Sjsg static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
24c349dbc7Sjsg {
25c349dbc7Sjsg return clip->y1 * pitch + clip->x1 * cpp;
26c349dbc7Sjsg }
27c349dbc7Sjsg
28c349dbc7Sjsg /**
291bb76ff1Sjsg * drm_fb_clip_offset - Returns the clipping rectangles byte-offset in a framebuffer
301bb76ff1Sjsg * @pitch: Framebuffer line pitch in byte
311bb76ff1Sjsg * @format: Framebuffer format
321bb76ff1Sjsg * @clip: Clip rectangle
331bb76ff1Sjsg *
341bb76ff1Sjsg * Returns:
351bb76ff1Sjsg * The byte offset of the clip rectangle's top-left corner within the framebuffer.
361bb76ff1Sjsg */
drm_fb_clip_offset(unsigned int pitch,const struct drm_format_info * format,const struct drm_rect * clip)371bb76ff1Sjsg unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
381bb76ff1Sjsg const struct drm_rect *clip)
391bb76ff1Sjsg {
401bb76ff1Sjsg return clip_offset(clip, pitch, format->cpp[0]);
411bb76ff1Sjsg }
421bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_clip_offset);
431bb76ff1Sjsg
441bb76ff1Sjsg /* TODO: Make this function work with multi-plane formats. */
__drm_fb_xfrm(void * dst,unsigned long dst_pitch,unsigned long dst_pixsize,const void * vaddr,const struct drm_framebuffer * fb,const struct drm_rect * clip,bool vaddr_cached_hint,void (* xfrm_line)(void * dbuf,const void * sbuf,unsigned int npixels))451bb76ff1Sjsg static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
461bb76ff1Sjsg const void *vaddr, const struct drm_framebuffer *fb,
471bb76ff1Sjsg const struct drm_rect *clip, bool vaddr_cached_hint,
481bb76ff1Sjsg void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
491bb76ff1Sjsg {
501bb76ff1Sjsg unsigned long linepixels = drm_rect_width(clip);
511bb76ff1Sjsg unsigned long lines = drm_rect_height(clip);
521bb76ff1Sjsg size_t sbuf_len = linepixels * fb->format->cpp[0];
531bb76ff1Sjsg void *stmp = NULL;
541bb76ff1Sjsg unsigned long i;
551bb76ff1Sjsg const void *sbuf;
561bb76ff1Sjsg
571bb76ff1Sjsg /*
581bb76ff1Sjsg * Some source buffers, such as DMA memory, use write-combine
591bb76ff1Sjsg * caching, so reads are uncached. Speed up access by fetching
601bb76ff1Sjsg * one line at a time.
611bb76ff1Sjsg */
621bb76ff1Sjsg if (!vaddr_cached_hint) {
631bb76ff1Sjsg stmp = kmalloc(sbuf_len, GFP_KERNEL);
641bb76ff1Sjsg if (!stmp)
651bb76ff1Sjsg return -ENOMEM;
661bb76ff1Sjsg }
671bb76ff1Sjsg
681bb76ff1Sjsg if (!dst_pitch)
691bb76ff1Sjsg dst_pitch = drm_rect_width(clip) * dst_pixsize;
701bb76ff1Sjsg vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
711bb76ff1Sjsg
721bb76ff1Sjsg for (i = 0; i < lines; ++i) {
731bb76ff1Sjsg if (stmp)
741bb76ff1Sjsg sbuf = memcpy(stmp, vaddr, sbuf_len);
751bb76ff1Sjsg else
761bb76ff1Sjsg sbuf = vaddr;
771bb76ff1Sjsg xfrm_line(dst, sbuf, linepixels);
781bb76ff1Sjsg vaddr += fb->pitches[0];
791bb76ff1Sjsg dst += dst_pitch;
801bb76ff1Sjsg }
811bb76ff1Sjsg
821bb76ff1Sjsg kfree(stmp);
831bb76ff1Sjsg
841bb76ff1Sjsg return 0;
851bb76ff1Sjsg }
861bb76ff1Sjsg
871bb76ff1Sjsg /* TODO: Make this function work with multi-plane formats. */
__drm_fb_xfrm_toio(void __iomem * dst,unsigned long dst_pitch,unsigned long dst_pixsize,const void * vaddr,const struct drm_framebuffer * fb,const struct drm_rect * clip,bool vaddr_cached_hint,void (* xfrm_line)(void * dbuf,const void * sbuf,unsigned int npixels))881bb76ff1Sjsg static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
891bb76ff1Sjsg const void *vaddr, const struct drm_framebuffer *fb,
901bb76ff1Sjsg const struct drm_rect *clip, bool vaddr_cached_hint,
911bb76ff1Sjsg void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
921bb76ff1Sjsg {
931bb76ff1Sjsg unsigned long linepixels = drm_rect_width(clip);
941bb76ff1Sjsg unsigned long lines = drm_rect_height(clip);
951bb76ff1Sjsg size_t dbuf_len = linepixels * dst_pixsize;
961bb76ff1Sjsg size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */
971bb76ff1Sjsg size_t sbuf_len = linepixels * fb->format->cpp[0];
981bb76ff1Sjsg void *stmp = NULL;
991bb76ff1Sjsg unsigned long i;
1001bb76ff1Sjsg const void *sbuf;
1011bb76ff1Sjsg void *dbuf;
1021bb76ff1Sjsg
1031bb76ff1Sjsg if (vaddr_cached_hint) {
1041bb76ff1Sjsg dbuf = kmalloc(dbuf_len, GFP_KERNEL);
1051bb76ff1Sjsg } else {
1061bb76ff1Sjsg dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL);
1071bb76ff1Sjsg stmp = dbuf + stmp_off;
1081bb76ff1Sjsg }
1091bb76ff1Sjsg if (!dbuf)
1101bb76ff1Sjsg return -ENOMEM;
1111bb76ff1Sjsg
1121bb76ff1Sjsg if (!dst_pitch)
1131bb76ff1Sjsg dst_pitch = linepixels * dst_pixsize;
1141bb76ff1Sjsg vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
1151bb76ff1Sjsg
1161bb76ff1Sjsg for (i = 0; i < lines; ++i) {
1171bb76ff1Sjsg if (stmp)
1181bb76ff1Sjsg sbuf = memcpy(stmp, vaddr, sbuf_len);
1191bb76ff1Sjsg else
1201bb76ff1Sjsg sbuf = vaddr;
1211bb76ff1Sjsg xfrm_line(dbuf, sbuf, linepixels);
1221bb76ff1Sjsg memcpy_toio(dst, dbuf, dbuf_len);
1231bb76ff1Sjsg vaddr += fb->pitches[0];
1241bb76ff1Sjsg dst += dst_pitch;
1251bb76ff1Sjsg }
1261bb76ff1Sjsg
1271bb76ff1Sjsg kfree(dbuf);
1281bb76ff1Sjsg
1291bb76ff1Sjsg return 0;
1301bb76ff1Sjsg }
1311bb76ff1Sjsg
1321bb76ff1Sjsg /* TODO: Make this function work with multi-plane formats. */
drm_fb_xfrm(struct iosys_map * dst,const unsigned int * dst_pitch,const u8 * dst_pixsize,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip,bool vaddr_cached_hint,void (* xfrm_line)(void * dbuf,const void * sbuf,unsigned int npixels))1331bb76ff1Sjsg static int drm_fb_xfrm(struct iosys_map *dst,
1341bb76ff1Sjsg const unsigned int *dst_pitch, const u8 *dst_pixsize,
1351bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
1361bb76ff1Sjsg const struct drm_rect *clip, bool vaddr_cached_hint,
1371bb76ff1Sjsg void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
1381bb76ff1Sjsg {
1391bb76ff1Sjsg static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
1401bb76ff1Sjsg 0, 0, 0, 0
1411bb76ff1Sjsg };
1421bb76ff1Sjsg
1431bb76ff1Sjsg if (!dst_pitch)
1441bb76ff1Sjsg dst_pitch = default_dst_pitch;
1451bb76ff1Sjsg
1461bb76ff1Sjsg /* TODO: handle src in I/O memory here */
1471bb76ff1Sjsg if (dst[0].is_iomem)
1481bb76ff1Sjsg return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0],
1491bb76ff1Sjsg src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line);
1501bb76ff1Sjsg else
1511bb76ff1Sjsg return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0],
1521bb76ff1Sjsg src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line);
1531bb76ff1Sjsg }
1541bb76ff1Sjsg
1551bb76ff1Sjsg /**
156c349dbc7Sjsg * drm_fb_memcpy - Copy clip buffer
1571bb76ff1Sjsg * @dst: Array of destination buffers
1581bb76ff1Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
1591bb76ff1Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
1601bb76ff1Sjsg * @src: Array of source buffers
161c349dbc7Sjsg * @fb: DRM framebuffer
162c349dbc7Sjsg * @clip: Clip rectangle area to copy
163c349dbc7Sjsg *
1641bb76ff1Sjsg * This function copies parts of a framebuffer to display memory. Destination and
1651bb76ff1Sjsg * framebuffer formats must match. No conversion takes place. The parameters @dst,
1661bb76ff1Sjsg * @dst_pitch and @src refer to arrays. Each array must have at least as many entries
1671bb76ff1Sjsg * as there are planes in @fb's format. Each entry stores the value for the format's
1681bb76ff1Sjsg * respective color plane at the same index.
1691bb76ff1Sjsg *
1701bb76ff1Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
1711bb76ff1Sjsg * top-left corner).
172c349dbc7Sjsg */
drm_fb_memcpy(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)1731bb76ff1Sjsg void drm_fb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch,
1741bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
1751bb76ff1Sjsg const struct drm_rect *clip)
176c349dbc7Sjsg {
1771bb76ff1Sjsg static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
1781bb76ff1Sjsg 0, 0, 0, 0
1791bb76ff1Sjsg };
180c349dbc7Sjsg
1811bb76ff1Sjsg const struct drm_format_info *format = fb->format;
1821bb76ff1Sjsg unsigned int i, y, lines = drm_rect_height(clip);
1831bb76ff1Sjsg
1841bb76ff1Sjsg if (!dst_pitch)
1851bb76ff1Sjsg dst_pitch = default_dst_pitch;
1861bb76ff1Sjsg
1871bb76ff1Sjsg for (i = 0; i < format->num_planes; ++i) {
1881bb76ff1Sjsg unsigned int bpp_i = drm_format_info_bpp(format, i);
1891bb76ff1Sjsg unsigned int cpp_i = DIV_ROUND_UP(bpp_i, 8);
1901bb76ff1Sjsg size_t len_i = DIV_ROUND_UP(drm_rect_width(clip) * bpp_i, 8);
1911bb76ff1Sjsg unsigned int dst_pitch_i = dst_pitch[i];
1921bb76ff1Sjsg struct iosys_map dst_i = dst[i];
1931bb76ff1Sjsg struct iosys_map src_i = src[i];
1941bb76ff1Sjsg
1951bb76ff1Sjsg if (!dst_pitch_i)
1961bb76ff1Sjsg dst_pitch_i = len_i;
1971bb76ff1Sjsg
1981bb76ff1Sjsg iosys_map_incr(&src_i, clip_offset(clip, fb->pitches[i], cpp_i));
199c349dbc7Sjsg for (y = 0; y < lines; y++) {
2001bb76ff1Sjsg /* TODO: handle src_i in I/O memory here */
2011bb76ff1Sjsg iosys_map_memcpy_to(&dst_i, 0, src_i.vaddr, len_i);
2021bb76ff1Sjsg iosys_map_incr(&src_i, fb->pitches[i]);
2031bb76ff1Sjsg iosys_map_incr(&dst_i, dst_pitch_i);
2041bb76ff1Sjsg }
205c349dbc7Sjsg }
206c349dbc7Sjsg }
207c349dbc7Sjsg EXPORT_SYMBOL(drm_fb_memcpy);
208c349dbc7Sjsg
drm_fb_swab16_line(void * dbuf,const void * sbuf,unsigned int pixels)2091bb76ff1Sjsg static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels)
210c349dbc7Sjsg {
2111bb76ff1Sjsg u16 *dbuf16 = dbuf;
2121bb76ff1Sjsg const u16 *sbuf16 = sbuf;
2131bb76ff1Sjsg const u16 *send16 = sbuf16 + pixels;
214c349dbc7Sjsg
2151bb76ff1Sjsg while (sbuf16 < send16)
2161bb76ff1Sjsg *dbuf16++ = swab16(*sbuf16++);
217c349dbc7Sjsg }
2181bb76ff1Sjsg
drm_fb_swab32_line(void * dbuf,const void * sbuf,unsigned int pixels)2191bb76ff1Sjsg static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels)
2201bb76ff1Sjsg {
2211bb76ff1Sjsg u32 *dbuf32 = dbuf;
2221bb76ff1Sjsg const u32 *sbuf32 = sbuf;
2231bb76ff1Sjsg const u32 *send32 = sbuf32 + pixels;
2241bb76ff1Sjsg
2251bb76ff1Sjsg while (sbuf32 < send32)
2261bb76ff1Sjsg *dbuf32++ = swab32(*sbuf32++);
227c349dbc7Sjsg }
228c349dbc7Sjsg
229c349dbc7Sjsg /**
230ad8b1aafSjsg * drm_fb_swab - Swap bytes into clip buffer
2311bb76ff1Sjsg * @dst: Array of destination buffers
2321bb76ff1Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
2331bb76ff1Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
2341bb76ff1Sjsg * @src: Array of source buffers
235c349dbc7Sjsg * @fb: DRM framebuffer
236c349dbc7Sjsg * @clip: Clip rectangle area to copy
237ad8b1aafSjsg * @cached: Source buffer is mapped cached (eg. not write-combined)
238ad8b1aafSjsg *
2391bb76ff1Sjsg * This function copies parts of a framebuffer to display memory and swaps per-pixel
2401bb76ff1Sjsg * bytes during the process. Destination and framebuffer formats must match. The
2411bb76ff1Sjsg * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
2421bb76ff1Sjsg * least as many entries as there are planes in @fb's format. Each entry stores the
2431bb76ff1Sjsg * value for the format's respective color plane at the same index. If @cached is
2441bb76ff1Sjsg * false a temporary buffer is used to cache one pixel line at a time to speed up
2451bb76ff1Sjsg * slow uncached reads.
246ad8b1aafSjsg *
2471bb76ff1Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
2481bb76ff1Sjsg * top-left corner).
249c349dbc7Sjsg */
drm_fb_swab(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip,bool cached)2501bb76ff1Sjsg void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
2511bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
2521bb76ff1Sjsg const struct drm_rect *clip, bool cached)
253c349dbc7Sjsg {
2541bb76ff1Sjsg const struct drm_format_info *format = fb->format;
2551bb76ff1Sjsg u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8);
2561bb76ff1Sjsg void (*swab_line)(void *dbuf, const void *sbuf, unsigned int npixels);
257c349dbc7Sjsg
2581bb76ff1Sjsg switch (cpp) {
2591bb76ff1Sjsg case 4:
2601bb76ff1Sjsg swab_line = drm_fb_swab32_line;
2611bb76ff1Sjsg break;
2621bb76ff1Sjsg case 2:
2631bb76ff1Sjsg swab_line = drm_fb_swab16_line;
2641bb76ff1Sjsg break;
2651bb76ff1Sjsg default:
2661bb76ff1Sjsg drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n",
2671bb76ff1Sjsg &format->format);
268c349dbc7Sjsg return;
269ad8b1aafSjsg }
270ad8b1aafSjsg
2711bb76ff1Sjsg drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, swab_line);
272c349dbc7Sjsg }
273ad8b1aafSjsg EXPORT_SYMBOL(drm_fb_swab);
274c349dbc7Sjsg
drm_fb_xrgb8888_to_rgb332_line(void * dbuf,const void * sbuf,unsigned int pixels)2751bb76ff1Sjsg static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
276c349dbc7Sjsg {
2771bb76ff1Sjsg u8 *dbuf8 = dbuf;
2781bb76ff1Sjsg const __le32 *sbuf32 = sbuf;
279c349dbc7Sjsg unsigned int x;
2801bb76ff1Sjsg u32 pix;
281c349dbc7Sjsg
282c349dbc7Sjsg for (x = 0; x < pixels; x++) {
2831bb76ff1Sjsg pix = le32_to_cpu(sbuf32[x]);
2841bb76ff1Sjsg dbuf8[x] = ((pix & 0x00e00000) >> 16) |
2851bb76ff1Sjsg ((pix & 0x0000e000) >> 11) |
2861bb76ff1Sjsg ((pix & 0x000000c0) >> 6);
2871bb76ff1Sjsg }
2881bb76ff1Sjsg }
2891bb76ff1Sjsg
2901bb76ff1Sjsg /**
2911bb76ff1Sjsg * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer
2921bb76ff1Sjsg * @dst: Array of RGB332 destination buffers
2931bb76ff1Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
2941bb76ff1Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
2951bb76ff1Sjsg * @src: Array of XRGB8888 source buffers
2961bb76ff1Sjsg * @fb: DRM framebuffer
2971bb76ff1Sjsg * @clip: Clip rectangle area to copy
2981bb76ff1Sjsg *
2991bb76ff1Sjsg * This function copies parts of a framebuffer to display memory and converts the
3001bb76ff1Sjsg * color format during the process. Destination and framebuffer formats must match. The
3011bb76ff1Sjsg * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
3021bb76ff1Sjsg * least as many entries as there are planes in @fb's format. Each entry stores the
3031bb76ff1Sjsg * value for the format's respective color plane at the same index.
3041bb76ff1Sjsg *
3051bb76ff1Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
3061bb76ff1Sjsg * top-left corner).
3071bb76ff1Sjsg *
3081bb76ff1Sjsg * Drivers can use this function for RGB332 devices that don't support XRGB8888 natively.
3091bb76ff1Sjsg */
drm_fb_xrgb8888_to_rgb332(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)3101bb76ff1Sjsg void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
3111bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
3121bb76ff1Sjsg const struct drm_rect *clip)
3131bb76ff1Sjsg {
3141bb76ff1Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
3151bb76ff1Sjsg 1,
3161bb76ff1Sjsg };
3171bb76ff1Sjsg
3181bb76ff1Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
3191bb76ff1Sjsg drm_fb_xrgb8888_to_rgb332_line);
3201bb76ff1Sjsg }
3211bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);
3221bb76ff1Sjsg
drm_fb_xrgb8888_to_rgb565_line(void * dbuf,const void * sbuf,unsigned int pixels)3231bb76ff1Sjsg static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels)
3241bb76ff1Sjsg {
325*f005ef32Sjsg __le16 *dbuf16 = dbuf;
3261bb76ff1Sjsg const __le32 *sbuf32 = sbuf;
3271bb76ff1Sjsg unsigned int x;
3281bb76ff1Sjsg u16 val16;
3291bb76ff1Sjsg u32 pix;
3301bb76ff1Sjsg
3311bb76ff1Sjsg for (x = 0; x < pixels; x++) {
3321bb76ff1Sjsg pix = le32_to_cpu(sbuf32[x]);
3331bb76ff1Sjsg val16 = ((pix & 0x00F80000) >> 8) |
3341bb76ff1Sjsg ((pix & 0x0000FC00) >> 5) |
3351bb76ff1Sjsg ((pix & 0x000000F8) >> 3);
336*f005ef32Sjsg dbuf16[x] = cpu_to_le16(val16);
3371bb76ff1Sjsg }
3381bb76ff1Sjsg }
3391bb76ff1Sjsg
340*f005ef32Sjsg /* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */
drm_fb_xrgb8888_to_rgb565_swab_line(void * dbuf,const void * sbuf,unsigned int pixels)3411bb76ff1Sjsg static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
3421bb76ff1Sjsg unsigned int pixels)
3431bb76ff1Sjsg {
344*f005ef32Sjsg __le16 *dbuf16 = dbuf;
3451bb76ff1Sjsg const __le32 *sbuf32 = sbuf;
3461bb76ff1Sjsg unsigned int x;
3471bb76ff1Sjsg u16 val16;
3481bb76ff1Sjsg u32 pix;
3491bb76ff1Sjsg
3501bb76ff1Sjsg for (x = 0; x < pixels; x++) {
3511bb76ff1Sjsg pix = le32_to_cpu(sbuf32[x]);
3521bb76ff1Sjsg val16 = ((pix & 0x00F80000) >> 8) |
3531bb76ff1Sjsg ((pix & 0x0000FC00) >> 5) |
3541bb76ff1Sjsg ((pix & 0x000000F8) >> 3);
355*f005ef32Sjsg dbuf16[x] = cpu_to_le16(swab16(val16));
356c349dbc7Sjsg }
357c349dbc7Sjsg }
358c349dbc7Sjsg
359c349dbc7Sjsg /**
360c349dbc7Sjsg * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
3611bb76ff1Sjsg * @dst: Array of RGB565 destination buffers
3621bb76ff1Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
3631bb76ff1Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
3641bb76ff1Sjsg * @src: Array of XRGB8888 source buffer
365c349dbc7Sjsg * @fb: DRM framebuffer
366c349dbc7Sjsg * @clip: Clip rectangle area to copy
367c349dbc7Sjsg * @swab: Swap bytes
368c349dbc7Sjsg *
3691bb76ff1Sjsg * This function copies parts of a framebuffer to display memory and converts the
3701bb76ff1Sjsg * color format during the process. Destination and framebuffer formats must match. The
3711bb76ff1Sjsg * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
3721bb76ff1Sjsg * least as many entries as there are planes in @fb's format. Each entry stores the
3731bb76ff1Sjsg * value for the format's respective color plane at the same index.
374c349dbc7Sjsg *
3751bb76ff1Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
3761bb76ff1Sjsg * top-left corner).
3771bb76ff1Sjsg *
3781bb76ff1Sjsg * Drivers can use this function for RGB565 devices that don't support XRGB8888 natively.
379c349dbc7Sjsg */
drm_fb_xrgb8888_to_rgb565(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip,bool swab)3801bb76ff1Sjsg void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
3811bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
3821bb76ff1Sjsg const struct drm_rect *clip, bool swab)
383c349dbc7Sjsg {
3841bb76ff1Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
3851bb76ff1Sjsg 2,
3861bb76ff1Sjsg };
387c349dbc7Sjsg
3881bb76ff1Sjsg void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels);
389c349dbc7Sjsg
3901bb76ff1Sjsg if (swab)
3911bb76ff1Sjsg xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line;
3921bb76ff1Sjsg else
3931bb76ff1Sjsg xfrm_line = drm_fb_xrgb8888_to_rgb565_line;
394c349dbc7Sjsg
3951bb76ff1Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm_line);
396c349dbc7Sjsg }
397c349dbc7Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
398c349dbc7Sjsg
drm_fb_xrgb8888_to_xrgb1555_line(void * dbuf,const void * sbuf,unsigned int pixels)399*f005ef32Sjsg static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
400*f005ef32Sjsg {
401*f005ef32Sjsg __le16 *dbuf16 = dbuf;
402*f005ef32Sjsg const __le32 *sbuf32 = sbuf;
403*f005ef32Sjsg unsigned int x;
404*f005ef32Sjsg u16 val16;
405*f005ef32Sjsg u32 pix;
406*f005ef32Sjsg
407*f005ef32Sjsg for (x = 0; x < pixels; x++) {
408*f005ef32Sjsg pix = le32_to_cpu(sbuf32[x]);
409*f005ef32Sjsg val16 = ((pix & 0x00f80000) >> 9) |
410*f005ef32Sjsg ((pix & 0x0000f800) >> 6) |
411*f005ef32Sjsg ((pix & 0x000000f8) >> 3);
412*f005ef32Sjsg dbuf16[x] = cpu_to_le16(val16);
413*f005ef32Sjsg }
414*f005ef32Sjsg }
415*f005ef32Sjsg
416*f005ef32Sjsg /**
417*f005ef32Sjsg * drm_fb_xrgb8888_to_xrgb1555 - Convert XRGB8888 to XRGB1555 clip buffer
418*f005ef32Sjsg * @dst: Array of XRGB1555 destination buffers
419*f005ef32Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
420*f005ef32Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
421*f005ef32Sjsg * @src: Array of XRGB8888 source buffer
422*f005ef32Sjsg * @fb: DRM framebuffer
423*f005ef32Sjsg * @clip: Clip rectangle area to copy
424*f005ef32Sjsg *
425*f005ef32Sjsg * This function copies parts of a framebuffer to display memory and converts
426*f005ef32Sjsg * the color format during the process. The parameters @dst, @dst_pitch and
427*f005ef32Sjsg * @src refer to arrays. Each array must have at least as many entries as
428*f005ef32Sjsg * there are planes in @fb's format. Each entry stores the value for the
429*f005ef32Sjsg * format's respective color plane at the same index.
430*f005ef32Sjsg *
431*f005ef32Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
432*f005ef32Sjsg * top-left corner).
433*f005ef32Sjsg *
434*f005ef32Sjsg * Drivers can use this function for XRGB1555 devices that don't support
435*f005ef32Sjsg * XRGB8888 natively.
436*f005ef32Sjsg */
drm_fb_xrgb8888_to_xrgb1555(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)437*f005ef32Sjsg void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
438*f005ef32Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
439*f005ef32Sjsg const struct drm_rect *clip)
440*f005ef32Sjsg {
441*f005ef32Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
442*f005ef32Sjsg 2,
443*f005ef32Sjsg };
444*f005ef32Sjsg
445*f005ef32Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
446*f005ef32Sjsg drm_fb_xrgb8888_to_xrgb1555_line);
447*f005ef32Sjsg }
448*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555);
449*f005ef32Sjsg
drm_fb_xrgb8888_to_argb1555_line(void * dbuf,const void * sbuf,unsigned int pixels)450*f005ef32Sjsg static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
451*f005ef32Sjsg {
452*f005ef32Sjsg __le16 *dbuf16 = dbuf;
453*f005ef32Sjsg const __le32 *sbuf32 = sbuf;
454*f005ef32Sjsg unsigned int x;
455*f005ef32Sjsg u16 val16;
456*f005ef32Sjsg u32 pix;
457*f005ef32Sjsg
458*f005ef32Sjsg for (x = 0; x < pixels; x++) {
459*f005ef32Sjsg pix = le32_to_cpu(sbuf32[x]);
460*f005ef32Sjsg val16 = BIT(15) | /* set alpha bit */
461*f005ef32Sjsg ((pix & 0x00f80000) >> 9) |
462*f005ef32Sjsg ((pix & 0x0000f800) >> 6) |
463*f005ef32Sjsg ((pix & 0x000000f8) >> 3);
464*f005ef32Sjsg dbuf16[x] = cpu_to_le16(val16);
465*f005ef32Sjsg }
466*f005ef32Sjsg }
467*f005ef32Sjsg
468*f005ef32Sjsg /**
469*f005ef32Sjsg * drm_fb_xrgb8888_to_argb1555 - Convert XRGB8888 to ARGB1555 clip buffer
470*f005ef32Sjsg * @dst: Array of ARGB1555 destination buffers
471*f005ef32Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
472*f005ef32Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
473*f005ef32Sjsg * @src: Array of XRGB8888 source buffer
474*f005ef32Sjsg * @fb: DRM framebuffer
475*f005ef32Sjsg * @clip: Clip rectangle area to copy
476*f005ef32Sjsg *
477*f005ef32Sjsg * This function copies parts of a framebuffer to display memory and converts
478*f005ef32Sjsg * the color format during the process. The parameters @dst, @dst_pitch and
479*f005ef32Sjsg * @src refer to arrays. Each array must have at least as many entries as
480*f005ef32Sjsg * there are planes in @fb's format. Each entry stores the value for the
481*f005ef32Sjsg * format's respective color plane at the same index.
482*f005ef32Sjsg *
483*f005ef32Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
484*f005ef32Sjsg * top-left corner).
485*f005ef32Sjsg *
486*f005ef32Sjsg * Drivers can use this function for ARGB1555 devices that don't support
487*f005ef32Sjsg * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
488*f005ef32Sjsg */
drm_fb_xrgb8888_to_argb1555(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)489*f005ef32Sjsg void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
490*f005ef32Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
491*f005ef32Sjsg const struct drm_rect *clip)
492*f005ef32Sjsg {
493*f005ef32Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
494*f005ef32Sjsg 2,
495*f005ef32Sjsg };
496*f005ef32Sjsg
497*f005ef32Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
498*f005ef32Sjsg drm_fb_xrgb8888_to_argb1555_line);
499*f005ef32Sjsg }
500*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555);
501*f005ef32Sjsg
drm_fb_xrgb8888_to_rgba5551_line(void * dbuf,const void * sbuf,unsigned int pixels)502*f005ef32Sjsg static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsigned int pixels)
503*f005ef32Sjsg {
504*f005ef32Sjsg __le16 *dbuf16 = dbuf;
505*f005ef32Sjsg const __le32 *sbuf32 = sbuf;
506*f005ef32Sjsg unsigned int x;
507*f005ef32Sjsg u16 val16;
508*f005ef32Sjsg u32 pix;
509*f005ef32Sjsg
510*f005ef32Sjsg for (x = 0; x < pixels; x++) {
511*f005ef32Sjsg pix = le32_to_cpu(sbuf32[x]);
512*f005ef32Sjsg val16 = ((pix & 0x00f80000) >> 8) |
513*f005ef32Sjsg ((pix & 0x0000f800) >> 5) |
514*f005ef32Sjsg ((pix & 0x000000f8) >> 2) |
515*f005ef32Sjsg BIT(0); /* set alpha bit */
516*f005ef32Sjsg dbuf16[x] = cpu_to_le16(val16);
517*f005ef32Sjsg }
518*f005ef32Sjsg }
519*f005ef32Sjsg
520*f005ef32Sjsg /**
521*f005ef32Sjsg * drm_fb_xrgb8888_to_rgba5551 - Convert XRGB8888 to RGBA5551 clip buffer
522*f005ef32Sjsg * @dst: Array of RGBA5551 destination buffers
523*f005ef32Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
524*f005ef32Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
525*f005ef32Sjsg * @src: Array of XRGB8888 source buffer
526*f005ef32Sjsg * @fb: DRM framebuffer
527*f005ef32Sjsg * @clip: Clip rectangle area to copy
528*f005ef32Sjsg *
529*f005ef32Sjsg * This function copies parts of a framebuffer to display memory and converts
530*f005ef32Sjsg * the color format during the process. The parameters @dst, @dst_pitch and
531*f005ef32Sjsg * @src refer to arrays. Each array must have at least as many entries as
532*f005ef32Sjsg * there are planes in @fb's format. Each entry stores the value for the
533*f005ef32Sjsg * format's respective color plane at the same index.
534*f005ef32Sjsg *
535*f005ef32Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
536*f005ef32Sjsg * top-left corner).
537*f005ef32Sjsg *
538*f005ef32Sjsg * Drivers can use this function for RGBA5551 devices that don't support
539*f005ef32Sjsg * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
540*f005ef32Sjsg */
drm_fb_xrgb8888_to_rgba5551(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)541*f005ef32Sjsg void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch,
542*f005ef32Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
543*f005ef32Sjsg const struct drm_rect *clip)
544*f005ef32Sjsg {
545*f005ef32Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
546*f005ef32Sjsg 2,
547*f005ef32Sjsg };
548*f005ef32Sjsg
549*f005ef32Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
550*f005ef32Sjsg drm_fb_xrgb8888_to_rgba5551_line);
551*f005ef32Sjsg }
552*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551);
553*f005ef32Sjsg
drm_fb_xrgb8888_to_rgb888_line(void * dbuf,const void * sbuf,unsigned int pixels)5541bb76ff1Sjsg static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels)
555c349dbc7Sjsg {
5561bb76ff1Sjsg u8 *dbuf8 = dbuf;
5571bb76ff1Sjsg const __le32 *sbuf32 = sbuf;
558c349dbc7Sjsg unsigned int x;
5591bb76ff1Sjsg u32 pix;
560c349dbc7Sjsg
561c349dbc7Sjsg for (x = 0; x < pixels; x++) {
5621bb76ff1Sjsg pix = le32_to_cpu(sbuf32[x]);
563*f005ef32Sjsg /* write blue-green-red to output in little endianness */
5641bb76ff1Sjsg *dbuf8++ = (pix & 0x000000FF) >> 0;
5651bb76ff1Sjsg *dbuf8++ = (pix & 0x0000FF00) >> 8;
5661bb76ff1Sjsg *dbuf8++ = (pix & 0x00FF0000) >> 16;
567c349dbc7Sjsg }
568c349dbc7Sjsg }
569c349dbc7Sjsg
570c349dbc7Sjsg /**
5711bb76ff1Sjsg * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer
5721bb76ff1Sjsg * @dst: Array of RGB888 destination buffers
5731bb76ff1Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
5741bb76ff1Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
5751bb76ff1Sjsg * @src: Array of XRGB8888 source buffers
576c349dbc7Sjsg * @fb: DRM framebuffer
577c349dbc7Sjsg * @clip: Clip rectangle area to copy
578c349dbc7Sjsg *
5791bb76ff1Sjsg * This function copies parts of a framebuffer to display memory and converts the
5801bb76ff1Sjsg * color format during the process. Destination and framebuffer formats must match. The
5811bb76ff1Sjsg * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
5821bb76ff1Sjsg * least as many entries as there are planes in @fb's format. Each entry stores the
5831bb76ff1Sjsg * value for the format's respective color plane at the same index.
5841bb76ff1Sjsg *
5851bb76ff1Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
5861bb76ff1Sjsg * top-left corner).
5871bb76ff1Sjsg *
588c349dbc7Sjsg * Drivers can use this function for RGB888 devices that don't natively
589c349dbc7Sjsg * support XRGB8888.
590c349dbc7Sjsg */
drm_fb_xrgb8888_to_rgb888(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)5911bb76ff1Sjsg void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch,
5921bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
5931bb76ff1Sjsg const struct drm_rect *clip)
594c349dbc7Sjsg {
5951bb76ff1Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
5961bb76ff1Sjsg 3,
5971bb76ff1Sjsg };
598c349dbc7Sjsg
5991bb76ff1Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
6001bb76ff1Sjsg drm_fb_xrgb8888_to_rgb888_line);
6011bb76ff1Sjsg }
6021bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
603c349dbc7Sjsg
drm_fb_xrgb8888_to_argb8888_line(void * dbuf,const void * sbuf,unsigned int pixels)604*f005ef32Sjsg static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
6051bb76ff1Sjsg {
6061bb76ff1Sjsg __le32 *dbuf32 = dbuf;
607*f005ef32Sjsg const __le32 *sbuf32 = sbuf;
6081bb76ff1Sjsg unsigned int x;
609*f005ef32Sjsg u32 pix;
6101bb76ff1Sjsg
6111bb76ff1Sjsg for (x = 0; x < pixels; x++) {
612*f005ef32Sjsg pix = le32_to_cpu(sbuf32[x]);
613*f005ef32Sjsg pix |= GENMASK(31, 24); /* fill alpha bits */
6141bb76ff1Sjsg dbuf32[x] = cpu_to_le32(pix);
6151bb76ff1Sjsg }
6161bb76ff1Sjsg }
6171bb76ff1Sjsg
618*f005ef32Sjsg /**
619*f005ef32Sjsg * drm_fb_xrgb8888_to_argb8888 - Convert XRGB8888 to ARGB8888 clip buffer
620*f005ef32Sjsg * @dst: Array of ARGB8888 destination buffers
621*f005ef32Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
622*f005ef32Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
623*f005ef32Sjsg * @src: Array of XRGB8888 source buffer
624*f005ef32Sjsg * @fb: DRM framebuffer
625*f005ef32Sjsg * @clip: Clip rectangle area to copy
626*f005ef32Sjsg *
627*f005ef32Sjsg * This function copies parts of a framebuffer to display memory and converts the
628*f005ef32Sjsg * color format during the process. The parameters @dst, @dst_pitch and @src refer
629*f005ef32Sjsg * to arrays. Each array must have at least as many entries as there are planes in
630*f005ef32Sjsg * @fb's format. Each entry stores the value for the format's respective color plane
631*f005ef32Sjsg * at the same index.
632*f005ef32Sjsg *
633*f005ef32Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
634*f005ef32Sjsg * top-left corner).
635*f005ef32Sjsg *
636*f005ef32Sjsg * Drivers can use this function for ARGB8888 devices that don't support XRGB8888
637*f005ef32Sjsg * natively. It sets an opaque alpha channel as part of the conversion.
638*f005ef32Sjsg */
drm_fb_xrgb8888_to_argb8888(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)639*f005ef32Sjsg void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
640*f005ef32Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
641*f005ef32Sjsg const struct drm_rect *clip)
642*f005ef32Sjsg {
643*f005ef32Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
644*f005ef32Sjsg 4,
645*f005ef32Sjsg };
646*f005ef32Sjsg
647*f005ef32Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
648*f005ef32Sjsg drm_fb_xrgb8888_to_argb8888_line);
649*f005ef32Sjsg }
650*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888);
651*f005ef32Sjsg
drm_fb_xrgb8888_to_abgr8888_line(void * dbuf,const void * sbuf,unsigned int pixels)652*f005ef32Sjsg static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
653*f005ef32Sjsg {
654*f005ef32Sjsg __le32 *dbuf32 = dbuf;
655*f005ef32Sjsg const __le32 *sbuf32 = sbuf;
656*f005ef32Sjsg unsigned int x;
657*f005ef32Sjsg u32 pix;
658*f005ef32Sjsg
659*f005ef32Sjsg for (x = 0; x < pixels; x++) {
660*f005ef32Sjsg pix = le32_to_cpu(sbuf32[x]);
661*f005ef32Sjsg pix = ((pix & 0x00ff0000) >> 16) << 0 |
662*f005ef32Sjsg ((pix & 0x0000ff00) >> 8) << 8 |
663*f005ef32Sjsg ((pix & 0x000000ff) >> 0) << 16 |
664*f005ef32Sjsg GENMASK(31, 24); /* fill alpha bits */
665*f005ef32Sjsg *dbuf32++ = cpu_to_le32(pix);
666*f005ef32Sjsg }
667*f005ef32Sjsg }
668*f005ef32Sjsg
drm_fb_xrgb8888_to_abgr8888(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)669*f005ef32Sjsg static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
6701bb76ff1Sjsg const struct iosys_map *src,
6711bb76ff1Sjsg const struct drm_framebuffer *fb,
6721bb76ff1Sjsg const struct drm_rect *clip)
6731bb76ff1Sjsg {
6741bb76ff1Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
6751bb76ff1Sjsg 4,
6761bb76ff1Sjsg };
6771bb76ff1Sjsg
6781bb76ff1Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
679*f005ef32Sjsg drm_fb_xrgb8888_to_abgr8888_line);
680*f005ef32Sjsg }
681*f005ef32Sjsg
drm_fb_xrgb8888_to_xbgr8888_line(void * dbuf,const void * sbuf,unsigned int pixels)682*f005ef32Sjsg static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
683*f005ef32Sjsg {
684*f005ef32Sjsg __le32 *dbuf32 = dbuf;
685*f005ef32Sjsg const __le32 *sbuf32 = sbuf;
686*f005ef32Sjsg unsigned int x;
687*f005ef32Sjsg u32 pix;
688*f005ef32Sjsg
689*f005ef32Sjsg for (x = 0; x < pixels; x++) {
690*f005ef32Sjsg pix = le32_to_cpu(sbuf32[x]);
691*f005ef32Sjsg pix = ((pix & 0x00ff0000) >> 16) << 0 |
692*f005ef32Sjsg ((pix & 0x0000ff00) >> 8) << 8 |
693*f005ef32Sjsg ((pix & 0x000000ff) >> 0) << 16 |
694*f005ef32Sjsg ((pix & 0xff000000) >> 24) << 24;
695*f005ef32Sjsg *dbuf32++ = cpu_to_le32(pix);
696*f005ef32Sjsg }
697*f005ef32Sjsg }
698*f005ef32Sjsg
drm_fb_xrgb8888_to_xbgr8888(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)699*f005ef32Sjsg static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
700*f005ef32Sjsg const struct iosys_map *src,
701*f005ef32Sjsg const struct drm_framebuffer *fb,
702*f005ef32Sjsg const struct drm_rect *clip)
703*f005ef32Sjsg {
704*f005ef32Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
705*f005ef32Sjsg 4,
706*f005ef32Sjsg };
707*f005ef32Sjsg
708*f005ef32Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
709*f005ef32Sjsg drm_fb_xrgb8888_to_xbgr8888_line);
7101bb76ff1Sjsg }
7111bb76ff1Sjsg
drm_fb_xrgb8888_to_xrgb2101010_line(void * dbuf,const void * sbuf,unsigned int pixels)7121bb76ff1Sjsg static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
7131bb76ff1Sjsg {
7141bb76ff1Sjsg __le32 *dbuf32 = dbuf;
7151bb76ff1Sjsg const __le32 *sbuf32 = sbuf;
7161bb76ff1Sjsg unsigned int x;
7171bb76ff1Sjsg u32 val32;
7181bb76ff1Sjsg u32 pix;
7191bb76ff1Sjsg
7201bb76ff1Sjsg for (x = 0; x < pixels; x++) {
7211bb76ff1Sjsg pix = le32_to_cpu(sbuf32[x]);
7221bb76ff1Sjsg val32 = ((pix & 0x000000FF) << 2) |
7231bb76ff1Sjsg ((pix & 0x0000FF00) << 4) |
7241bb76ff1Sjsg ((pix & 0x00FF0000) << 6);
7251bb76ff1Sjsg pix = val32 | ((val32 >> 8) & 0x00300C03);
7261bb76ff1Sjsg *dbuf32++ = cpu_to_le32(pix);
7271bb76ff1Sjsg }
7281bb76ff1Sjsg }
729c349dbc7Sjsg
730c349dbc7Sjsg /**
7311bb76ff1Sjsg * drm_fb_xrgb8888_to_xrgb2101010 - Convert XRGB8888 to XRGB2101010 clip buffer
7321bb76ff1Sjsg * @dst: Array of XRGB2101010 destination buffers
7331bb76ff1Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
7341bb76ff1Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
7351bb76ff1Sjsg * @src: Array of XRGB8888 source buffers
736c349dbc7Sjsg * @fb: DRM framebuffer
737c349dbc7Sjsg * @clip: Clip rectangle area to copy
738c349dbc7Sjsg *
7391bb76ff1Sjsg * This function copies parts of a framebuffer to display memory and converts the
7401bb76ff1Sjsg * color format during the process. Destination and framebuffer formats must match. The
7411bb76ff1Sjsg * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
7421bb76ff1Sjsg * least as many entries as there are planes in @fb's format. Each entry stores the
7431bb76ff1Sjsg * value for the format's respective color plane at the same index.
744c349dbc7Sjsg *
7451bb76ff1Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
7461bb76ff1Sjsg * top-left corner).
747c349dbc7Sjsg *
7481bb76ff1Sjsg * Drivers can use this function for XRGB2101010 devices that don't support XRGB8888
7491bb76ff1Sjsg * natively.
750c349dbc7Sjsg */
drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)7511bb76ff1Sjsg void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
7521bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
7531bb76ff1Sjsg const struct drm_rect *clip)
754c349dbc7Sjsg {
7551bb76ff1Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
7561bb76ff1Sjsg 4,
7571bb76ff1Sjsg };
758c349dbc7Sjsg
7591bb76ff1Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
7601bb76ff1Sjsg drm_fb_xrgb8888_to_xrgb2101010_line);
7611bb76ff1Sjsg }
7621bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010);
763c349dbc7Sjsg
drm_fb_xrgb8888_to_argb2101010_line(void * dbuf,const void * sbuf,unsigned int pixels)764*f005ef32Sjsg static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
765*f005ef32Sjsg {
766*f005ef32Sjsg __le32 *dbuf32 = dbuf;
767*f005ef32Sjsg const __le32 *sbuf32 = sbuf;
768*f005ef32Sjsg unsigned int x;
769*f005ef32Sjsg u32 val32;
770*f005ef32Sjsg u32 pix;
771*f005ef32Sjsg
772*f005ef32Sjsg for (x = 0; x < pixels; x++) {
773*f005ef32Sjsg pix = le32_to_cpu(sbuf32[x]);
774*f005ef32Sjsg val32 = ((pix & 0x000000ff) << 2) |
775*f005ef32Sjsg ((pix & 0x0000ff00) << 4) |
776*f005ef32Sjsg ((pix & 0x00ff0000) << 6);
777*f005ef32Sjsg pix = GENMASK(31, 30) | /* set alpha bits */
778*f005ef32Sjsg val32 | ((val32 >> 8) & 0x00300c03);
779*f005ef32Sjsg *dbuf32++ = cpu_to_le32(pix);
780*f005ef32Sjsg }
781*f005ef32Sjsg }
782*f005ef32Sjsg
783*f005ef32Sjsg /**
784*f005ef32Sjsg * drm_fb_xrgb8888_to_argb2101010 - Convert XRGB8888 to ARGB2101010 clip buffer
785*f005ef32Sjsg * @dst: Array of ARGB2101010 destination buffers
786*f005ef32Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
787*f005ef32Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
788*f005ef32Sjsg * @src: Array of XRGB8888 source buffers
789*f005ef32Sjsg * @fb: DRM framebuffer
790*f005ef32Sjsg * @clip: Clip rectangle area to copy
791*f005ef32Sjsg *
792*f005ef32Sjsg * This function copies parts of a framebuffer to display memory and converts
793*f005ef32Sjsg * the color format during the process. The parameters @dst, @dst_pitch and
794*f005ef32Sjsg * @src refer to arrays. Each array must have at least as many entries as
795*f005ef32Sjsg * there are planes in @fb's format. Each entry stores the value for the
796*f005ef32Sjsg * format's respective color plane at the same index.
797*f005ef32Sjsg *
798*f005ef32Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
799*f005ef32Sjsg * top-left corner).
800*f005ef32Sjsg *
801*f005ef32Sjsg * Drivers can use this function for ARGB2101010 devices that don't support XRGB8888
802*f005ef32Sjsg * natively.
803*f005ef32Sjsg */
drm_fb_xrgb8888_to_argb2101010(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)804*f005ef32Sjsg void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
805*f005ef32Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
806*f005ef32Sjsg const struct drm_rect *clip)
807*f005ef32Sjsg {
808*f005ef32Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
809*f005ef32Sjsg 4,
810*f005ef32Sjsg };
811*f005ef32Sjsg
812*f005ef32Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
813*f005ef32Sjsg drm_fb_xrgb8888_to_argb2101010_line);
814*f005ef32Sjsg }
815*f005ef32Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010);
816*f005ef32Sjsg
drm_fb_xrgb8888_to_gray8_line(void * dbuf,const void * sbuf,unsigned int pixels)8171bb76ff1Sjsg static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels)
8181bb76ff1Sjsg {
8191bb76ff1Sjsg u8 *dbuf8 = dbuf;
8201bb76ff1Sjsg const __le32 *sbuf32 = sbuf;
8211bb76ff1Sjsg unsigned int x;
8221bb76ff1Sjsg
8231bb76ff1Sjsg for (x = 0; x < pixels; x++) {
8241bb76ff1Sjsg u32 pix = le32_to_cpu(sbuf32[x]);
8251bb76ff1Sjsg u8 r = (pix & 0x00ff0000) >> 16;
8261bb76ff1Sjsg u8 g = (pix & 0x0000ff00) >> 8;
8271bb76ff1Sjsg u8 b = pix & 0x000000ff;
828c349dbc7Sjsg
829c349dbc7Sjsg /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
8301bb76ff1Sjsg *dbuf8++ = (3 * r + 6 * g + b) / 10;
831c349dbc7Sjsg }
832c349dbc7Sjsg }
833c349dbc7Sjsg
8341bb76ff1Sjsg /**
8351bb76ff1Sjsg * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
8361bb76ff1Sjsg * @dst: Array of 8-bit grayscale destination buffers
8371bb76ff1Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
8381bb76ff1Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
8391bb76ff1Sjsg * @src: Array of XRGB8888 source buffers
8401bb76ff1Sjsg * @fb: DRM framebuffer
8411bb76ff1Sjsg * @clip: Clip rectangle area to copy
8421bb76ff1Sjsg *
8431bb76ff1Sjsg * This function copies parts of a framebuffer to display memory and converts the
8441bb76ff1Sjsg * color format during the process. Destination and framebuffer formats must match. The
8451bb76ff1Sjsg * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
8461bb76ff1Sjsg * least as many entries as there are planes in @fb's format. Each entry stores the
8471bb76ff1Sjsg * value for the format's respective color plane at the same index.
8481bb76ff1Sjsg *
8491bb76ff1Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
8501bb76ff1Sjsg * top-left corner).
8511bb76ff1Sjsg *
8521bb76ff1Sjsg * DRM doesn't have native monochrome or grayscale support. Drivers can use this
8531bb76ff1Sjsg * function for grayscale devices that don't support XRGB8888 natively.Such
8541bb76ff1Sjsg * drivers can announce the commonly supported XR24 format to userspace and use
8551bb76ff1Sjsg * this function to convert to the native format. Monochrome drivers will use the
8561bb76ff1Sjsg * most significant bit, where 1 means foreground color and 0 background color.
8571bb76ff1Sjsg * ITU BT.601 is being used for the RGB -> luma (brightness) conversion.
8581bb76ff1Sjsg */
drm_fb_xrgb8888_to_gray8(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)8591bb76ff1Sjsg void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch,
8601bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
8611bb76ff1Sjsg const struct drm_rect *clip)
8621bb76ff1Sjsg {
8631bb76ff1Sjsg static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
8641bb76ff1Sjsg 1,
8651bb76ff1Sjsg };
8661bb76ff1Sjsg
8671bb76ff1Sjsg drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
8681bb76ff1Sjsg drm_fb_xrgb8888_to_gray8_line);
869c349dbc7Sjsg }
870c349dbc7Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
871c349dbc7Sjsg
8725ca02815Sjsg /**
8731bb76ff1Sjsg * drm_fb_blit - Copy parts of a framebuffer to display memory
8741bb76ff1Sjsg * @dst: Array of display-memory addresses to copy to
8751bb76ff1Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
8761bb76ff1Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
8775ca02815Sjsg * @dst_format: FOURCC code of the display's color format
8781bb76ff1Sjsg * @src: The framebuffer memory to copy from
8795ca02815Sjsg * @fb: The framebuffer to copy from
8805ca02815Sjsg * @clip: Clip rectangle area to copy
8815ca02815Sjsg *
8825ca02815Sjsg * This function copies parts of a framebuffer to display memory. If the
8835ca02815Sjsg * formats of the display and the framebuffer mismatch, the blit function
8841bb76ff1Sjsg * will attempt to convert between them during the process. The parameters @dst,
8851bb76ff1Sjsg * @dst_pitch and @src refer to arrays. Each array must have at least as many
8861bb76ff1Sjsg * entries as there are planes in @dst_format's format. Each entry stores the
8871bb76ff1Sjsg * value for the format's respective color plane at the same index.
8885ca02815Sjsg *
8891bb76ff1Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
8901bb76ff1Sjsg * top-left corner).
8915ca02815Sjsg *
8925ca02815Sjsg * Returns:
8935ca02815Sjsg * 0 on success, or
8945ca02815Sjsg * -EINVAL if the color-format conversion failed, or
8955ca02815Sjsg * a negative error code otherwise.
8965ca02815Sjsg */
drm_fb_blit(struct iosys_map * dst,const unsigned int * dst_pitch,uint32_t dst_format,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)8971bb76ff1Sjsg int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format,
8981bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
8991bb76ff1Sjsg const struct drm_rect *clip)
9005ca02815Sjsg {
9015ca02815Sjsg uint32_t fb_format = fb->format->format;
9025ca02815Sjsg
903*f005ef32Sjsg if (fb_format == dst_format) {
9041bb76ff1Sjsg drm_fb_memcpy(dst, dst_pitch, src, fb, clip);
9055ca02815Sjsg return 0;
906*f005ef32Sjsg } else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) {
907*f005ef32Sjsg drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
908*f005ef32Sjsg return 0;
909*f005ef32Sjsg } else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) {
910*f005ef32Sjsg drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
911*f005ef32Sjsg return 0;
912*f005ef32Sjsg } else if (fb_format == DRM_FORMAT_XRGB8888) {
913*f005ef32Sjsg if (dst_format == DRM_FORMAT_RGB565) {
9141bb76ff1Sjsg drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false);
9155ca02815Sjsg return 0;
916*f005ef32Sjsg } else if (dst_format == DRM_FORMAT_XRGB1555) {
917*f005ef32Sjsg drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip);
918*f005ef32Sjsg return 0;
919*f005ef32Sjsg } else if (dst_format == DRM_FORMAT_ARGB1555) {
920*f005ef32Sjsg drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip);
921*f005ef32Sjsg return 0;
922*f005ef32Sjsg } else if (dst_format == DRM_FORMAT_RGBA5551) {
923*f005ef32Sjsg drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip);
924*f005ef32Sjsg return 0;
9255ca02815Sjsg } else if (dst_format == DRM_FORMAT_RGB888) {
9261bb76ff1Sjsg drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip);
9271bb76ff1Sjsg return 0;
928*f005ef32Sjsg } else if (dst_format == DRM_FORMAT_ARGB8888) {
929*f005ef32Sjsg drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip);
9301bb76ff1Sjsg return 0;
931*f005ef32Sjsg } else if (dst_format == DRM_FORMAT_XBGR8888) {
932*f005ef32Sjsg drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip);
9331bb76ff1Sjsg return 0;
934*f005ef32Sjsg } else if (dst_format == DRM_FORMAT_ABGR8888) {
935*f005ef32Sjsg drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip);
936*f005ef32Sjsg return 0;
9371bb76ff1Sjsg } else if (dst_format == DRM_FORMAT_XRGB2101010) {
9381bb76ff1Sjsg drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip);
9395ca02815Sjsg return 0;
940*f005ef32Sjsg } else if (dst_format == DRM_FORMAT_ARGB2101010) {
941*f005ef32Sjsg drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip);
942*f005ef32Sjsg return 0;
943*f005ef32Sjsg } else if (dst_format == DRM_FORMAT_BGRX8888) {
944*f005ef32Sjsg drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
945*f005ef32Sjsg return 0;
9465ca02815Sjsg }
9475ca02815Sjsg }
9485ca02815Sjsg
9491bb76ff1Sjsg drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n",
9501bb76ff1Sjsg &fb_format, &dst_format);
9511bb76ff1Sjsg
9525ca02815Sjsg return -EINVAL;
9535ca02815Sjsg }
9541bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_blit);
9551bb76ff1Sjsg
drm_fb_gray8_to_mono_line(void * dbuf,const void * sbuf,unsigned int pixels)9561bb76ff1Sjsg static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int pixels)
9571bb76ff1Sjsg {
9581bb76ff1Sjsg u8 *dbuf8 = dbuf;
9591bb76ff1Sjsg const u8 *sbuf8 = sbuf;
9601bb76ff1Sjsg
9611bb76ff1Sjsg while (pixels) {
9621bb76ff1Sjsg unsigned int i, bits = min(pixels, 8U);
9631bb76ff1Sjsg u8 byte = 0;
9641bb76ff1Sjsg
9651bb76ff1Sjsg for (i = 0; i < bits; i++, pixels--) {
9661bb76ff1Sjsg if (*sbuf8++ >= 128)
9671bb76ff1Sjsg byte |= BIT(i);
9681bb76ff1Sjsg }
9691bb76ff1Sjsg *dbuf8++ = byte;
9701bb76ff1Sjsg }
9711bb76ff1Sjsg }
9725ca02815Sjsg
9735ca02815Sjsg /**
9741bb76ff1Sjsg * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome
9751bb76ff1Sjsg * @dst: Array of monochrome destination buffers (0=black, 1=white)
9761bb76ff1Sjsg * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
9771bb76ff1Sjsg * within @dst; can be NULL if scanlines are stored next to each other.
9781bb76ff1Sjsg * @src: Array of XRGB8888 source buffers
9791bb76ff1Sjsg * @fb: DRM framebuffer
9801bb76ff1Sjsg * @clip: Clip rectangle area to copy
9815ca02815Sjsg *
9821bb76ff1Sjsg * This function copies parts of a framebuffer to display memory and converts the
9831bb76ff1Sjsg * color format during the process. Destination and framebuffer formats must match. The
9841bb76ff1Sjsg * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
9851bb76ff1Sjsg * least as many entries as there are planes in @fb's format. Each entry stores the
9861bb76ff1Sjsg * value for the format's respective color plane at the same index.
9875ca02815Sjsg *
9881bb76ff1Sjsg * This function does not apply clipping on @dst (i.e. the destination is at the
9891bb76ff1Sjsg * top-left corner). The first pixel (upper left corner of the clip rectangle) will
9901bb76ff1Sjsg * be converted and copied to the first bit (LSB) in the first byte of the monochrome
9911bb76ff1Sjsg * destination buffer. If the caller requires that the first pixel in a byte must
9921bb76ff1Sjsg * be located at an x-coordinate that is a multiple of 8, then the caller must take
9931bb76ff1Sjsg * care itself of supplying a suitable clip rectangle.
9941bb76ff1Sjsg *
9951bb76ff1Sjsg * DRM doesn't have native monochrome support. Drivers can use this function for
9961bb76ff1Sjsg * monochrome devices that don't support XRGB8888 natively. Such drivers can
9971bb76ff1Sjsg * announce the commonly supported XR24 format to userspace and use this function
9981bb76ff1Sjsg * to convert to the native format.
9991bb76ff1Sjsg *
10001bb76ff1Sjsg * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and
10011bb76ff1Sjsg * then the result is converted from grayscale to monochrome.
10021bb76ff1Sjsg */
drm_fb_xrgb8888_to_mono(struct iosys_map * dst,const unsigned int * dst_pitch,const struct iosys_map * src,const struct drm_framebuffer * fb,const struct drm_rect * clip)10031bb76ff1Sjsg void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch,
10041bb76ff1Sjsg const struct iosys_map *src, const struct drm_framebuffer *fb,
10051bb76ff1Sjsg const struct drm_rect *clip)
10061bb76ff1Sjsg {
10071bb76ff1Sjsg static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
10081bb76ff1Sjsg 0, 0, 0, 0
10091bb76ff1Sjsg };
10101bb76ff1Sjsg unsigned int linepixels = drm_rect_width(clip);
10111bb76ff1Sjsg unsigned int lines = drm_rect_height(clip);
10121bb76ff1Sjsg unsigned int cpp = fb->format->cpp[0];
10131bb76ff1Sjsg unsigned int len_src32 = linepixels * cpp;
10141bb76ff1Sjsg struct drm_device *dev = fb->dev;
10151bb76ff1Sjsg void *vaddr = src[0].vaddr;
10161bb76ff1Sjsg unsigned int dst_pitch_0;
10171bb76ff1Sjsg unsigned int y;
10181bb76ff1Sjsg u8 *mono = dst[0].vaddr, *gray8;
10191bb76ff1Sjsg u32 *src32;
10201bb76ff1Sjsg
10211bb76ff1Sjsg if (drm_WARN_ON(dev, fb->format->format != DRM_FORMAT_XRGB8888))
10221bb76ff1Sjsg return;
10231bb76ff1Sjsg
10241bb76ff1Sjsg if (!dst_pitch)
10251bb76ff1Sjsg dst_pitch = default_dst_pitch;
10261bb76ff1Sjsg dst_pitch_0 = dst_pitch[0];
10271bb76ff1Sjsg
10281bb76ff1Sjsg /*
10291bb76ff1Sjsg * The mono destination buffer contains 1 bit per pixel
10301bb76ff1Sjsg */
10311bb76ff1Sjsg if (!dst_pitch_0)
10321bb76ff1Sjsg dst_pitch_0 = DIV_ROUND_UP(linepixels, 8);
10331bb76ff1Sjsg
10341bb76ff1Sjsg /*
10351bb76ff1Sjsg * The dma memory is write-combined so reads are uncached.
10361bb76ff1Sjsg * Speed up by fetching one line at a time.
10371bb76ff1Sjsg *
10381bb76ff1Sjsg * Also, format conversion from XR24 to monochrome are done
10391bb76ff1Sjsg * line-by-line but are converted to 8-bit grayscale as an
10401bb76ff1Sjsg * intermediate step.
10411bb76ff1Sjsg *
10421bb76ff1Sjsg * Allocate a buffer to be used for both copying from the cma
10431bb76ff1Sjsg * memory and to store the intermediate grayscale line pixels.
10441bb76ff1Sjsg */
10451bb76ff1Sjsg src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);
10461bb76ff1Sjsg if (!src32)
10471bb76ff1Sjsg return;
10481bb76ff1Sjsg
10491bb76ff1Sjsg gray8 = (u8 *)src32 + len_src32;
10501bb76ff1Sjsg
10511bb76ff1Sjsg vaddr += clip_offset(clip, fb->pitches[0], cpp);
10521bb76ff1Sjsg for (y = 0; y < lines; y++) {
10531bb76ff1Sjsg src32 = memcpy(src32, vaddr, len_src32);
10541bb76ff1Sjsg drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels);
10551bb76ff1Sjsg drm_fb_gray8_to_mono_line(mono, gray8, linepixels);
10561bb76ff1Sjsg vaddr += fb->pitches[0];
10571bb76ff1Sjsg mono += dst_pitch_0;
10581bb76ff1Sjsg }
10591bb76ff1Sjsg
10601bb76ff1Sjsg kfree(src32);
10611bb76ff1Sjsg }
10621bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
10631bb76ff1Sjsg
drm_fb_nonalpha_fourcc(uint32_t fourcc)1064*f005ef32Sjsg static uint32_t drm_fb_nonalpha_fourcc(uint32_t fourcc)
1065*f005ef32Sjsg {
1066*f005ef32Sjsg /* only handle formats with depth != 0 and alpha channel */
1067*f005ef32Sjsg switch (fourcc) {
1068*f005ef32Sjsg case DRM_FORMAT_ARGB1555:
1069*f005ef32Sjsg return DRM_FORMAT_XRGB1555;
1070*f005ef32Sjsg case DRM_FORMAT_ABGR1555:
1071*f005ef32Sjsg return DRM_FORMAT_XBGR1555;
1072*f005ef32Sjsg case DRM_FORMAT_RGBA5551:
1073*f005ef32Sjsg return DRM_FORMAT_RGBX5551;
1074*f005ef32Sjsg case DRM_FORMAT_BGRA5551:
1075*f005ef32Sjsg return DRM_FORMAT_BGRX5551;
1076*f005ef32Sjsg case DRM_FORMAT_ARGB8888:
1077*f005ef32Sjsg return DRM_FORMAT_XRGB8888;
1078*f005ef32Sjsg case DRM_FORMAT_ABGR8888:
1079*f005ef32Sjsg return DRM_FORMAT_XBGR8888;
1080*f005ef32Sjsg case DRM_FORMAT_RGBA8888:
1081*f005ef32Sjsg return DRM_FORMAT_RGBX8888;
1082*f005ef32Sjsg case DRM_FORMAT_BGRA8888:
1083*f005ef32Sjsg return DRM_FORMAT_BGRX8888;
1084*f005ef32Sjsg case DRM_FORMAT_ARGB2101010:
1085*f005ef32Sjsg return DRM_FORMAT_XRGB2101010;
1086*f005ef32Sjsg case DRM_FORMAT_ABGR2101010:
1087*f005ef32Sjsg return DRM_FORMAT_XBGR2101010;
1088*f005ef32Sjsg case DRM_FORMAT_RGBA1010102:
1089*f005ef32Sjsg return DRM_FORMAT_RGBX1010102;
1090*f005ef32Sjsg case DRM_FORMAT_BGRA1010102:
1091*f005ef32Sjsg return DRM_FORMAT_BGRX1010102;
1092*f005ef32Sjsg }
1093*f005ef32Sjsg
1094*f005ef32Sjsg return fourcc;
1095*f005ef32Sjsg }
1096*f005ef32Sjsg
is_listed_fourcc(const uint32_t * fourccs,size_t nfourccs,uint32_t fourcc)10971bb76ff1Sjsg static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc)
10981bb76ff1Sjsg {
10991bb76ff1Sjsg const uint32_t *fourccs_end = fourccs + nfourccs;
11001bb76ff1Sjsg
11011bb76ff1Sjsg while (fourccs < fourccs_end) {
11021bb76ff1Sjsg if (*fourccs == fourcc)
11031bb76ff1Sjsg return true;
11041bb76ff1Sjsg ++fourccs;
11051bb76ff1Sjsg }
11061bb76ff1Sjsg return false;
11071bb76ff1Sjsg }
11081bb76ff1Sjsg
11091bb76ff1Sjsg /**
11101bb76ff1Sjsg * drm_fb_build_fourcc_list - Filters a list of supported color formats against
11111bb76ff1Sjsg * the device's native formats
11121bb76ff1Sjsg * @dev: DRM device
11131bb76ff1Sjsg * @native_fourccs: 4CC codes of natively supported color formats
11141bb76ff1Sjsg * @native_nfourccs: The number of entries in @native_fourccs
11151bb76ff1Sjsg * @fourccs_out: Returns 4CC codes of supported color formats
11161bb76ff1Sjsg * @nfourccs_out: The number of available entries in @fourccs_out
11171bb76ff1Sjsg *
11181bb76ff1Sjsg * This function create a list of supported color format from natively
1119*f005ef32Sjsg * supported formats and additional emulated formats.
11201bb76ff1Sjsg * At a minimum, most userspace programs expect at least support for
11211bb76ff1Sjsg * XRGB8888 on the primary plane. Devices that have to emulate the
11221bb76ff1Sjsg * format, and possibly others, can use drm_fb_build_fourcc_list() to
11231bb76ff1Sjsg * create a list of supported color formats. The returned list can
11241bb76ff1Sjsg * be handed over to drm_universal_plane_init() et al. Native formats
1125*f005ef32Sjsg * will go before emulated formats. Native formats with alpha channel
1126*f005ef32Sjsg * will be replaced by such without, as primary planes usually don't
1127*f005ef32Sjsg * support alpha. Other heuristics might be applied
11281bb76ff1Sjsg * to optimize the order. Formats near the beginning of the list are
1129*f005ef32Sjsg * usually preferred over formats near the end of the list.
11305ca02815Sjsg *
11315ca02815Sjsg * Returns:
11321bb76ff1Sjsg * The number of color-formats 4CC codes returned in @fourccs_out.
11335ca02815Sjsg */
drm_fb_build_fourcc_list(struct drm_device * dev,const u32 * native_fourccs,size_t native_nfourccs,u32 * fourccs_out,size_t nfourccs_out)11341bb76ff1Sjsg size_t drm_fb_build_fourcc_list(struct drm_device *dev,
11351bb76ff1Sjsg const u32 *native_fourccs, size_t native_nfourccs,
11361bb76ff1Sjsg u32 *fourccs_out, size_t nfourccs_out)
11375ca02815Sjsg {
1138*f005ef32Sjsg /*
1139*f005ef32Sjsg * XRGB8888 is the default fallback format for most of userspace
1140*f005ef32Sjsg * and it's currently the only format that should be emulated for
1141*f005ef32Sjsg * the primary plane. Only if there's ever another default fallback,
1142*f005ef32Sjsg * it should be added here.
1143*f005ef32Sjsg */
1144*f005ef32Sjsg static const uint32_t extra_fourccs[] = {
1145*f005ef32Sjsg DRM_FORMAT_XRGB8888,
1146*f005ef32Sjsg };
1147*f005ef32Sjsg static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs);
1148*f005ef32Sjsg
11491bb76ff1Sjsg u32 *fourccs = fourccs_out;
11501bb76ff1Sjsg const u32 *fourccs_end = fourccs_out + nfourccs_out;
11511bb76ff1Sjsg size_t i;
11521bb76ff1Sjsg
11531bb76ff1Sjsg /*
11541bb76ff1Sjsg * The device's native formats go first.
11551bb76ff1Sjsg */
11561bb76ff1Sjsg
11571bb76ff1Sjsg for (i = 0; i < native_nfourccs; ++i) {
1158*f005ef32Sjsg /*
1159*f005ef32Sjsg * Several DTs, boot loaders and firmware report native
1160*f005ef32Sjsg * alpha formats that are non-alpha formats instead. So
1161*f005ef32Sjsg * replace alpha formats by non-alpha formats.
1162*f005ef32Sjsg */
1163*f005ef32Sjsg u32 fourcc = drm_fb_nonalpha_fourcc(native_fourccs[i]);
11641bb76ff1Sjsg
11651bb76ff1Sjsg if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
11661bb76ff1Sjsg continue; /* skip duplicate entries */
11671bb76ff1Sjsg } else if (fourccs == fourccs_end) {
11681bb76ff1Sjsg drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc);
11691bb76ff1Sjsg continue; /* end of available output buffer */
11705ca02815Sjsg }
11711bb76ff1Sjsg
11721bb76ff1Sjsg drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc);
11731bb76ff1Sjsg
11741bb76ff1Sjsg *fourccs = fourcc;
11751bb76ff1Sjsg ++fourccs;
11761bb76ff1Sjsg }
11771bb76ff1Sjsg
11781bb76ff1Sjsg /*
11791bb76ff1Sjsg * The extra formats, emulated by the driver, go second.
11801bb76ff1Sjsg */
11811bb76ff1Sjsg
1182*f005ef32Sjsg for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) {
1183*f005ef32Sjsg u32 fourcc = extra_fourccs[i];
11841bb76ff1Sjsg
11851bb76ff1Sjsg if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
11861bb76ff1Sjsg continue; /* skip duplicate and native entries */
11871bb76ff1Sjsg } else if (fourccs == fourccs_end) {
11881bb76ff1Sjsg drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc);
11891bb76ff1Sjsg continue; /* end of available output buffer */
11901bb76ff1Sjsg }
11911bb76ff1Sjsg
11921bb76ff1Sjsg drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc);
11931bb76ff1Sjsg
11941bb76ff1Sjsg *fourccs = fourcc;
11951bb76ff1Sjsg ++fourccs;
11961bb76ff1Sjsg }
11971bb76ff1Sjsg
11981bb76ff1Sjsg return fourccs - fourccs_out;
11991bb76ff1Sjsg }
12001bb76ff1Sjsg EXPORT_SYMBOL(drm_fb_build_fourcc_list);
1201