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
62void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
63 struct drm_framebuffer *fb,
64 struct drm_rect *clip)
65{
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;
70
71 vaddr += offset;
72 dst += offset;
73 for (y = 0; y < lines; y++) {
74 memcpy_toio(dst, vaddr, len);
75 vaddr += fb->pitches[0];
76 dst += fb->pitches[0];
77 }
78}
79EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb,
96 struct drm_rect *clip, bool cached)
97{
98 u8 cpp = fb->format->cpp[0];
99 size_t len = drm_rect_width(clip) * cpp;
100 u16 *src16, *dst16 = dst;
101 u32 *src32, *dst32 = dst;
102 unsigned int x, y;
103 void *buf = NULL;
104
105 if (WARN_ON_ONCE(cpp != 2 && cpp != 4))
106 return;
107
108 if (!cached)
109 buf = kmalloc(len, GFP_KERNEL);
110
111 src += clip_offset(clip, fb->pitches[0], cpp);
112
113 for (y = clip->y1; y < clip->y2; y++) {
114 if (buf) {
115 memcpy(buf, src, len);
116 src16 = buf;
117 src32 = buf;
118 } else {
119 src16 = src;
120 src32 = src;
121 }
122
123 for (x = clip->x1; x < clip->x2; x++) {
124 if (cpp == 4)
125 *dst32++ = swab32(*src32++);
126 else
127 *dst16++ = swab16(*src16++);
128 }
129
130 src += fb->pitches[0];
131 }
132
133 kfree(buf);
134}
135EXPORT_SYMBOL(drm_fb_swab);
136
137static void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf,
138 unsigned int pixels,
139 bool swab)
140{
141 unsigned int x;
142 u16 val16;
143
144 for (x = 0; x < pixels; x++) {
145 val16 = ((sbuf[x] & 0x00F80000) >> 8) |
146 ((sbuf[x] & 0x0000FC00) >> 5) |
147 ((sbuf[x] & 0x000000F8) >> 3);
148 if (swab)
149 dbuf[x] = swab16(val16);
150 else
151 dbuf[x] = val16;
152 }
153}
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
170 struct drm_framebuffer *fb,
171 struct drm_rect *clip, bool swab)
172{
173 size_t linepixels = clip->x2 - clip->x1;
174 size_t src_len = linepixels * sizeof(u32);
175 size_t dst_len = linepixels * sizeof(u16);
176 unsigned y, lines = clip->y2 - clip->y1;
177 void *sbuf;
178
179
180
181
182
183 sbuf = kmalloc(src_len, GFP_KERNEL);
184 if (!sbuf)
185 return;
186
187 vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
188 for (y = 0; y < lines; y++) {
189 memcpy(sbuf, vaddr, src_len);
190 drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels, swab);
191 vaddr += fb->pitches[0];
192 dst += dst_len;
193 }
194
195 kfree(sbuf);
196}
197EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214void drm_fb_xrgb8888_to_rgb565_dstclip(void __iomem *dst, unsigned int dst_pitch,
215 void *vaddr, struct drm_framebuffer *fb,
216 struct drm_rect *clip, bool swab)
217{
218 size_t linepixels = clip->x2 - clip->x1;
219 size_t dst_len = linepixels * sizeof(u16);
220 unsigned y, lines = clip->y2 - clip->y1;
221 void *dbuf;
222
223 dbuf = kmalloc(dst_len, GFP_KERNEL);
224 if (!dbuf)
225 return;
226
227 vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
228 dst += clip_offset(clip, dst_pitch, sizeof(u16));
229 for (y = 0; y < lines; y++) {
230 drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels, swab);
231 memcpy_toio(dst, dbuf, dst_len);
232 vaddr += fb->pitches[0];
233 dst += dst_len;
234 }
235
236 kfree(dbuf);
237}
238EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
239
240static void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf,
241 unsigned int pixels)
242{
243 unsigned int x;
244
245 for (x = 0; x < pixels; x++) {
246 *dbuf++ = (sbuf[x] & 0x000000FF) >> 0;
247 *dbuf++ = (sbuf[x] & 0x0000FF00) >> 8;
248 *dbuf++ = (sbuf[x] & 0x00FF0000) >> 16;
249 }
250}
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch,
267 void *vaddr, struct drm_framebuffer *fb,
268 struct drm_rect *clip)
269{
270 size_t linepixels = clip->x2 - clip->x1;
271 size_t dst_len = linepixels * 3;
272 unsigned y, lines = clip->y2 - clip->y1;
273 void *dbuf;
274
275 dbuf = kmalloc(dst_len, GFP_KERNEL);
276 if (!dbuf)
277 return;
278
279 vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
280 dst += clip_offset(clip, dst_pitch, sizeof(u16));
281 for (y = 0; y < lines; y++) {
282 drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels);
283 memcpy_toio(dst, dbuf, dst_len);
284 vaddr += fb->pitches[0];
285 dst += dst_len;
286 }
287
288 kfree(dbuf);
289}
290EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip);
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
309 struct drm_rect *clip)
310{
311 unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
312 unsigned int x, y;
313 void *buf;
314 u32 *src;
315
316 if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
317 return;
318
319
320
321
322 buf = kmalloc(len, GFP_KERNEL);
323 if (!buf)
324 return;
325
326 for (y = clip->y1; y < clip->y2; y++) {
327 src = vaddr + (y * fb->pitches[0]);
328 src += clip->x1;
329 memcpy(buf, src, len);
330 src = buf;
331 for (x = clip->x1; x < clip->x2; x++) {
332 u8 r = (*src & 0x00ff0000) >> 16;
333 u8 g = (*src & 0x0000ff00) >> 8;
334 u8 b = *src & 0x000000ff;
335
336
337 *dst++ = (3 * r + 6 * g + b) / 10;
338 src++;
339 }
340 }
341
342 kfree(buf);
343}
344EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
345
346