1
2
3
4
5
6
7
8
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
20static unsigned int clip_offset(struct drm_rect *clip,
21 unsigned int pitch, unsigned int cpp)
22{
23 return clip->y1 * pitch + clip->x1 * cpp;
24}
25
26
27
28
29
30
31
32
33
34
35
36void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
37 struct drm_rect *clip)
38{
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;
42
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];
47 dst += len;
48 }
49}
50EXPORT_SYMBOL(drm_fb_memcpy);
51
52
53
54
55
56
57
58
59
60
61
62
63void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch,
64 void *vaddr, struct drm_framebuffer *fb,
65 struct drm_rect *clip)
66{
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;
71
72 vaddr += offset;
73 dst += offset;
74 for (y = 0; y < lines; y++) {
75 memcpy_toio(dst, vaddr, len);
76 vaddr += fb->pitches[0];
77 dst += dst_pitch;
78 }
79}
80EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb,
97 struct drm_rect *clip, bool cached)
98{
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;
103 unsigned int x, y;
104 void *buf = NULL;
105
106 if (WARN_ON_ONCE(cpp != 2 && cpp != 4))
107 return;
108
109 if (!cached)
110 buf = kmalloc(len, GFP_KERNEL);
111
112 src += clip_offset(clip, fb->pitches[0], cpp);
113
114 for (y = clip->y1; y < clip->y2; y++) {
115 if (buf) {
116 memcpy(buf, src, len);
117 src16 = buf;
118 src32 = buf;
119 } else {
120 src16 = src;
121 src32 = src;
122 }
123
124 for (x = clip->x1; x < clip->x2; x++) {
125 if (cpp == 4)
126 *dst32++ = swab32(*src32++);
127 else
128 *dst16++ = swab16(*src16++);
129 }
130
131 src += fb->pitches[0];
132 }
133
134 kfree(buf);
135}
136EXPORT_SYMBOL(drm_fb_swab);
137
138static void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf,
139 unsigned int pixels,
140 bool swab)
141{
142 unsigned int x;
143 u16 val16;
144
145 for (x = 0; x < pixels; x++) {
146 val16 = ((sbuf[x] & 0x00F80000) >> 8) |
147 ((sbuf[x] & 0x0000FC00) >> 5) |
148 ((sbuf[x] & 0x000000F8) >> 3);
149 if (swab)
150 dbuf[x] = swab16(val16);
151 else
152 dbuf[x] = val16;
153 }
154}
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
171 struct drm_framebuffer *fb,
172 struct drm_rect *clip, bool swab)
173{
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;
178 void *sbuf;
179
180
181
182
183
184 sbuf = kmalloc(src_len, GFP_KERNEL);
185 if (!sbuf)
186 return;
187
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];
193 dst += dst_len;
194 }
195
196 kfree(sbuf);
197}
198EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215void 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)
218{
219 size_t linepixels = clip->x2 - clip->x1;
220 size_t dst_len = linepixels * sizeof(u16);
221 unsigned y, lines = clip->y2 - clip->y1;
222 void *dbuf;
223
224 dbuf = kmalloc(dst_len, GFP_KERNEL);
225 if (!dbuf)
226 return;
227
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];
234 dst += dst_len;
235 }
236
237 kfree(dbuf);
238}
239EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
240
241static void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf,
242 unsigned int pixels)
243{
244 unsigned int x;
245
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;
250 }
251}
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267void 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)
270{
271 size_t linepixels = clip->x2 - clip->x1;
272 size_t dst_len = linepixels * 3;
273 unsigned y, lines = clip->y2 - clip->y1;
274 void *dbuf;
275
276 dbuf = kmalloc(dst_len, GFP_KERNEL);
277 if (!dbuf)
278 return;
279
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];
286 dst += dst_len;
287 }
288
289 kfree(dbuf);
290}
291EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip);
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
310 struct drm_rect *clip)
311{
312 unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
313 unsigned int x, y;
314 void *buf;
315 u32 *src;
316
317 if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
318 return;
319
320
321
322
323 buf = kmalloc(len, GFP_KERNEL);
324 if (!buf)
325 return;
326
327 for (y = clip->y1; y < clip->y2; y++) {
328 src = vaddr + (y * fb->pitches[0]);
329 src += clip->x1;
330 memcpy(buf, src, len);
331 src = buf;
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;
336
337
338 *dst++ = (3 * r + 6 * g + b) / 10;
339 src++;
340 }
341 }
342
343 kfree(buf);
344}
345EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367int 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)
371{
372 uint32_t fb_format = fb->format->format;
373
374
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;
379
380 if (dst_format == fb_format) {
381 drm_fb_memcpy_dstclip(dst, dst_pitch, vmap, fb, clip);
382 return 0;
383
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,
387 vmap, fb, clip,
388 false);
389 return 0;
390 }
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,
394 vmap, fb, clip);
395 return 0;
396 }
397 }
398
399 return -EINVAL;
400}
401EXPORT_SYMBOL(drm_fb_blit_rect_dstclip);
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch,
421 uint32_t dst_format, void *vmap,
422 struct drm_framebuffer *fb)
423{
424 struct drm_rect fullscreen = {
425 .x1 = 0,
426 .x2 = fb->width,
427 .y1 = 0,
428 .y2 = fb->height,
429 };
430 return drm_fb_blit_rect_dstclip(dst, dst_pitch, dst_format, vmap, fb,
431 &fullscreen);
432}
433EXPORT_SYMBOL(drm_fb_blit_dstclip);
434