18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Noralf Trønnes 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 68c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 78c2ecf20Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 88c2ecf20Sopenharmony_ci * (at your option) any later version. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <drm/drm_format_helper.h> 168c2ecf20Sopenharmony_ci#include <drm/drm_framebuffer.h> 178c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 188c2ecf20Sopenharmony_ci#include <drm/drm_rect.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic unsigned int clip_offset(struct drm_rect *clip, 218c2ecf20Sopenharmony_ci unsigned int pitch, unsigned int cpp) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci return clip->y1 * pitch + clip->x1 * cpp; 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/** 278c2ecf20Sopenharmony_ci * drm_fb_memcpy - Copy clip buffer 288c2ecf20Sopenharmony_ci * @dst: Destination buffer 298c2ecf20Sopenharmony_ci * @vaddr: Source buffer 308c2ecf20Sopenharmony_ci * @fb: DRM framebuffer 318c2ecf20Sopenharmony_ci * @clip: Clip rectangle area to copy 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * This function does not apply clipping on dst, i.e. the destination 348c2ecf20Sopenharmony_ci * is a small buffer containing the clip rect only. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_civoid drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, 378c2ecf20Sopenharmony_ci struct drm_rect *clip) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci unsigned int cpp = fb->format->cpp[0]; 408c2ecf20Sopenharmony_ci size_t len = (clip->x2 - clip->x1) * cpp; 418c2ecf20Sopenharmony_ci unsigned int y, lines = clip->y2 - clip->y1; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci vaddr += clip_offset(clip, fb->pitches[0], cpp); 448c2ecf20Sopenharmony_ci for (y = 0; y < lines; y++) { 458c2ecf20Sopenharmony_ci memcpy(dst, vaddr, len); 468c2ecf20Sopenharmony_ci vaddr += fb->pitches[0]; 478c2ecf20Sopenharmony_ci dst += len; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_fb_memcpy); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/** 538c2ecf20Sopenharmony_ci * drm_fb_memcpy_dstclip - Copy clip buffer 548c2ecf20Sopenharmony_ci * @dst: Destination buffer (iomem) 558c2ecf20Sopenharmony_ci * @vaddr: Source buffer 568c2ecf20Sopenharmony_ci * @fb: DRM framebuffer 578c2ecf20Sopenharmony_ci * @clip: Clip rectangle area to copy 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * This function applies clipping on dst, i.e. the destination is a 608c2ecf20Sopenharmony_ci * full (iomem) framebuffer but only the clip rect content is copied over. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_civoid drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr, 638c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, 648c2ecf20Sopenharmony_ci struct drm_rect *clip) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci unsigned int cpp = fb->format->cpp[0]; 678c2ecf20Sopenharmony_ci unsigned int offset = clip_offset(clip, fb->pitches[0], cpp); 688c2ecf20Sopenharmony_ci size_t len = (clip->x2 - clip->x1) * cpp; 698c2ecf20Sopenharmony_ci unsigned int y, lines = clip->y2 - clip->y1; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci vaddr += offset; 728c2ecf20Sopenharmony_ci dst += offset; 738c2ecf20Sopenharmony_ci for (y = 0; y < lines; y++) { 748c2ecf20Sopenharmony_ci memcpy_toio(dst, vaddr, len); 758c2ecf20Sopenharmony_ci vaddr += fb->pitches[0]; 768c2ecf20Sopenharmony_ci dst += fb->pitches[0]; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_fb_memcpy_dstclip); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/** 828c2ecf20Sopenharmony_ci * drm_fb_swab - Swap bytes into clip buffer 838c2ecf20Sopenharmony_ci * @dst: Destination buffer 848c2ecf20Sopenharmony_ci * @src: Source buffer 858c2ecf20Sopenharmony_ci * @fb: DRM framebuffer 868c2ecf20Sopenharmony_ci * @clip: Clip rectangle area to copy 878c2ecf20Sopenharmony_ci * @cached: Source buffer is mapped cached (eg. not write-combined) 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * If @cached is false a temporary buffer is used to cache one pixel line at a 908c2ecf20Sopenharmony_ci * time to speed up slow uncached reads. 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * This function does not apply clipping on dst, i.e. the destination 938c2ecf20Sopenharmony_ci * is a small buffer containing the clip rect only. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_civoid drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb, 968c2ecf20Sopenharmony_ci struct drm_rect *clip, bool cached) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci u8 cpp = fb->format->cpp[0]; 998c2ecf20Sopenharmony_ci size_t len = drm_rect_width(clip) * cpp; 1008c2ecf20Sopenharmony_ci u16 *src16, *dst16 = dst; 1018c2ecf20Sopenharmony_ci u32 *src32, *dst32 = dst; 1028c2ecf20Sopenharmony_ci unsigned int x, y; 1038c2ecf20Sopenharmony_ci void *buf = NULL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(cpp != 2 && cpp != 4)) 1068c2ecf20Sopenharmony_ci return; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (!cached) 1098c2ecf20Sopenharmony_ci buf = kmalloc(len, GFP_KERNEL); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci src += clip_offset(clip, fb->pitches[0], cpp); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci for (y = clip->y1; y < clip->y2; y++) { 1148c2ecf20Sopenharmony_ci if (buf) { 1158c2ecf20Sopenharmony_ci memcpy(buf, src, len); 1168c2ecf20Sopenharmony_ci src16 = buf; 1178c2ecf20Sopenharmony_ci src32 = buf; 1188c2ecf20Sopenharmony_ci } else { 1198c2ecf20Sopenharmony_ci src16 = src; 1208c2ecf20Sopenharmony_ci src32 = src; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci for (x = clip->x1; x < clip->x2; x++) { 1248c2ecf20Sopenharmony_ci if (cpp == 4) 1258c2ecf20Sopenharmony_ci *dst32++ = swab32(*src32++); 1268c2ecf20Sopenharmony_ci else 1278c2ecf20Sopenharmony_ci *dst16++ = swab16(*src16++); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci src += fb->pitches[0]; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci kfree(buf); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_fb_swab); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf, 1388c2ecf20Sopenharmony_ci unsigned int pixels, 1398c2ecf20Sopenharmony_ci bool swab) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci unsigned int x; 1428c2ecf20Sopenharmony_ci u16 val16; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci for (x = 0; x < pixels; x++) { 1458c2ecf20Sopenharmony_ci val16 = ((sbuf[x] & 0x00F80000) >> 8) | 1468c2ecf20Sopenharmony_ci ((sbuf[x] & 0x0000FC00) >> 5) | 1478c2ecf20Sopenharmony_ci ((sbuf[x] & 0x000000F8) >> 3); 1488c2ecf20Sopenharmony_ci if (swab) 1498c2ecf20Sopenharmony_ci dbuf[x] = swab16(val16); 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci dbuf[x] = val16; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/** 1568c2ecf20Sopenharmony_ci * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer 1578c2ecf20Sopenharmony_ci * @dst: RGB565 destination buffer 1588c2ecf20Sopenharmony_ci * @vaddr: XRGB8888 source buffer 1598c2ecf20Sopenharmony_ci * @fb: DRM framebuffer 1608c2ecf20Sopenharmony_ci * @clip: Clip rectangle area to copy 1618c2ecf20Sopenharmony_ci * @swab: Swap bytes 1628c2ecf20Sopenharmony_ci * 1638c2ecf20Sopenharmony_ci * Drivers can use this function for RGB565 devices that don't natively 1648c2ecf20Sopenharmony_ci * support XRGB8888. 1658c2ecf20Sopenharmony_ci * 1668c2ecf20Sopenharmony_ci * This function does not apply clipping on dst, i.e. the destination 1678c2ecf20Sopenharmony_ci * is a small buffer containing the clip rect only. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_civoid drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr, 1708c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, 1718c2ecf20Sopenharmony_ci struct drm_rect *clip, bool swab) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci size_t linepixels = clip->x2 - clip->x1; 1748c2ecf20Sopenharmony_ci size_t src_len = linepixels * sizeof(u32); 1758c2ecf20Sopenharmony_ci size_t dst_len = linepixels * sizeof(u16); 1768c2ecf20Sopenharmony_ci unsigned y, lines = clip->y2 - clip->y1; 1778c2ecf20Sopenharmony_ci void *sbuf; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * The cma memory is write-combined so reads are uncached. 1818c2ecf20Sopenharmony_ci * Speed up by fetching one line at a time. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci sbuf = kmalloc(src_len, GFP_KERNEL); 1848c2ecf20Sopenharmony_ci if (!sbuf) 1858c2ecf20Sopenharmony_ci return; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); 1888c2ecf20Sopenharmony_ci for (y = 0; y < lines; y++) { 1898c2ecf20Sopenharmony_ci memcpy(sbuf, vaddr, src_len); 1908c2ecf20Sopenharmony_ci drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels, swab); 1918c2ecf20Sopenharmony_ci vaddr += fb->pitches[0]; 1928c2ecf20Sopenharmony_ci dst += dst_len; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci kfree(sbuf); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/** 2008c2ecf20Sopenharmony_ci * drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer 2018c2ecf20Sopenharmony_ci * @dst: RGB565 destination buffer (iomem) 2028c2ecf20Sopenharmony_ci * @dst_pitch: destination buffer pitch 2038c2ecf20Sopenharmony_ci * @vaddr: XRGB8888 source buffer 2048c2ecf20Sopenharmony_ci * @fb: DRM framebuffer 2058c2ecf20Sopenharmony_ci * @clip: Clip rectangle area to copy 2068c2ecf20Sopenharmony_ci * @swab: Swap bytes 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * Drivers can use this function for RGB565 devices that don't natively 2098c2ecf20Sopenharmony_ci * support XRGB8888. 2108c2ecf20Sopenharmony_ci * 2118c2ecf20Sopenharmony_ci * This function applies clipping on dst, i.e. the destination is a 2128c2ecf20Sopenharmony_ci * full (iomem) framebuffer but only the clip rect content is copied over. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_civoid drm_fb_xrgb8888_to_rgb565_dstclip(void __iomem *dst, unsigned int dst_pitch, 2158c2ecf20Sopenharmony_ci void *vaddr, struct drm_framebuffer *fb, 2168c2ecf20Sopenharmony_ci struct drm_rect *clip, bool swab) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci size_t linepixels = clip->x2 - clip->x1; 2198c2ecf20Sopenharmony_ci size_t dst_len = linepixels * sizeof(u16); 2208c2ecf20Sopenharmony_ci unsigned y, lines = clip->y2 - clip->y1; 2218c2ecf20Sopenharmony_ci void *dbuf; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci dbuf = kmalloc(dst_len, GFP_KERNEL); 2248c2ecf20Sopenharmony_ci if (!dbuf) 2258c2ecf20Sopenharmony_ci return; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); 2288c2ecf20Sopenharmony_ci dst += clip_offset(clip, dst_pitch, sizeof(u16)); 2298c2ecf20Sopenharmony_ci for (y = 0; y < lines; y++) { 2308c2ecf20Sopenharmony_ci drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels, swab); 2318c2ecf20Sopenharmony_ci memcpy_toio(dst, dbuf, dst_len); 2328c2ecf20Sopenharmony_ci vaddr += fb->pitches[0]; 2338c2ecf20Sopenharmony_ci dst += dst_len; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci kfree(dbuf); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf, 2418c2ecf20Sopenharmony_ci unsigned int pixels) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci unsigned int x; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci for (x = 0; x < pixels; x++) { 2468c2ecf20Sopenharmony_ci *dbuf++ = (sbuf[x] & 0x000000FF) >> 0; 2478c2ecf20Sopenharmony_ci *dbuf++ = (sbuf[x] & 0x0000FF00) >> 8; 2488c2ecf20Sopenharmony_ci *dbuf++ = (sbuf[x] & 0x00FF0000) >> 16; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/** 2538c2ecf20Sopenharmony_ci * drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer 2548c2ecf20Sopenharmony_ci * @dst: RGB565 destination buffer (iomem) 2558c2ecf20Sopenharmony_ci * @dst_pitch: destination buffer pitch 2568c2ecf20Sopenharmony_ci * @vaddr: XRGB8888 source buffer 2578c2ecf20Sopenharmony_ci * @fb: DRM framebuffer 2588c2ecf20Sopenharmony_ci * @clip: Clip rectangle area to copy 2598c2ecf20Sopenharmony_ci * 2608c2ecf20Sopenharmony_ci * Drivers can use this function for RGB888 devices that don't natively 2618c2ecf20Sopenharmony_ci * support XRGB8888. 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * This function applies clipping on dst, i.e. the destination is a 2648c2ecf20Sopenharmony_ci * full (iomem) framebuffer but only the clip rect content is copied over. 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_civoid drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch, 2678c2ecf20Sopenharmony_ci void *vaddr, struct drm_framebuffer *fb, 2688c2ecf20Sopenharmony_ci struct drm_rect *clip) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci size_t linepixels = clip->x2 - clip->x1; 2718c2ecf20Sopenharmony_ci size_t dst_len = linepixels * 3; 2728c2ecf20Sopenharmony_ci unsigned y, lines = clip->y2 - clip->y1; 2738c2ecf20Sopenharmony_ci void *dbuf; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci dbuf = kmalloc(dst_len, GFP_KERNEL); 2768c2ecf20Sopenharmony_ci if (!dbuf) 2778c2ecf20Sopenharmony_ci return; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); 2808c2ecf20Sopenharmony_ci dst += clip_offset(clip, dst_pitch, sizeof(u16)); 2818c2ecf20Sopenharmony_ci for (y = 0; y < lines; y++) { 2828c2ecf20Sopenharmony_ci drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels); 2838c2ecf20Sopenharmony_ci memcpy_toio(dst, dbuf, dst_len); 2848c2ecf20Sopenharmony_ci vaddr += fb->pitches[0]; 2858c2ecf20Sopenharmony_ci dst += dst_len; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci kfree(dbuf); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/** 2938c2ecf20Sopenharmony_ci * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale 2948c2ecf20Sopenharmony_ci * @dst: 8-bit grayscale destination buffer 2958c2ecf20Sopenharmony_ci * @vaddr: XRGB8888 source buffer 2968c2ecf20Sopenharmony_ci * @fb: DRM framebuffer 2978c2ecf20Sopenharmony_ci * @clip: Clip rectangle area to copy 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * Drm doesn't have native monochrome or grayscale support. 3008c2ecf20Sopenharmony_ci * Such drivers can announce the commonly supported XR24 format to userspace 3018c2ecf20Sopenharmony_ci * and use this function to convert to the native format. 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci * Monochrome drivers will use the most significant bit, 3048c2ecf20Sopenharmony_ci * where 1 means foreground color and 0 background color. 3058c2ecf20Sopenharmony_ci * 3068c2ecf20Sopenharmony_ci * ITU BT.601 is used for the RGB -> luma (brightness) conversion. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_civoid drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, 3098c2ecf20Sopenharmony_ci struct drm_rect *clip) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci unsigned int len = (clip->x2 - clip->x1) * sizeof(u32); 3128c2ecf20Sopenharmony_ci unsigned int x, y; 3138c2ecf20Sopenharmony_ci void *buf; 3148c2ecf20Sopenharmony_ci u32 *src; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888)) 3178c2ecf20Sopenharmony_ci return; 3188c2ecf20Sopenharmony_ci /* 3198c2ecf20Sopenharmony_ci * The cma memory is write-combined so reads are uncached. 3208c2ecf20Sopenharmony_ci * Speed up by fetching one line at a time. 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ci buf = kmalloc(len, GFP_KERNEL); 3238c2ecf20Sopenharmony_ci if (!buf) 3248c2ecf20Sopenharmony_ci return; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci for (y = clip->y1; y < clip->y2; y++) { 3278c2ecf20Sopenharmony_ci src = vaddr + (y * fb->pitches[0]); 3288c2ecf20Sopenharmony_ci src += clip->x1; 3298c2ecf20Sopenharmony_ci memcpy(buf, src, len); 3308c2ecf20Sopenharmony_ci src = buf; 3318c2ecf20Sopenharmony_ci for (x = clip->x1; x < clip->x2; x++) { 3328c2ecf20Sopenharmony_ci u8 r = (*src & 0x00ff0000) >> 16; 3338c2ecf20Sopenharmony_ci u8 g = (*src & 0x0000ff00) >> 8; 3348c2ecf20Sopenharmony_ci u8 b = *src & 0x000000ff; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */ 3378c2ecf20Sopenharmony_ci *dst++ = (3 * r + 6 * g + b) / 10; 3388c2ecf20Sopenharmony_ci src++; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci kfree(buf); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); 3458c2ecf20Sopenharmony_ci 346