1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (C) 2016 Noralf Trønnes
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.
11 #include <linux/module.h>
12 #include <linux/slab.h>
14 #include <drm/drm_format_helper.h>
15 #include <drm/drm_framebuffer.h>
16 #include <drm/drm_fourcc.h>
17 #include <drm/drm_rect.h>
19 static void drm_fb_memcpy_lines(void *dst, unsigned int dst_pitch,
20 void *src, unsigned int src_pitch,
21 unsigned int linelength, unsigned int lines)
25 for (line = 0; line < lines; line++) {
26 memcpy(dst, src, linelength);
33 * drm_fb_memcpy - Copy clip buffer
34 * @dst: Destination buffer
35 * @vaddr: Source buffer
36 * @fb: DRM framebuffer
37 * @clip: Clip rectangle area to copy
39 * This function does not apply clipping on dst, i.e. the destination
40 * is a small buffer containing the clip rect only.
42 void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
43 struct drm_rect *clip)
45 unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
46 unsigned int offset = (clip->y1 * fb->pitches[0]) + (clip->x1 * cpp);
47 size_t len = (clip->x2 - clip->x1) * cpp;
49 drm_fb_memcpy_lines(dst, len,
50 vaddr + offset, fb->pitches[0],
51 len, clip->y2 - clip->y1);
53 EXPORT_SYMBOL(drm_fb_memcpy);
56 * drm_fb_memcpy_dstclip - Copy clip buffer
57 * @dst: Destination buffer
58 * @vaddr: Source buffer
59 * @fb: DRM framebuffer
60 * @clip: Clip rectangle area to copy
62 * This function applies clipping on dst, i.e. the destination is a
63 * full framebuffer but only the clip rect content is copied over.
65 void drm_fb_memcpy_dstclip(void *dst, void *vaddr, struct drm_framebuffer *fb,
66 struct drm_rect *clip)
68 unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
69 unsigned int offset = (clip->y1 * fb->pitches[0]) + (clip->x1 * cpp);
70 size_t len = (clip->x2 - clip->x1) * cpp;
72 drm_fb_memcpy_lines(dst + offset, fb->pitches[0],
73 vaddr + offset, fb->pitches[0],
74 len, clip->y2 - clip->y1);
76 EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
79 * drm_fb_swab16 - Swap bytes into clip buffer
80 * @dst: RGB565 destination buffer
81 * @vaddr: RGB565 source buffer
82 * @fb: DRM framebuffer
83 * @clip: Clip rectangle area to copy
85 void drm_fb_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
86 struct drm_rect *clip)
88 size_t len = (clip->x2 - clip->x1) * sizeof(u16);
93 * The cma memory is write-combined so reads are uncached.
94 * Speed up by fetching one line at a time.
96 buf = kmalloc(len, GFP_KERNEL);
100 for (y = clip->y1; y < clip->y2; y++) {
101 src = vaddr + (y * fb->pitches[0]);
103 memcpy(buf, src, len);
105 for (x = clip->x1; x < clip->x2; x++)
106 *dst++ = swab16(*src++);
111 EXPORT_SYMBOL(drm_fb_swab16);
113 static void drm_fb_xrgb8888_to_rgb565_lines(void *dst, unsigned int dst_pitch,
114 void *src, unsigned int src_pitch,
115 unsigned int src_linelength,
119 unsigned int linepixels = src_linelength / sizeof(u32);
125 * The cma memory is write-combined so reads are uncached.
126 * Speed up by fetching one line at a time.
128 sbuf = kmalloc(src_linelength, GFP_KERNEL);
132 for (y = 0; y < lines; y++) {
133 memcpy(sbuf, src, src_linelength);
135 for (x = 0; x < linepixels; x++) {
136 val16 = ((sbuf[x] & 0x00F80000) >> 8) |
137 ((sbuf[x] & 0x0000FC00) >> 5) |
138 ((sbuf[x] & 0x000000F8) >> 3);
140 *dbuf++ = swab16(val16);
152 * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
153 * @dst: RGB565 destination buffer
154 * @vaddr: XRGB8888 source buffer
155 * @fb: DRM framebuffer
156 * @clip: Clip rectangle area to copy
159 * Drivers can use this function for RGB565 devices that don't natively
162 * This function does not apply clipping on dst, i.e. the destination
163 * is a small buffer containing the clip rect only.
165 void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
166 struct drm_framebuffer *fb,
167 struct drm_rect *clip, bool swap)
169 unsigned int src_offset = (clip->y1 * fb->pitches[0])
170 + (clip->x1 * sizeof(u32));
171 size_t src_len = (clip->x2 - clip->x1) * sizeof(u32);
172 size_t dst_len = (clip->x2 - clip->x1) * sizeof(u16);
174 drm_fb_xrgb8888_to_rgb565_lines(dst, dst_len,
175 vaddr + src_offset, fb->pitches[0],
176 src_len, clip->y2 - clip->y1,
179 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
182 * drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer
183 * @dst: RGB565 destination buffer
184 * @dst_pitch: destination buffer pitch
185 * @vaddr: XRGB8888 source buffer
186 * @fb: DRM framebuffer
187 * @clip: Clip rectangle area to copy
190 * Drivers can use this function for RGB565 devices that don't natively
193 * This function applies clipping on dst, i.e. the destination is a
194 * full framebuffer but only the clip rect content is copied over.
196 void drm_fb_xrgb8888_to_rgb565_dstclip(void *dst, unsigned int dst_pitch,
197 void *vaddr, struct drm_framebuffer *fb,
198 struct drm_rect *clip, bool swap)
200 unsigned int src_offset = (clip->y1 * fb->pitches[0])
201 + (clip->x1 * sizeof(u32));
202 unsigned int dst_offset = (clip->y1 * dst_pitch)
203 + (clip->x1 * sizeof(u16));
204 size_t src_len = (clip->x2 - clip->x1) * sizeof(u32);
206 drm_fb_xrgb8888_to_rgb565_lines(dst + dst_offset, dst_pitch,
207 vaddr + src_offset, fb->pitches[0],
208 src_len, clip->y2 - clip->y1,
211 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
213 static void drm_fb_xrgb8888_to_rgb888_lines(void *dst, unsigned int dst_pitch,
214 void *src, unsigned int src_pitch,
215 unsigned int src_linelength,
218 unsigned int linepixels = src_linelength / 3;
223 sbuf = kmalloc(src_linelength, GFP_KERNEL);
227 for (y = 0; y < lines; y++) {
228 memcpy(sbuf, src, src_linelength);
230 for (x = 0; x < linepixels; x++) {
231 *dbuf++ = (sbuf[x] & 0x000000FF) >> 0;
232 *dbuf++ = (sbuf[x] & 0x0000FF00) >> 8;
233 *dbuf++ = (sbuf[x] & 0x00FF0000) >> 16;
243 * drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer
244 * @dst: RGB565 destination buffer
245 * @dst_pitch: destination buffer pitch
246 * @vaddr: XRGB8888 source buffer
247 * @fb: DRM framebuffer
248 * @clip: Clip rectangle area to copy
249 * @dstclip: Clip destination too.
251 * Drivers can use this function for RGB888 devices that don't natively
254 * This function applies clipping on dst, i.e. the destination is a
255 * full framebuffer but only the clip rect content is copied over.
257 void drm_fb_xrgb8888_to_rgb888_dstclip(void *dst, unsigned int dst_pitch,
258 void *vaddr, struct drm_framebuffer *fb,
259 struct drm_rect *clip)
261 unsigned int src_offset = (clip->y1 * fb->pitches[0])
262 + (clip->x1 * sizeof(u32));
263 unsigned int dst_offset = (clip->y1 * dst_pitch)
265 size_t src_len = (clip->x2 - clip->x1) * sizeof(u32);
267 drm_fb_xrgb8888_to_rgb888_lines(dst + dst_offset, dst_pitch,
268 vaddr + src_offset, fb->pitches[0],
269 src_len, clip->y2 - clip->y1);
271 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip);
274 * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
275 * @dst: 8-bit grayscale destination buffer
276 * @vaddr: XRGB8888 source buffer
277 * @fb: DRM framebuffer
278 * @clip: Clip rectangle area to copy
280 * Drm doesn't have native monochrome or grayscale support.
281 * Such drivers can announce the commonly supported XR24 format to userspace
282 * and use this function to convert to the native format.
284 * Monochrome drivers will use the most significant bit,
285 * where 1 means foreground color and 0 background color.
287 * ITU BT.601 is used for the RGB -> luma (brightness) conversion.
289 void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
290 struct drm_rect *clip)
292 unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
297 if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
300 * The cma memory is write-combined so reads are uncached.
301 * Speed up by fetching one line at a time.
303 buf = kmalloc(len, GFP_KERNEL);
307 for (y = clip->y1; y < clip->y2; y++) {
308 src = vaddr + (y * fb->pitches[0]);
310 memcpy(buf, src, len);
312 for (x = clip->x1; x < clip->x2; x++) {
313 u8 r = (*src & 0x00ff0000) >> 16;
314 u8 g = (*src & 0x0000ff00) >> 8;
315 u8 b = *src & 0x000000ff;
317 /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
318 *dst++ = (3 * r + 6 * g + b) / 10;
325 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);