Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */
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_format_helper.h>
16 : : #include <drm/drm_framebuffer.h>
17 : : #include <drm/drm_fourcc.h>
18 : : #include <drm/drm_rect.h>
19 : :
20 : 0 : static unsigned int clip_offset(struct drm_rect *clip,
21 : : unsigned int pitch, unsigned int cpp)
22 : : {
23 : 0 : return clip->y1 * pitch + clip->x1 * cpp;
24 : : }
25 : :
26 : : /**
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
32 : : *
33 : : * This function does not apply clipping on dst, i.e. the destination
34 : : * is a small buffer containing the clip rect only.
35 : : */
36 : 0 : void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
37 : : struct drm_rect *clip)
38 : : {
39 : 0 : unsigned int cpp = fb->format->cpp[0];
40 : 0 : size_t len = (clip->x2 - clip->x1) * cpp;
41 : 0 : unsigned int y, lines = clip->y2 - clip->y1;
42 : :
43 : 0 : vaddr += clip_offset(clip, fb->pitches[0], cpp);
44 [ # # ]: 0 : for (y = 0; y < lines; y++) {
45 : 0 : memcpy(dst, vaddr, len);
46 : 0 : vaddr += fb->pitches[0];
47 : 0 : dst += len;
48 : : }
49 : 0 : }
50 : : EXPORT_SYMBOL(drm_fb_memcpy);
51 : :
52 : : /**
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
58 : : *
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.
61 : : */
62 : 0 : void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
63 : : struct drm_framebuffer *fb,
64 : : struct drm_rect *clip)
65 : : {
66 : 0 : unsigned int cpp = fb->format->cpp[0];
67 : 0 : unsigned int offset = clip_offset(clip, fb->pitches[0], cpp);
68 : 0 : size_t len = (clip->x2 - clip->x1) * cpp;
69 : 0 : unsigned int y, lines = clip->y2 - clip->y1;
70 : :
71 : 0 : vaddr += offset;
72 : 0 : dst += offset;
73 [ # # ]: 0 : for (y = 0; y < lines; y++) {
74 : 0 : memcpy_toio(dst, vaddr, len);
75 : 0 : vaddr += fb->pitches[0];
76 : 0 : dst += fb->pitches[0];
77 : : }
78 : 0 : }
79 : : EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
80 : :
81 : : /**
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
87 : : */
88 : 0 : void drm_fb_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
89 : : struct drm_rect *clip)
90 : : {
91 : 0 : size_t len = (clip->x2 - clip->x1) * sizeof(u16);
92 : 0 : unsigned int x, y;
93 : 0 : u16 *src, *buf;
94 : :
95 : : /*
96 : : * The cma memory is write-combined so reads are uncached.
97 : : * Speed up by fetching one line at a time.
98 : : */
99 [ # # ]: 0 : buf = kmalloc(len, GFP_KERNEL);
100 [ # # ]: 0 : if (!buf)
101 : : return;
102 : :
103 [ # # ]: 0 : for (y = clip->y1; y < clip->y2; y++) {
104 : 0 : src = vaddr + (y * fb->pitches[0]);
105 : 0 : src += clip->x1;
106 : 0 : memcpy(buf, src, len);
107 : 0 : src = buf;
108 [ # # ]: 0 : for (x = clip->x1; x < clip->x2; x++)
109 : 0 : *dst++ = swab16(*src++);
110 : : }
111 : :
112 : 0 : kfree(buf);
113 : : }
114 : : EXPORT_SYMBOL(drm_fb_swab16);
115 : :
116 : 0 : static void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf,
117 : : unsigned int pixels,
118 : : bool swab)
119 : : {
120 : 0 : unsigned int x;
121 : 0 : u16 val16;
122 : :
123 [ # # ]: 0 : for (x = 0; x < pixels; x++) {
124 : 0 : val16 = ((sbuf[x] & 0x00F80000) >> 8) |
125 : 0 : ((sbuf[x] & 0x0000FC00) >> 5) |
126 : 0 : ((sbuf[x] & 0x000000F8) >> 3);
127 [ # # ]: 0 : if (swab)
128 : 0 : dbuf[x] = swab16(val16);
129 : : else
130 : 0 : dbuf[x] = val16;
131 : : }
132 : 0 : }
133 : :
134 : : /**
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
140 : : * @swab: Swap bytes
141 : : *
142 : : * Drivers can use this function for RGB565 devices that don't natively
143 : : * support XRGB8888.
144 : : *
145 : : * This function does not apply clipping on dst, i.e. the destination
146 : : * is a small buffer containing the clip rect only.
147 : : */
148 : 0 : void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
149 : : struct drm_framebuffer *fb,
150 : : struct drm_rect *clip, bool swab)
151 : : {
152 : 0 : size_t linepixels = clip->x2 - clip->x1;
153 : 0 : size_t src_len = linepixels * sizeof(u32);
154 : 0 : size_t dst_len = linepixels * sizeof(u16);
155 : 0 : unsigned y, lines = clip->y2 - clip->y1;
156 : 0 : void *sbuf;
157 : :
158 : : /*
159 : : * The cma memory is write-combined so reads are uncached.
160 : : * Speed up by fetching one line at a time.
161 : : */
162 [ # # ]: 0 : sbuf = kmalloc(src_len, GFP_KERNEL);
163 [ # # ]: 0 : if (!sbuf)
164 : : return;
165 : :
166 : 0 : vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
167 [ # # ]: 0 : for (y = 0; y < lines; y++) {
168 : 0 : memcpy(sbuf, vaddr, src_len);
169 : 0 : drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels, swab);
170 : 0 : vaddr += fb->pitches[0];
171 : 0 : dst += dst_len;
172 : : }
173 : :
174 : 0 : kfree(sbuf);
175 : : }
176 : : EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
177 : :
178 : : /**
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
185 : : * @swab: Swap bytes
186 : : *
187 : : * Drivers can use this function for RGB565 devices that don't natively
188 : : * support XRGB8888.
189 : : *
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.
192 : : */
193 : 0 : 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)
196 : : {
197 : 0 : size_t linepixels = clip->x2 - clip->x1;
198 : 0 : size_t dst_len = linepixels * sizeof(u16);
199 : 0 : unsigned y, lines = clip->y2 - clip->y1;
200 : 0 : void *dbuf;
201 : :
202 [ # # ]: 0 : dbuf = kmalloc(dst_len, GFP_KERNEL);
203 [ # # ]: 0 : if (!dbuf)
204 : : return;
205 : :
206 : 0 : vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
207 : 0 : dst += clip_offset(clip, dst_pitch, sizeof(u16));
208 [ # # ]: 0 : for (y = 0; y < lines; y++) {
209 : 0 : drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels, swab);
210 : 0 : memcpy_toio(dst, dbuf, dst_len);
211 : 0 : vaddr += fb->pitches[0];
212 : 0 : dst += dst_len;
213 : : }
214 : :
215 : 0 : kfree(dbuf);
216 : : }
217 : : EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
218 : :
219 : 0 : static void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf,
220 : : unsigned int pixels)
221 : : {
222 : 0 : unsigned int x;
223 : :
224 [ # # ]: 0 : for (x = 0; x < pixels; x++) {
225 : 0 : *dbuf++ = (sbuf[x] & 0x000000FF) >> 0;
226 : 0 : *dbuf++ = (sbuf[x] & 0x0000FF00) >> 8;
227 : 0 : *dbuf++ = (sbuf[x] & 0x00FF0000) >> 16;
228 : : }
229 : : }
230 : :
231 : : /**
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
238 : : *
239 : : * Drivers can use this function for RGB888 devices that don't natively
240 : : * support XRGB8888.
241 : : *
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.
244 : : */
245 : 0 : 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)
248 : : {
249 : 0 : size_t linepixels = clip->x2 - clip->x1;
250 : 0 : size_t dst_len = linepixels * 3;
251 : 0 : unsigned y, lines = clip->y2 - clip->y1;
252 : 0 : void *dbuf;
253 : :
254 [ # # ]: 0 : dbuf = kmalloc(dst_len, GFP_KERNEL);
255 [ # # ]: 0 : if (!dbuf)
256 : : return;
257 : :
258 : 0 : vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
259 : 0 : dst += clip_offset(clip, dst_pitch, sizeof(u16));
260 [ # # ]: 0 : for (y = 0; y < lines; y++) {
261 : 0 : drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels);
262 : 0 : memcpy_toio(dst, dbuf, dst_len);
263 : 0 : vaddr += fb->pitches[0];
264 : 0 : dst += dst_len;
265 : : }
266 : :
267 : 0 : kfree(dbuf);
268 : : }
269 : : EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip);
270 : :
271 : : /**
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
277 : : *
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.
281 : : *
282 : : * Monochrome drivers will use the most significant bit,
283 : : * where 1 means foreground color and 0 background color.
284 : : *
285 : : * ITU BT.601 is used for the RGB -> luma (brightness) conversion.
286 : : */
287 : 0 : void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
288 : : struct drm_rect *clip)
289 : : {
290 : 0 : unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
291 : 0 : unsigned int x, y;
292 : 0 : void *buf;
293 : 0 : u32 *src;
294 : :
295 [ # # # # ]: 0 : if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
296 : : return;
297 : : /*
298 : : * The cma memory is write-combined so reads are uncached.
299 : : * Speed up by fetching one line at a time.
300 : : */
301 [ # # ]: 0 : buf = kmalloc(len, GFP_KERNEL);
302 [ # # ]: 0 : if (!buf)
303 : : return;
304 : :
305 [ # # ]: 0 : for (y = clip->y1; y < clip->y2; y++) {
306 : 0 : src = vaddr + (y * fb->pitches[0]);
307 : 0 : src += clip->x1;
308 : 0 : memcpy(buf, src, len);
309 : 0 : src = buf;
310 [ # # ]: 0 : for (x = clip->x1; x < clip->x2; x++) {
311 : 0 : u8 r = (*src & 0x00ff0000) >> 16;
312 : 0 : u8 g = (*src & 0x0000ff00) >> 8;
313 : 0 : u8 b = *src & 0x000000ff;
314 : :
315 : : /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
316 : 0 : *dst++ = (3 * r + 6 * g + b) / 10;
317 : 0 : src++;
318 : : }
319 : : }
320 : :
321 : 0 : kfree(buf);
322 : : }
323 : : EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
324 : :
|