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>
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 * @vaddr: Source buffer
56 * @fb: DRM framebuffer
57 * @clip: Clip rectangle area to copy
59 * This function applies clipping on dst, i.e. the destination is a
60 * full (iomem) framebuffer but only the clip rect content is copied over.
62 void drm_fb_memcpy_dstclip(void __iomem
*dst
, void *vaddr
,
63 struct drm_framebuffer
*fb
,
64 struct drm_rect
*clip
)
66 unsigned int cpp
= fb
->format
->cpp
[0];
67 unsigned int offset
= clip_offset(clip
, fb
->pitches
[0], cpp
);
68 size_t len
= (clip
->x2
- clip
->x1
) * cpp
;
69 unsigned int y
, lines
= clip
->y2
- clip
->y1
;
73 for (y
= 0; y
< lines
; y
++) {
74 memcpy_toio(dst
, vaddr
, len
);
75 vaddr
+= fb
->pitches
[0];
76 dst
+= fb
->pitches
[0];
79 EXPORT_SYMBOL(drm_fb_memcpy_dstclip
);
82 * drm_fb_swab16 - Swap bytes into clip buffer
83 * @dst: RGB565 destination buffer
84 * @vaddr: RGB565 source buffer
85 * @fb: DRM framebuffer
86 * @clip: Clip rectangle area to copy
88 void drm_fb_swab16(u16
*dst
, void *vaddr
, struct drm_framebuffer
*fb
,
89 struct drm_rect
*clip
)
91 size_t len
= (clip
->x2
- clip
->x1
) * sizeof(u16
);
96 * The cma memory is write-combined so reads are uncached.
97 * Speed up by fetching one line at a time.
99 buf
= kmalloc(len
, GFP_KERNEL
);
103 for (y
= clip
->y1
; y
< clip
->y2
; y
++) {
104 src
= vaddr
+ (y
* fb
->pitches
[0]);
106 memcpy(buf
, src
, len
);
108 for (x
= clip
->x1
; x
< clip
->x2
; x
++)
109 *dst
++ = swab16(*src
++);
114 EXPORT_SYMBOL(drm_fb_swab16
);
116 static void drm_fb_xrgb8888_to_rgb565_line(u16
*dbuf
, u32
*sbuf
,
123 for (x
= 0; x
< pixels
; x
++) {
124 val16
= ((sbuf
[x
] & 0x00F80000) >> 8) |
125 ((sbuf
[x
] & 0x0000FC00) >> 5) |
126 ((sbuf
[x
] & 0x000000F8) >> 3);
128 dbuf
[x
] = swab16(val16
);
135 * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
136 * @dst: RGB565 destination buffer
137 * @vaddr: XRGB8888 source buffer
138 * @fb: DRM framebuffer
139 * @clip: Clip rectangle area to copy
142 * Drivers can use this function for RGB565 devices that don't natively
145 * This function does not apply clipping on dst, i.e. the destination
146 * is a small buffer containing the clip rect only.
148 void drm_fb_xrgb8888_to_rgb565(void *dst
, void *vaddr
,
149 struct drm_framebuffer
*fb
,
150 struct drm_rect
*clip
, bool swab
)
152 size_t linepixels
= clip
->x2
- clip
->x1
;
153 size_t src_len
= linepixels
* sizeof(u32
);
154 size_t dst_len
= linepixels
* sizeof(u16
);
155 unsigned y
, lines
= clip
->y2
- clip
->y1
;
159 * The cma memory is write-combined so reads are uncached.
160 * Speed up by fetching one line at a time.
162 sbuf
= kmalloc(src_len
, GFP_KERNEL
);
166 vaddr
+= clip_offset(clip
, fb
->pitches
[0], sizeof(u32
));
167 for (y
= 0; y
< lines
; y
++) {
168 memcpy(sbuf
, vaddr
, src_len
);
169 drm_fb_xrgb8888_to_rgb565_line(dst
, sbuf
, linepixels
, swab
);
170 vaddr
+= fb
->pitches
[0];
176 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565
);
179 * drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer
180 * @dst: RGB565 destination buffer (iomem)
181 * @dst_pitch: destination buffer pitch
182 * @vaddr: XRGB8888 source buffer
183 * @fb: DRM framebuffer
184 * @clip: Clip rectangle area to copy
187 * Drivers can use this function for RGB565 devices that don't natively
190 * This function applies clipping on dst, i.e. the destination is a
191 * full (iomem) framebuffer but only the clip rect content is copied over.
193 void drm_fb_xrgb8888_to_rgb565_dstclip(void __iomem
*dst
, unsigned int dst_pitch
,
194 void *vaddr
, struct drm_framebuffer
*fb
,
195 struct drm_rect
*clip
, bool swab
)
197 size_t linepixels
= clip
->x2
- clip
->x1
;
198 size_t dst_len
= linepixels
* sizeof(u16
);
199 unsigned y
, lines
= clip
->y2
- clip
->y1
;
202 dbuf
= kmalloc(dst_len
, GFP_KERNEL
);
206 vaddr
+= clip_offset(clip
, fb
->pitches
[0], sizeof(u32
));
207 dst
+= clip_offset(clip
, dst_pitch
, sizeof(u16
));
208 for (y
= 0; y
< lines
; y
++) {
209 drm_fb_xrgb8888_to_rgb565_line(dbuf
, vaddr
, linepixels
, swab
);
210 memcpy_toio(dst
, dbuf
, dst_len
);
211 vaddr
+= fb
->pitches
[0];
217 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip
);
219 static void drm_fb_xrgb8888_to_rgb888_line(u8
*dbuf
, u32
*sbuf
,
224 for (x
= 0; x
< pixels
; x
++) {
225 *dbuf
++ = (sbuf
[x
] & 0x000000FF) >> 0;
226 *dbuf
++ = (sbuf
[x
] & 0x0000FF00) >> 8;
227 *dbuf
++ = (sbuf
[x
] & 0x00FF0000) >> 16;
232 * drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer
233 * @dst: RGB565 destination buffer (iomem)
234 * @dst_pitch: destination buffer pitch
235 * @vaddr: XRGB8888 source buffer
236 * @fb: DRM framebuffer
237 * @clip: Clip rectangle area to copy
239 * Drivers can use this function for RGB888 devices that don't natively
242 * This function applies clipping on dst, i.e. the destination is a
243 * full (iomem) framebuffer but only the clip rect content is copied over.
245 void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem
*dst
, unsigned int dst_pitch
,
246 void *vaddr
, struct drm_framebuffer
*fb
,
247 struct drm_rect
*clip
)
249 size_t linepixels
= clip
->x2
- clip
->x1
;
250 size_t dst_len
= linepixels
* 3;
251 unsigned y
, lines
= clip
->y2
- clip
->y1
;
254 dbuf
= kmalloc(dst_len
, GFP_KERNEL
);
258 vaddr
+= clip_offset(clip
, fb
->pitches
[0], sizeof(u32
));
259 dst
+= clip_offset(clip
, dst_pitch
, sizeof(u16
));
260 for (y
= 0; y
< lines
; y
++) {
261 drm_fb_xrgb8888_to_rgb888_line(dbuf
, vaddr
, linepixels
);
262 memcpy_toio(dst
, dbuf
, dst_len
);
263 vaddr
+= fb
->pitches
[0];
269 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip
);
272 * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
273 * @dst: 8-bit grayscale destination buffer
274 * @vaddr: XRGB8888 source buffer
275 * @fb: DRM framebuffer
276 * @clip: Clip rectangle area to copy
278 * Drm doesn't have native monochrome or grayscale support.
279 * Such drivers can announce the commonly supported XR24 format to userspace
280 * and use this function to convert to the native format.
282 * Monochrome drivers will use the most significant bit,
283 * where 1 means foreground color and 0 background color.
285 * ITU BT.601 is used for the RGB -> luma (brightness) conversion.
287 void drm_fb_xrgb8888_to_gray8(u8
*dst
, void *vaddr
, struct drm_framebuffer
*fb
,
288 struct drm_rect
*clip
)
290 unsigned int len
= (clip
->x2
- clip
->x1
) * sizeof(u32
);
295 if (WARN_ON(fb
->format
->format
!= DRM_FORMAT_XRGB8888
))
298 * The cma memory is write-combined so reads are uncached.
299 * Speed up by fetching one line at a time.
301 buf
= kmalloc(len
, GFP_KERNEL
);
305 for (y
= clip
->y1
; y
< clip
->y2
; y
++) {
306 src
= vaddr
+ (y
* fb
->pitches
[0]);
308 memcpy(buf
, src
, len
);
310 for (x
= clip
->x1
; x
< clip
->x2
; x
++) {
311 u8 r
= (*src
& 0x00ff0000) >> 16;
312 u8 g
= (*src
& 0x0000ff00) >> 8;
313 u8 b
= *src
& 0x000000ff;
315 /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
316 *dst
++ = (3 * r
+ 6 * g
+ b
) / 10;
323 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8
);