1 // SPDX-License-Identifier: GPL-2.0 or MIT
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>
15 #include <drm/drm_format_helper.h>
16 #include <drm/drm_framebuffer.h>
17 #include <drm/drm_fourcc.h>
18 #include <drm/drm_rect.h>
20 static unsigned int clip_offset(struct drm_rect *clip,
21 unsigned int pitch, unsigned int cpp)
23 return clip->y1 * pitch + clip->x1 * cpp;
27 * drm_fb_memcpy - Copy clip buffer
28 * @dst: Destination buffer
29 * @vaddr: Source buffer
30 * @fb: DRM framebuffer
31 * @clip: Clip rectangle area to copy
33 * This function does not apply clipping on dst, i.e. the destination
34 * is a small buffer containing the clip rect only.
36 void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
37 struct drm_rect *clip)
39 unsigned int cpp = fb->format->cpp[0];
40 size_t len = (clip->x2 - clip->x1) * cpp;
41 unsigned int y, lines = clip->y2 - clip->y1;
43 vaddr += clip_offset(clip, fb->pitches[0], cpp);
44 for (y = 0; y < lines; y++) {
45 memcpy(dst, vaddr, len);
46 vaddr += fb->pitches[0];
50 EXPORT_SYMBOL(drm_fb_memcpy);
53 * drm_fb_memcpy_dstclip - Copy clip buffer
54 * @dst: Destination buffer (iomem)
55 * @dst_pitch: Number of bytes between two consecutive scanlines within dst
56 * @vaddr: Source buffer
57 * @fb: DRM framebuffer
58 * @clip: Clip rectangle area to copy
60 * This function applies clipping on dst, i.e. the destination is a
61 * full (iomem) framebuffer but only the clip rect content is copied over.
63 void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch,
64 void *vaddr, struct drm_framebuffer *fb,
65 struct drm_rect *clip)
67 unsigned int cpp = fb->format->cpp[0];
68 unsigned int offset = clip_offset(clip, dst_pitch, cpp);
69 size_t len = (clip->x2 - clip->x1) * cpp;
70 unsigned int y, lines = clip->y2 - clip->y1;
74 for (y = 0; y < lines; y++) {
75 memcpy_toio(dst, vaddr, len);
76 vaddr += fb->pitches[0];
80 EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
83 * drm_fb_swab - Swap bytes into clip buffer
84 * @dst: Destination buffer
86 * @fb: DRM framebuffer
87 * @clip: Clip rectangle area to copy
88 * @cached: Source buffer is mapped cached (eg. not write-combined)
90 * If @cached is false a temporary buffer is used to cache one pixel line at a
91 * time to speed up slow uncached reads.
93 * This function does not apply clipping on dst, i.e. the destination
94 * is a small buffer containing the clip rect only.
96 void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb,
97 struct drm_rect *clip, bool cached)
99 u8 cpp = fb->format->cpp[0];
100 size_t len = drm_rect_width(clip) * cpp;
101 u16 *src16, *dst16 = dst;
102 u32 *src32, *dst32 = dst;
106 if (WARN_ON_ONCE(cpp != 2 && cpp != 4))
110 buf = kmalloc(len, GFP_KERNEL);
112 src += clip_offset(clip, fb->pitches[0], cpp);
114 for (y = clip->y1; y < clip->y2; y++) {
116 memcpy(buf, src, len);
124 for (x = clip->x1; x < clip->x2; x++) {
126 *dst32++ = swab32(*src32++);
128 *dst16++ = swab16(*src16++);
131 src += fb->pitches[0];
136 EXPORT_SYMBOL(drm_fb_swab);
138 static void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf,
145 for (x = 0; x < pixels; x++) {
146 val16 = ((sbuf[x] & 0x00F80000) >> 8) |
147 ((sbuf[x] & 0x0000FC00) >> 5) |
148 ((sbuf[x] & 0x000000F8) >> 3);
150 dbuf[x] = swab16(val16);
157 * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
158 * @dst: RGB565 destination buffer
159 * @vaddr: XRGB8888 source buffer
160 * @fb: DRM framebuffer
161 * @clip: Clip rectangle area to copy
164 * Drivers can use this function for RGB565 devices that don't natively
167 * This function does not apply clipping on dst, i.e. the destination
168 * is a small buffer containing the clip rect only.
170 void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
171 struct drm_framebuffer *fb,
172 struct drm_rect *clip, bool swab)
174 size_t linepixels = clip->x2 - clip->x1;
175 size_t src_len = linepixels * sizeof(u32);
176 size_t dst_len = linepixels * sizeof(u16);
177 unsigned y, lines = clip->y2 - clip->y1;
181 * The cma memory is write-combined so reads are uncached.
182 * Speed up by fetching one line at a time.
184 sbuf = kmalloc(src_len, GFP_KERNEL);
188 vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
189 for (y = 0; y < lines; y++) {
190 memcpy(sbuf, vaddr, src_len);
191 drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels, swab);
192 vaddr += fb->pitches[0];
198 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
201 * drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer
202 * @dst: RGB565 destination buffer (iomem)
203 * @dst_pitch: destination buffer pitch
204 * @vaddr: XRGB8888 source buffer
205 * @fb: DRM framebuffer
206 * @clip: Clip rectangle area to copy
209 * Drivers can use this function for RGB565 devices that don't natively
212 * This function applies clipping on dst, i.e. the destination is a
213 * full (iomem) framebuffer but only the clip rect content is copied over.
215 void drm_fb_xrgb8888_to_rgb565_dstclip(void __iomem *dst, unsigned int dst_pitch,
216 void *vaddr, struct drm_framebuffer *fb,
217 struct drm_rect *clip, bool swab)
219 size_t linepixels = clip->x2 - clip->x1;
220 size_t dst_len = linepixels * sizeof(u16);
221 unsigned y, lines = clip->y2 - clip->y1;
224 dbuf = kmalloc(dst_len, GFP_KERNEL);
228 vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
229 dst += clip_offset(clip, dst_pitch, sizeof(u16));
230 for (y = 0; y < lines; y++) {
231 drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels, swab);
232 memcpy_toio(dst, dbuf, dst_len);
233 vaddr += fb->pitches[0];
239 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
241 static void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf,
246 for (x = 0; x < pixels; x++) {
247 *dbuf++ = (sbuf[x] & 0x000000FF) >> 0;
248 *dbuf++ = (sbuf[x] & 0x0000FF00) >> 8;
249 *dbuf++ = (sbuf[x] & 0x00FF0000) >> 16;
254 * drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer
255 * @dst: RGB565 destination buffer (iomem)
256 * @dst_pitch: destination buffer pitch
257 * @vaddr: XRGB8888 source buffer
258 * @fb: DRM framebuffer
259 * @clip: Clip rectangle area to copy
261 * Drivers can use this function for RGB888 devices that don't natively
264 * This function applies clipping on dst, i.e. the destination is a
265 * full (iomem) framebuffer but only the clip rect content is copied over.
267 void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch,
268 void *vaddr, struct drm_framebuffer *fb,
269 struct drm_rect *clip)
271 size_t linepixels = clip->x2 - clip->x1;
272 size_t dst_len = linepixels * 3;
273 unsigned y, lines = clip->y2 - clip->y1;
276 dbuf = kmalloc(dst_len, GFP_KERNEL);
280 vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
281 dst += clip_offset(clip, dst_pitch, sizeof(u16));
282 for (y = 0; y < lines; y++) {
283 drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels);
284 memcpy_toio(dst, dbuf, dst_len);
285 vaddr += fb->pitches[0];
291 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip);
294 * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
295 * @dst: 8-bit grayscale destination buffer
296 * @vaddr: XRGB8888 source buffer
297 * @fb: DRM framebuffer
298 * @clip: Clip rectangle area to copy
300 * Drm doesn't have native monochrome or grayscale support.
301 * Such drivers can announce the commonly supported XR24 format to userspace
302 * and use this function to convert to the native format.
304 * Monochrome drivers will use the most significant bit,
305 * where 1 means foreground color and 0 background color.
307 * ITU BT.601 is used for the RGB -> luma (brightness) conversion.
309 void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
310 struct drm_rect *clip)
312 unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
317 if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
320 * The cma memory is write-combined so reads are uncached.
321 * Speed up by fetching one line at a time.
323 buf = kmalloc(len, GFP_KERNEL);
327 for (y = clip->y1; y < clip->y2; y++) {
328 src = vaddr + (y * fb->pitches[0]);
330 memcpy(buf, src, len);
332 for (x = clip->x1; x < clip->x2; x++) {
333 u8 r = (*src & 0x00ff0000) >> 16;
334 u8 g = (*src & 0x0000ff00) >> 8;
335 u8 b = *src & 0x000000ff;
337 /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
338 *dst++ = (3 * r + 6 * g + b) / 10;
345 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
348 * drm_fb_blit_rect_dstclip - Copy parts of a framebuffer to display memory
349 * @dst: The display memory to copy to
350 * @dst_pitch: Number of bytes between two consecutive scanlines within dst
351 * @dst_format: FOURCC code of the display's color format
352 * @vmap: The framebuffer memory to copy from
353 * @fb: The framebuffer to copy from
354 * @clip: Clip rectangle area to copy
356 * This function copies parts of a framebuffer to display memory. If the
357 * formats of the display and the framebuffer mismatch, the blit function
358 * will attempt to convert between them.
360 * Use drm_fb_blit_dstclip() to copy the full framebuffer.
364 * -EINVAL if the color-format conversion failed, or
365 * a negative error code otherwise.
367 int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch,
368 uint32_t dst_format, void *vmap,
369 struct drm_framebuffer *fb,
370 struct drm_rect *clip)
372 uint32_t fb_format = fb->format->format;
374 /* treat alpha channel like filler bits */
375 if (fb_format == DRM_FORMAT_ARGB8888)
376 fb_format = DRM_FORMAT_XRGB8888;
377 if (dst_format == DRM_FORMAT_ARGB8888)
378 dst_format = DRM_FORMAT_XRGB8888;
380 if (dst_format == fb_format) {
381 drm_fb_memcpy_dstclip(dst, dst_pitch, vmap, fb, clip);
384 } else if (dst_format == DRM_FORMAT_RGB565) {
385 if (fb_format == DRM_FORMAT_XRGB8888) {
386 drm_fb_xrgb8888_to_rgb565_dstclip(dst, dst_pitch,
391 } else if (dst_format == DRM_FORMAT_RGB888) {
392 if (fb_format == DRM_FORMAT_XRGB8888) {
393 drm_fb_xrgb8888_to_rgb888_dstclip(dst, dst_pitch,
401 EXPORT_SYMBOL(drm_fb_blit_rect_dstclip);
404 * drm_fb_blit_dstclip - Copy framebuffer to display memory
405 * @dst: The display memory to copy to
406 * @dst_pitch: Number of bytes between two consecutive scanlines within dst
407 * @dst_format: FOURCC code of the display's color format
408 * @vmap: The framebuffer memory to copy from
409 * @fb: The framebuffer to copy from
411 * This function copies a full framebuffer to display memory. If the formats
412 * of the display and the framebuffer mismatch, the copy function will
413 * attempt to convert between them.
415 * See drm_fb_blit_rect_dstclip() for more information.
418 * 0 on success, or a negative error code otherwise.
420 int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch,
421 uint32_t dst_format, void *vmap,
422 struct drm_framebuffer *fb)
424 struct drm_rect fullscreen = {
430 return drm_fb_blit_rect_dstclip(dst, dst_pitch, dst_format, vmap, fb,
433 EXPORT_SYMBOL(drm_fb_blit_dstclip);