cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

drm_format_helper.c (21163B)


      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
     22static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
     23{
     24	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 */
     36unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
     37				const struct drm_rect *clip)
     38{
     39	return clip_offset(clip, pitch, format->cpp[0]);
     40}
     41EXPORT_SYMBOL(drm_fb_clip_offset);
     42
     43/* TODO: Make this functon work with multi-plane formats. */
     44static 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	unsigned long linepixels = drm_rect_width(clip);
     50	unsigned long lines = drm_rect_height(clip);
     51	size_t sbuf_len = linepixels * fb->format->cpp[0];
     52	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	if (!vaddr_cached_hint) {
     62		stmp = kmalloc(sbuf_len, GFP_KERNEL);
     63		if (!stmp)
     64			return -ENOMEM;
     65	}
     66
     67	if (!dst_pitch)
     68		dst_pitch = drm_rect_width(clip) * dst_pixsize;
     69	vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
     70
     71	for (i = 0; i < lines; ++i) {
     72		if (stmp)
     73			sbuf = memcpy(stmp, vaddr, sbuf_len);
     74		else
     75			sbuf = vaddr;
     76		xfrm_line(dst, sbuf, linepixels);
     77		vaddr += fb->pitches[0];
     78		dst += dst_pitch;
     79	}
     80
     81	kfree(stmp);
     82
     83	return 0;
     84}
     85
     86/* TODO: Make this functon work with multi-plane formats. */
     87static 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	unsigned long linepixels = drm_rect_width(clip);
     93	unsigned long lines = drm_rect_height(clip);
     94	size_t dbuf_len = linepixels * dst_pixsize;
     95	size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */
     96	size_t sbuf_len = linepixels * fb->format->cpp[0];
     97	void *stmp = NULL;
     98	unsigned long i;
     99	const void *sbuf;
    100	void *dbuf;
    101
    102	if (vaddr_cached_hint) {
    103		dbuf = kmalloc(dbuf_len, GFP_KERNEL);
    104	} else {
    105		dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL);
    106		stmp = dbuf + stmp_off;
    107	}
    108	if (!dbuf)
    109		return -ENOMEM;
    110
    111	if (!dst_pitch)
    112		dst_pitch = linepixels * dst_pixsize;
    113	vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
    114
    115	for (i = 0; i < lines; ++i) {
    116		if (stmp)
    117			sbuf = memcpy(stmp, vaddr, sbuf_len);
    118		else
    119			sbuf = vaddr;
    120		xfrm_line(dbuf, sbuf, linepixels);
    121		memcpy_toio(dst, dbuf, dbuf_len);
    122		vaddr += fb->pitches[0];
    123		dst += dst_pitch;
    124	}
    125
    126	kfree(dbuf);
    127
    128	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 */
    142void 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	unsigned int cpp = fb->format->cpp[0];
    146	size_t len = (clip->x2 - clip->x1) * cpp;
    147	unsigned int y, lines = clip->y2 - clip->y1;
    148
    149	if (!dst_pitch)
    150		dst_pitch = len;
    151
    152	vaddr += clip_offset(clip, fb->pitches[0], cpp);
    153	for (y = 0; y < lines; y++) {
    154		memcpy(dst, vaddr, len);
    155		vaddr += fb->pitches[0];
    156		dst += dst_pitch;
    157	}
    158}
    159EXPORT_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 */
    172void 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	unsigned int cpp = fb->format->cpp[0];
    176	size_t len = (clip->x2 - clip->x1) * cpp;
    177	unsigned int y, lines = clip->y2 - clip->y1;
    178
    179	if (!dst_pitch)
    180		dst_pitch = len;
    181
    182	vaddr += clip_offset(clip, fb->pitches[0], cpp);
    183	for (y = 0; y < lines; y++) {
    184		memcpy_toio(dst, vaddr, len);
    185		vaddr += fb->pitches[0];
    186		dst += dst_pitch;
    187	}
    188}
    189EXPORT_SYMBOL(drm_fb_memcpy_toio);
    190
    191static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels)
    192{
    193	u16 *dbuf16 = dbuf;
    194	const u16 *sbuf16 = sbuf;
    195	const u16 *send16 = sbuf16 + pixels;
    196
    197	while (sbuf16 < send16)
    198		*dbuf16++ = swab16(*sbuf16++);
    199}
    200
    201static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels)
    202{
    203	u32 *dbuf32 = dbuf;
    204	const u32 *sbuf32 = sbuf;
    205	const u32 *send32 = sbuf32 + pixels;
    206
    207	while (sbuf32 < send32)
    208		*dbuf32++ = swab32(*sbuf32++);
    209}
    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 */
    226void 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	u8 cpp = fb->format->cpp[0];
    231
    232	switch (cpp) {
    233	case 4:
    234		drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab32_line);
    235		break;
    236	case 2:
    237		drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab16_line);
    238		break;
    239	default:
    240		drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n",
    241			      &fb->format->format);
    242		break;
    243	}
    244}
    245EXPORT_SYMBOL(drm_fb_swab);
    246
    247static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
    248{
    249	u8 *dbuf8 = dbuf;
    250	const __le32 *sbuf32 = sbuf;
    251	unsigned int x;
    252	u32 pix;
    253
    254	for (x = 0; x < pixels; x++) {
    255		pix = le32_to_cpu(sbuf32[x]);
    256		dbuf8[x] = ((pix & 0x00e00000) >> 16) |
    257			   ((pix & 0x0000e000) >> 11) |
    258			   ((pix & 0x000000c0) >> 6);
    259	}
    260}
    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 */
    272void 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	drm_fb_xfrm(dst, dst_pitch, 1, src, fb, clip, false, drm_fb_xrgb8888_to_rgb332_line);
    276}
    277EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);
    278
    279static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels)
    280{
    281	u16 *dbuf16 = dbuf;
    282	const u32 *sbuf32 = sbuf;
    283	unsigned int x;
    284	u16 val16;
    285
    286	for (x = 0; x < pixels; x++) {
    287		val16 = ((sbuf32[x] & 0x00F80000) >> 8) |
    288			((sbuf32[x] & 0x0000FC00) >> 5) |
    289			((sbuf32[x] & 0x000000F8) >> 3);
    290		dbuf16[x] = val16;
    291	}
    292}
    293
    294static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
    295						unsigned int pixels)
    296{
    297	u16 *dbuf16 = dbuf;
    298	const u32 *sbuf32 = sbuf;
    299	unsigned int x;
    300	u16 val16;
    301
    302	for (x = 0; x < pixels; x++) {
    303		val16 = ((sbuf32[x] & 0x00F80000) >> 8) |
    304			((sbuf32[x] & 0x0000FC00) >> 5) |
    305			((sbuf32[x] & 0x000000F8) >> 3);
    306		dbuf16[x] = swab16(val16);
    307	}
    308}
    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 */
    322void 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	if (swab)
    327		drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false,
    328			    drm_fb_xrgb8888_to_rgb565_swab_line);
    329	else
    330		drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false,
    331			    drm_fb_xrgb8888_to_rgb565_line);
    332}
    333EXPORT_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 */
    347void 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	if (swab)
    352		drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false,
    353				 drm_fb_xrgb8888_to_rgb565_swab_line);
    354	else
    355		drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false,
    356				 drm_fb_xrgb8888_to_rgb565_line);
    357}
    358EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_toio);
    359
    360static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels)
    361{
    362	u8 *dbuf8 = dbuf;
    363	const u32 *sbuf32 = sbuf;
    364	unsigned int x;
    365
    366	for (x = 0; x < pixels; x++) {
    367		*dbuf8++ = (sbuf32[x] & 0x000000FF) >>  0;
    368		*dbuf8++ = (sbuf32[x] & 0x0000FF00) >>  8;
    369		*dbuf8++ = (sbuf32[x] & 0x00FF0000) >> 16;
    370	}
    371}
    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 */
    384void 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	drm_fb_xfrm(dst, dst_pitch, 3, src, fb, clip, false, drm_fb_xrgb8888_to_rgb888_line);
    388}
    389EXPORT_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 */
    402void 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	drm_fb_xfrm_toio(dst, dst_pitch, 3, vaddr, fb, clip, false,
    407			 drm_fb_xrgb8888_to_rgb888_line);
    408}
    409EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_toio);
    410
    411static void drm_fb_rgb565_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
    412{
    413	u32 *dbuf32 = dbuf;
    414	const u16 *sbuf16 = sbuf;
    415	unsigned int x;
    416
    417	for (x = 0; x < pixels; x++, ++sbuf16, ++dbuf32) {
    418		u32 val32 = ((*sbuf16 & 0xf800) << 8) |
    419			    ((*sbuf16 & 0x07e0) << 5) |
    420			    ((*sbuf16 & 0x001f) << 3);
    421		*dbuf32 = 0xff000000 | val32 |
    422			  ((val32 >> 3) & 0x00070007) |
    423			  ((val32 >> 2) & 0x00000300);
    424	}
    425}
    426
    427static 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	drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false,
    432			 drm_fb_rgb565_to_xrgb8888_line);
    433}
    434
    435static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
    436{
    437	u32 *dbuf32 = dbuf;
    438	const u8 *sbuf8 = sbuf;
    439	unsigned int x;
    440
    441	for (x = 0; x < pixels; x++) {
    442		u8 r = *sbuf8++;
    443		u8 g = *sbuf8++;
    444		u8 b = *sbuf8++;
    445		*dbuf32++ = 0xff000000 | (r << 16) | (g << 8) | b;
    446	}
    447}
    448
    449static 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	drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false,
    454			 drm_fb_rgb888_to_xrgb8888_line);
    455}
    456
    457static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
    458{
    459	u32 *dbuf32 = dbuf;
    460	const u32 *sbuf32 = sbuf;
    461	unsigned int x;
    462	u32 val32;
    463
    464	for (x = 0; x < pixels; x++) {
    465		val32 = ((sbuf32[x] & 0x000000FF) << 2) |
    466			((sbuf32[x] & 0x0000FF00) << 4) |
    467			((sbuf32[x] & 0x00FF0000) << 6);
    468		*dbuf32++ = val32 | ((val32 >> 8) & 0x00300C03);
    469	}
    470}
    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 */
    484void 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	drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false,
    490			 drm_fb_xrgb8888_to_xrgb2101010_line);
    491}
    492EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio);
    493
    494static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels)
    495{
    496	u8 *dbuf8 = dbuf;
    497	const u32 *sbuf32 = sbuf;
    498	unsigned int x;
    499
    500	for (x = 0; x < pixels; x++) {
    501		u8 r = (*sbuf32 & 0x00ff0000) >> 16;
    502		u8 g = (*sbuf32 & 0x0000ff00) >> 8;
    503		u8 b =  *sbuf32 & 0x000000ff;
    504
    505		/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
    506		*dbuf8++ = (3 * r + 6 * g + b) / 10;
    507		sbuf32++;
    508	}
    509}
    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 */
    528void 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	drm_fb_xfrm(dst, dst_pitch, 1, vaddr, fb, clip, false, drm_fb_xrgb8888_to_gray8_line);
    532}
    533EXPORT_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 */
    553int 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	uint32_t fb_format = fb->format->format;
    558
    559	/* treat alpha channel like filler bits */
    560	if (fb_format == DRM_FORMAT_ARGB8888)
    561		fb_format = DRM_FORMAT_XRGB8888;
    562	if (dst_format == DRM_FORMAT_ARGB8888)
    563		dst_format = DRM_FORMAT_XRGB8888;
    564	if (fb_format == DRM_FORMAT_ARGB2101010)
    565		fb_format = DRM_FORMAT_XRGB2101010;
    566	if (dst_format == DRM_FORMAT_ARGB2101010)
    567		dst_format = DRM_FORMAT_XRGB2101010;
    568
    569	if (dst_format == fb_format) {
    570		drm_fb_memcpy_toio(dst, dst_pitch, vmap, fb, clip);
    571		return 0;
    572
    573	} else if (dst_format == DRM_FORMAT_RGB565) {
    574		if (fb_format == DRM_FORMAT_XRGB8888) {
    575			drm_fb_xrgb8888_to_rgb565_toio(dst, dst_pitch, vmap, fb, clip, false);
    576			return 0;
    577		}
    578	} else if (dst_format == DRM_FORMAT_RGB888) {
    579		if (fb_format == DRM_FORMAT_XRGB8888) {
    580			drm_fb_xrgb8888_to_rgb888_toio(dst, dst_pitch, vmap, fb, clip);
    581			return 0;
    582		}
    583	} else if (dst_format == DRM_FORMAT_XRGB8888) {
    584		if (fb_format == DRM_FORMAT_RGB888) {
    585			drm_fb_rgb888_to_xrgb8888_toio(dst, dst_pitch, vmap, fb, clip);
    586			return 0;
    587		} else if (fb_format == DRM_FORMAT_RGB565) {
    588			drm_fb_rgb565_to_xrgb8888_toio(dst, dst_pitch, vmap, fb, clip);
    589			return 0;
    590		}
    591	} else if (dst_format == DRM_FORMAT_XRGB2101010) {
    592		if (fb_format == DRM_FORMAT_XRGB8888) {
    593			drm_fb_xrgb8888_to_xrgb2101010_toio(dst, dst_pitch, vmap, fb, clip);
    594			return 0;
    595		}
    596	}
    597
    598	drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n",
    599		      &fb_format, &dst_format);
    600
    601	return -EINVAL;
    602}
    603EXPORT_SYMBOL(drm_fb_blit_toio);
    604
    605
    606static 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	while (pixels) {
    612		unsigned int i, bits = min(pixels, 8U);
    613		u8 byte = 0;
    614
    615		for (i = 0; i < bits; i++, pixels--) {
    616			if (*sbuf8++ >= 128)
    617				byte |= BIT(i);
    618		}
    619		*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 */
    645void 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	unsigned int linepixels = drm_rect_width(clip);
    649	unsigned int lines = drm_rect_height(clip);
    650	unsigned int cpp = fb->format->cpp[0];
    651	unsigned int len_src32 = linepixels * cpp;
    652	struct drm_device *dev = fb->dev;
    653	unsigned int y;
    654	u8 *mono = dst, *gray8;
    655	u32 *src32;
    656
    657	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	if (!dst_pitch)
    664		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	src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);
    678	if (!src32)
    679		return;
    680
    681	gray8 = (u8 *)src32 + len_src32;
    682
    683	vaddr += clip_offset(clip, fb->pitches[0], cpp);
    684	for (y = 0; y < lines; y++) {
    685		src32 = memcpy(src32, vaddr, len_src32);
    686		drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels);
    687		drm_fb_gray8_to_mono_line(mono, gray8, linepixels);
    688		vaddr += fb->pitches[0];
    689		mono += dst_pitch;
    690	}
    691
    692	kfree(src32);
    693}
    694EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);