Commit | Line | Data |
---|---|---|
0bd65bd8 | 1 | // SPDX-License-Identifier: GPL-2.0 or MIT |
7415287e GH |
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 | ||
71bf5587 TZ |
11 | #include <linux/io.h> |
12 | #include <linux/iosys-map.h> | |
7415287e GH |
13 | #include <linux/module.h> |
14 | #include <linux/slab.h> | |
15 | ||
bcf8b616 | 16 | #include <drm/drm_device.h> |
7415287e GH |
17 | #include <drm/drm_format_helper.h> |
18 | #include <drm/drm_framebuffer.h> | |
19 | #include <drm/drm_fourcc.h> | |
bcf8b616 | 20 | #include <drm/drm_print.h> |
7415287e GH |
21 | #include <drm/drm_rect.h> |
22 | ||
d55d0b06 TZ |
23 | #include "drm_format_internal.h" |
24 | ||
38b2d9d3 TZ |
25 | /** |
26 | * drm_format_conv_state_init - Initialize format-conversion state | |
27 | * @state: The state to initialize | |
28 | * | |
29 | * Clears all fields in struct drm_format_conv_state. The state will | |
30 | * be empty with no preallocated resources. | |
31 | */ | |
32 | void drm_format_conv_state_init(struct drm_format_conv_state *state) | |
33 | { | |
34 | state->tmp.mem = NULL; | |
35 | state->tmp.size = 0; | |
36 | state->tmp.preallocated = false; | |
37 | } | |
38 | EXPORT_SYMBOL(drm_format_conv_state_init); | |
39 | ||
40 | /** | |
41 | * drm_format_conv_state_copy - Copy format-conversion state | |
42 | * @state: Destination state | |
43 | * @old_state: Source state | |
44 | * | |
45 | * Copies format-conversion state from @old_state to @state; except for | |
46 | * temporary storage. | |
47 | */ | |
48 | void drm_format_conv_state_copy(struct drm_format_conv_state *state, | |
49 | const struct drm_format_conv_state *old_state) | |
50 | { | |
51 | /* | |
52 | * So far, there's only temporary storage here, which we don't | |
53 | * duplicate. Just clear the fields. | |
54 | */ | |
55 | state->tmp.mem = NULL; | |
56 | state->tmp.size = 0; | |
57 | state->tmp.preallocated = false; | |
58 | } | |
59 | EXPORT_SYMBOL(drm_format_conv_state_copy); | |
60 | ||
61 | /** | |
62 | * drm_format_conv_state_reserve - Allocates storage for format conversion | |
63 | * @state: The format-conversion state | |
64 | * @new_size: The minimum allocation size | |
65 | * @flags: Flags for kmalloc() | |
66 | * | |
67 | * Allocates at least @new_size bytes and returns a pointer to the memory | |
68 | * range. After calling this function, previously returned memory blocks | |
69 | * are invalid. It's best to collect all memory requirements of a format | |
70 | * conversion and call this function once to allocate the range. | |
71 | * | |
72 | * Returns: | |
73 | * A pointer to the allocated memory range, or NULL otherwise. | |
74 | */ | |
75 | void *drm_format_conv_state_reserve(struct drm_format_conv_state *state, | |
76 | size_t new_size, gfp_t flags) | |
77 | { | |
78 | void *mem; | |
79 | ||
80 | if (new_size <= state->tmp.size) | |
81 | goto out; | |
82 | else if (state->tmp.preallocated) | |
83 | return NULL; | |
84 | ||
85 | mem = krealloc(state->tmp.mem, new_size, flags); | |
86 | if (!mem) | |
87 | return NULL; | |
88 | ||
89 | state->tmp.mem = mem; | |
90 | state->tmp.size = new_size; | |
91 | ||
92 | out: | |
93 | return state->tmp.mem; | |
94 | } | |
95 | EXPORT_SYMBOL(drm_format_conv_state_reserve); | |
96 | ||
97 | /** | |
98 | * drm_format_conv_state_release - Releases an format-conversion storage | |
99 | * @state: The format-conversion state | |
100 | * | |
101 | * Releases the memory range references by the format-conversion state. | |
102 | * After this call, all pointers to the memory are invalid. Prefer | |
103 | * drm_format_conv_state_init() for cleaning up and unloading a driver. | |
104 | */ | |
105 | void drm_format_conv_state_release(struct drm_format_conv_state *state) | |
106 | { | |
107 | if (state->tmp.preallocated) | |
108 | return; | |
109 | ||
110 | kfree(state->tmp.mem); | |
111 | state->tmp.mem = NULL; | |
112 | state->tmp.size = 0; | |
113 | } | |
114 | EXPORT_SYMBOL(drm_format_conv_state_release); | |
115 | ||
452290f3 | 116 | static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp) |
26f024f5 | 117 | { |
bf4f6d16 | 118 | return clip->y1 * pitch + clip->x1 * cpp; |
26f024f5 GH |
119 | } |
120 | ||
452290f3 TZ |
121 | /** |
122 | * drm_fb_clip_offset - Returns the clipping rectangles byte-offset in a framebuffer | |
123 | * @pitch: Framebuffer line pitch in byte | |
124 | * @format: Framebuffer format | |
125 | * @clip: Clip rectangle | |
126 | * | |
127 | * Returns: | |
128 | * The byte offset of the clip rectangle's top-left corner within the framebuffer. | |
129 | */ | |
130 | unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format, | |
131 | const struct drm_rect *clip) | |
132 | { | |
133 | return clip_offset(clip, pitch, format->cpp[0]); | |
134 | } | |
135 | EXPORT_SYMBOL(drm_fb_clip_offset); | |
136 | ||
f241b064 TZ |
137 | /* TODO: Make this function work with multi-plane formats. */ |
138 | static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize, | |
139 | const void *vaddr, const struct drm_framebuffer *fb, | |
140 | const struct drm_rect *clip, bool vaddr_cached_hint, | |
38b2d9d3 | 141 | struct drm_format_conv_state *state, |
f241b064 | 142 | void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) |
cce6bedb TZ |
143 | { |
144 | unsigned long linepixels = drm_rect_width(clip); | |
145 | unsigned long lines = drm_rect_height(clip); | |
146 | size_t sbuf_len = linepixels * fb->format->cpp[0]; | |
147 | void *stmp = NULL; | |
148 | unsigned long i; | |
149 | const void *sbuf; | |
150 | ||
151 | /* | |
6bcfe8ea | 152 | * Some source buffers, such as DMA memory, use write-combine |
cce6bedb TZ |
153 | * caching, so reads are uncached. Speed up access by fetching |
154 | * one line at a time. | |
155 | */ | |
156 | if (!vaddr_cached_hint) { | |
38b2d9d3 | 157 | stmp = drm_format_conv_state_reserve(state, sbuf_len, GFP_KERNEL); |
cce6bedb TZ |
158 | if (!stmp) |
159 | return -ENOMEM; | |
160 | } | |
161 | ||
162 | if (!dst_pitch) | |
163 | dst_pitch = drm_rect_width(clip) * dst_pixsize; | |
164 | vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); | |
165 | ||
166 | for (i = 0; i < lines; ++i) { | |
167 | if (stmp) | |
168 | sbuf = memcpy(stmp, vaddr, sbuf_len); | |
169 | else | |
170 | sbuf = vaddr; | |
171 | xfrm_line(dst, sbuf, linepixels); | |
172 | vaddr += fb->pitches[0]; | |
173 | dst += dst_pitch; | |
174 | } | |
175 | ||
cce6bedb TZ |
176 | return 0; |
177 | } | |
178 | ||
f241b064 TZ |
179 | /* TODO: Make this function work with multi-plane formats. */ |
180 | static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize, | |
181 | const void *vaddr, const struct drm_framebuffer *fb, | |
182 | const struct drm_rect *clip, bool vaddr_cached_hint, | |
38b2d9d3 | 183 | struct drm_format_conv_state *state, |
f241b064 | 184 | void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) |
cce6bedb TZ |
185 | { |
186 | unsigned long linepixels = drm_rect_width(clip); | |
187 | unsigned long lines = drm_rect_height(clip); | |
188 | size_t dbuf_len = linepixels * dst_pixsize; | |
189 | size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */ | |
190 | size_t sbuf_len = linepixels * fb->format->cpp[0]; | |
191 | void *stmp = NULL; | |
192 | unsigned long i; | |
193 | const void *sbuf; | |
194 | void *dbuf; | |
195 | ||
196 | if (vaddr_cached_hint) { | |
38b2d9d3 | 197 | dbuf = drm_format_conv_state_reserve(state, dbuf_len, GFP_KERNEL); |
cce6bedb | 198 | } else { |
38b2d9d3 | 199 | dbuf = drm_format_conv_state_reserve(state, stmp_off + sbuf_len, GFP_KERNEL); |
cce6bedb TZ |
200 | stmp = dbuf + stmp_off; |
201 | } | |
202 | if (!dbuf) | |
203 | return -ENOMEM; | |
204 | ||
205 | if (!dst_pitch) | |
206 | dst_pitch = linepixels * dst_pixsize; | |
207 | vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); | |
208 | ||
209 | for (i = 0; i < lines; ++i) { | |
210 | if (stmp) | |
211 | sbuf = memcpy(stmp, vaddr, sbuf_len); | |
212 | else | |
213 | sbuf = vaddr; | |
214 | xfrm_line(dbuf, sbuf, linepixels); | |
215 | memcpy_toio(dst, dbuf, dbuf_len); | |
216 | vaddr += fb->pitches[0]; | |
217 | dst += dst_pitch; | |
218 | } | |
219 | ||
cce6bedb TZ |
220 | return 0; |
221 | } | |
222 | ||
f241b064 TZ |
223 | /* TODO: Make this function work with multi-plane formats. */ |
224 | static int drm_fb_xfrm(struct iosys_map *dst, | |
225 | const unsigned int *dst_pitch, const u8 *dst_pixsize, | |
504a51d7 | 226 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
f241b064 | 227 | const struct drm_rect *clip, bool vaddr_cached_hint, |
4cd24d4b | 228 | struct drm_format_conv_state *state, |
f241b064 TZ |
229 | void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) |
230 | { | |
231 | static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { | |
232 | 0, 0, 0, 0 | |
233 | }; | |
234 | ||
235 | if (!dst_pitch) | |
236 | dst_pitch = default_dst_pitch; | |
237 | ||
504a51d7 | 238 | /* TODO: handle src in I/O memory here */ |
f241b064 | 239 | if (dst[0].is_iomem) |
4cd24d4b TZ |
240 | return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0], |
241 | src[0].vaddr, fb, clip, vaddr_cached_hint, state, | |
242 | xfrm_line); | |
f241b064 | 243 | else |
4cd24d4b TZ |
244 | return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0], |
245 | src[0].vaddr, fb, clip, vaddr_cached_hint, state, | |
246 | xfrm_line); | |
f241b064 TZ |
247 | } |
248 | ||
58523a25 TZ |
249 | #define ALIGN_DOWN_PIXELS(end, n, a) \ |
250 | ((end) - ((n) & ((a) - 1))) | |
251 | ||
a376dcf4 TZ |
252 | static __always_inline void drm_fb_xfrm_line_32to8(void *dbuf, const void *sbuf, |
253 | unsigned int pixels, | |
254 | u32 (*xfrm_pixel)(u32)) | |
255 | { | |
65931bbc TZ |
256 | __le32 *dbuf32 = dbuf; |
257 | u8 *dbuf8; | |
a376dcf4 TZ |
258 | const __le32 *sbuf32 = sbuf; |
259 | const __le32 *send32 = sbuf32 + pixels; | |
260 | ||
65931bbc TZ |
261 | /* write 4 pixels at once */ |
262 | while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 4)) { | |
263 | u32 pix[4] = { | |
5024aa7a MA |
264 | le32_to_cpup(sbuf32), |
265 | le32_to_cpup(sbuf32 + 1), | |
266 | le32_to_cpup(sbuf32 + 2), | |
267 | le32_to_cpup(sbuf32 + 3), | |
65931bbc TZ |
268 | }; |
269 | /* write output bytes in reverse order for little endianness */ | |
270 | u32 val32 = xfrm_pixel(pix[0]) | | |
271 | (xfrm_pixel(pix[1]) << 8) | | |
272 | (xfrm_pixel(pix[2]) << 16) | | |
273 | (xfrm_pixel(pix[3]) << 24); | |
274 | *dbuf32++ = cpu_to_le32(val32); | |
5024aa7a | 275 | sbuf32 += ARRAY_SIZE(pix); |
65931bbc TZ |
276 | } |
277 | ||
278 | /* write trailing pixels */ | |
279 | dbuf8 = (u8 __force *)dbuf32; | |
a376dcf4 TZ |
280 | while (sbuf32 < send32) |
281 | *dbuf8++ = xfrm_pixel(le32_to_cpup(sbuf32++)); | |
282 | } | |
283 | ||
b39e5ba0 TZ |
284 | static __always_inline void drm_fb_xfrm_line_32to16(void *dbuf, const void *sbuf, |
285 | unsigned int pixels, | |
286 | u32 (*xfrm_pixel)(u32)) | |
287 | { | |
3f31a017 TZ |
288 | __le64 *dbuf64 = dbuf; |
289 | __le32 *dbuf32; | |
290 | __le16 *dbuf16; | |
b39e5ba0 TZ |
291 | const __le32 *sbuf32 = sbuf; |
292 | const __le32 *send32 = sbuf32 + pixels; | |
293 | ||
3f31a017 TZ |
294 | #if defined(CONFIG_64BIT) |
295 | /* write 4 pixels at once */ | |
296 | while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 4)) { | |
297 | u32 pix[4] = { | |
5024aa7a MA |
298 | le32_to_cpup(sbuf32), |
299 | le32_to_cpup(sbuf32 + 1), | |
300 | le32_to_cpup(sbuf32 + 2), | |
301 | le32_to_cpup(sbuf32 + 3), | |
3f31a017 TZ |
302 | }; |
303 | /* write output bytes in reverse order for little endianness */ | |
304 | u64 val64 = ((u64)xfrm_pixel(pix[0])) | | |
305 | ((u64)xfrm_pixel(pix[1]) << 16) | | |
306 | ((u64)xfrm_pixel(pix[2]) << 32) | | |
307 | ((u64)xfrm_pixel(pix[3]) << 48); | |
308 | *dbuf64++ = cpu_to_le64(val64); | |
5024aa7a | 309 | sbuf32 += ARRAY_SIZE(pix); |
3f31a017 TZ |
310 | } |
311 | #endif | |
312 | ||
313 | /* write 2 pixels at once */ | |
314 | dbuf32 = (__le32 __force *)dbuf64; | |
315 | while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 2)) { | |
316 | u32 pix[2] = { | |
5024aa7a MA |
317 | le32_to_cpup(sbuf32), |
318 | le32_to_cpup(sbuf32 + 1), | |
3f31a017 TZ |
319 | }; |
320 | /* write output bytes in reverse order for little endianness */ | |
321 | u32 val32 = xfrm_pixel(pix[0]) | | |
322 | (xfrm_pixel(pix[1]) << 16); | |
323 | *dbuf32++ = cpu_to_le32(val32); | |
5024aa7a | 324 | sbuf32 += ARRAY_SIZE(pix); |
3f31a017 TZ |
325 | } |
326 | ||
327 | /* write trailing pixel */ | |
328 | dbuf16 = (__le16 __force *)dbuf32; | |
b39e5ba0 TZ |
329 | while (sbuf32 < send32) |
330 | *dbuf16++ = cpu_to_le16(xfrm_pixel(le32_to_cpup(sbuf32++))); | |
331 | } | |
332 | ||
f46bf572 TZ |
333 | static __always_inline void drm_fb_xfrm_line_32to24(void *dbuf, const void *sbuf, |
334 | unsigned int pixels, | |
335 | u32 (*xfrm_pixel)(u32)) | |
336 | { | |
58523a25 TZ |
337 | __le32 *dbuf32 = dbuf; |
338 | u8 *dbuf8; | |
f46bf572 TZ |
339 | const __le32 *sbuf32 = sbuf; |
340 | const __le32 *send32 = sbuf32 + pixels; | |
341 | ||
58523a25 TZ |
342 | /* write pixels in chunks of 4 */ |
343 | while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 4)) { | |
344 | u32 val24[4] = { | |
5024aa7a MA |
345 | xfrm_pixel(le32_to_cpup(sbuf32)), |
346 | xfrm_pixel(le32_to_cpup(sbuf32 + 1)), | |
347 | xfrm_pixel(le32_to_cpup(sbuf32 + 2)), | |
348 | xfrm_pixel(le32_to_cpup(sbuf32 + 3)), | |
58523a25 TZ |
349 | }; |
350 | u32 out32[3] = { | |
351 | /* write output bytes in reverse order for little endianness */ | |
352 | ((val24[0] & 0x000000ff)) | | |
353 | ((val24[0] & 0x0000ff00)) | | |
354 | ((val24[0] & 0x00ff0000)) | | |
355 | ((val24[1] & 0x000000ff) << 24), | |
356 | ((val24[1] & 0x0000ff00) >> 8) | | |
357 | ((val24[1] & 0x00ff0000) >> 8) | | |
358 | ((val24[2] & 0x000000ff) << 16) | | |
359 | ((val24[2] & 0x0000ff00) << 16), | |
360 | ((val24[2] & 0x00ff0000) >> 16) | | |
361 | ((val24[3] & 0x000000ff) << 8) | | |
362 | ((val24[3] & 0x0000ff00) << 8) | | |
363 | ((val24[3] & 0x00ff0000) << 8), | |
364 | }; | |
365 | ||
366 | *dbuf32++ = cpu_to_le32(out32[0]); | |
367 | *dbuf32++ = cpu_to_le32(out32[1]); | |
368 | *dbuf32++ = cpu_to_le32(out32[2]); | |
5024aa7a | 369 | sbuf32 += ARRAY_SIZE(val24); |
58523a25 TZ |
370 | } |
371 | ||
372 | /* write trailing pixel */ | |
373 | dbuf8 = (u8 __force *)dbuf32; | |
f46bf572 TZ |
374 | while (sbuf32 < send32) { |
375 | u32 val24 = xfrm_pixel(le32_to_cpup(sbuf32++)); | |
376 | /* write output in reverse order for little endianness */ | |
377 | *dbuf8++ = (val24 & 0x000000ff); | |
378 | *dbuf8++ = (val24 & 0x0000ff00) >> 8; | |
379 | *dbuf8++ = (val24 & 0x00ff0000) >> 16; | |
380 | } | |
381 | } | |
382 | ||
d55d0b06 TZ |
383 | static __always_inline void drm_fb_xfrm_line_32to32(void *dbuf, const void *sbuf, |
384 | unsigned int pixels, | |
385 | u32 (*xfrm_pixel)(u32)) | |
386 | { | |
387 | __le32 *dbuf32 = dbuf; | |
388 | const __le32 *sbuf32 = sbuf; | |
389 | const __le32 *send32 = sbuf32 + pixels; | |
390 | ||
391 | while (sbuf32 < send32) | |
392 | *dbuf32++ = cpu_to_le32(xfrm_pixel(le32_to_cpup(sbuf32++))); | |
393 | } | |
394 | ||
7415287e GH |
395 | /** |
396 | * drm_fb_memcpy - Copy clip buffer | |
edbe262a TZ |
397 | * @dst: Array of destination buffers |
398 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
399 | * within @dst; can be NULL if scanlines are stored next to each other. | |
504a51d7 | 400 | * @src: Array of source buffers |
7415287e GH |
401 | * @fb: DRM framebuffer |
402 | * @clip: Clip rectangle area to copy | |
26f024f5 | 403 | * |
edbe262a TZ |
404 | * This function copies parts of a framebuffer to display memory. Destination and |
405 | * framebuffer formats must match. No conversion takes place. The parameters @dst, | |
504a51d7 | 406 | * @dst_pitch and @src refer to arrays. Each array must have at least as many entries |
edbe262a TZ |
407 | * as there are planes in @fb's format. Each entry stores the value for the format's |
408 | * respective color plane at the same index. | |
26f024f5 | 409 | * |
edbe262a TZ |
410 | * This function does not apply clipping on @dst (i.e. the destination is at the |
411 | * top-left corner). | |
26f024f5 | 412 | */ |
edbe262a | 413 | void drm_fb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch, |
504a51d7 | 414 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
edbe262a | 415 | const struct drm_rect *clip) |
26f024f5 | 416 | { |
edbe262a TZ |
417 | static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { |
418 | 0, 0, 0, 0 | |
419 | }; | |
26f024f5 | 420 | |
edbe262a TZ |
421 | const struct drm_format_info *format = fb->format; |
422 | unsigned int i, y, lines = drm_rect_height(clip); | |
27bd66dd | 423 | |
edbe262a TZ |
424 | if (!dst_pitch) |
425 | dst_pitch = default_dst_pitch; | |
426 | ||
427 | for (i = 0; i < format->num_planes; ++i) { | |
428 | unsigned int bpp_i = drm_format_info_bpp(format, i); | |
429 | unsigned int cpp_i = DIV_ROUND_UP(bpp_i, 8); | |
430 | size_t len_i = DIV_ROUND_UP(drm_rect_width(clip) * bpp_i, 8); | |
431 | unsigned int dst_pitch_i = dst_pitch[i]; | |
432 | struct iosys_map dst_i = dst[i]; | |
504a51d7 | 433 | struct iosys_map src_i = src[i]; |
edbe262a TZ |
434 | |
435 | if (!dst_pitch_i) | |
436 | dst_pitch_i = len_i; | |
437 | ||
504a51d7 | 438 | iosys_map_incr(&src_i, clip_offset(clip, fb->pitches[i], cpp_i)); |
edbe262a | 439 | for (y = 0; y < lines; y++) { |
504a51d7 TZ |
440 | /* TODO: handle src_i in I/O memory here */ |
441 | iosys_map_memcpy_to(&dst_i, 0, src_i.vaddr, len_i); | |
442 | iosys_map_incr(&src_i, fb->pitches[i]); | |
edbe262a TZ |
443 | iosys_map_incr(&dst_i, dst_pitch_i); |
444 | } | |
bf4f6d16 | 445 | } |
26f024f5 | 446 | } |
edbe262a | 447 | EXPORT_SYMBOL(drm_fb_memcpy); |
26f024f5 | 448 | |
41fd6f0a TZ |
449 | static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels) |
450 | { | |
451 | u16 *dbuf16 = dbuf; | |
452 | const u16 *sbuf16 = sbuf; | |
453 | const u16 *send16 = sbuf16 + pixels; | |
454 | ||
455 | while (sbuf16 < send16) | |
456 | *dbuf16++ = swab16(*sbuf16++); | |
457 | } | |
458 | ||
459 | static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels) | |
460 | { | |
461 | u32 *dbuf32 = dbuf; | |
462 | const u32 *sbuf32 = sbuf; | |
463 | const u32 *send32 = sbuf32 + pixels; | |
464 | ||
465 | while (sbuf32 < send32) | |
466 | *dbuf32++ = swab32(*sbuf32++); | |
467 | } | |
468 | ||
7415287e | 469 | /** |
bd34cea2 | 470 | * drm_fb_swab - Swap bytes into clip buffer |
ce582859 TZ |
471 | * @dst: Array of destination buffers |
472 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
473 | * within @dst; can be NULL if scanlines are stored next to each other. | |
504a51d7 | 474 | * @src: Array of source buffers |
7415287e GH |
475 | * @fb: DRM framebuffer |
476 | * @clip: Clip rectangle area to copy | |
bd34cea2 | 477 | * @cached: Source buffer is mapped cached (eg. not write-combined) |
4cd24d4b | 478 | * @state: Transform and conversion state |
bd34cea2 | 479 | * |
ce582859 TZ |
480 | * This function copies parts of a framebuffer to display memory and swaps per-pixel |
481 | * bytes during the process. Destination and framebuffer formats must match. The | |
504a51d7 | 482 | * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at |
ce582859 TZ |
483 | * least as many entries as there are planes in @fb's format. Each entry stores the |
484 | * value for the format's respective color plane at the same index. If @cached is | |
485 | * false a temporary buffer is used to cache one pixel line at a time to speed up | |
486 | * slow uncached reads. | |
bd34cea2 | 487 | * |
ce582859 TZ |
488 | * This function does not apply clipping on @dst (i.e. the destination is at the |
489 | * top-left corner). | |
7415287e | 490 | */ |
ce582859 | 491 | void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch, |
504a51d7 | 492 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
4cd24d4b TZ |
493 | const struct drm_rect *clip, bool cached, |
494 | struct drm_format_conv_state *state) | |
7415287e | 495 | { |
ce582859 TZ |
496 | const struct drm_format_info *format = fb->format; |
497 | u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8); | |
498 | void (*swab_line)(void *dbuf, const void *sbuf, unsigned int npixels); | |
bd34cea2 | 499 | |
cce6bedb TZ |
500 | switch (cpp) { |
501 | case 4: | |
ce582859 | 502 | swab_line = drm_fb_swab32_line; |
cce6bedb TZ |
503 | break; |
504 | case 2: | |
ce582859 | 505 | swab_line = drm_fb_swab16_line; |
cce6bedb TZ |
506 | break; |
507 | default: | |
508 | drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n", | |
ce582859 | 509 | &format->format); |
ce582859 | 510 | return; |
f241b064 | 511 | } |
ce582859 | 512 | |
4cd24d4b | 513 | drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, state, swab_line); |
7415287e | 514 | } |
bd34cea2 | 515 | EXPORT_SYMBOL(drm_fb_swab); |
7415287e | 516 | |
cce6bedb | 517 | static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels) |
cee0b7cb | 518 | { |
a376dcf4 | 519 | drm_fb_xfrm_line_32to8(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb332); |
cee0b7cb NT |
520 | } |
521 | ||
522 | /** | |
523 | * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer | |
e13140a0 TZ |
524 | * @dst: Array of RGB332 destination buffers |
525 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
526 | * within @dst; can be NULL if scanlines are stored next to each other. | |
504a51d7 | 527 | * @src: Array of XRGB8888 source buffers |
cee0b7cb NT |
528 | * @fb: DRM framebuffer |
529 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 530 | * @state: Transform and conversion state |
cee0b7cb | 531 | * |
e13140a0 TZ |
532 | * This function copies parts of a framebuffer to display memory and converts the |
533 | * color format during the process. Destination and framebuffer formats must match. The | |
504a51d7 | 534 | * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at |
e13140a0 TZ |
535 | * least as many entries as there are planes in @fb's format. Each entry stores the |
536 | * value for the format's respective color plane at the same index. | |
537 | * | |
538 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
539 | * top-left corner). | |
540 | * | |
541 | * Drivers can use this function for RGB332 devices that don't support XRGB8888 natively. | |
cee0b7cb | 542 | */ |
e13140a0 | 543 | void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch, |
504a51d7 | 544 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
4cd24d4b | 545 | const struct drm_rect *clip, struct drm_format_conv_state *state) |
cee0b7cb | 546 | { |
f241b064 TZ |
547 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { |
548 | 1, | |
e13140a0 TZ |
549 | }; |
550 | ||
4cd24d4b | 551 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
f241b064 | 552 | drm_fb_xrgb8888_to_rgb332_line); |
cee0b7cb NT |
553 | } |
554 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); | |
555 | ||
a6fdb669 | 556 | static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels) |
7415287e | 557 | { |
b39e5ba0 TZ |
558 | drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb565); |
559 | } | |
d653bd39 | 560 | |
b39e5ba0 TZ |
561 | static __always_inline u32 drm_xrgb8888_to_rgb565_swab(u32 pix) |
562 | { | |
563 | return swab16(drm_pixel_xrgb8888_to_rgb565(pix)); | |
69add027 TZ |
564 | } |
565 | ||
f21d62c9 | 566 | /* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */ |
a6fdb669 | 567 | static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, |
69add027 TZ |
568 | unsigned int pixels) |
569 | { | |
b39e5ba0 | 570 | drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_xrgb8888_to_rgb565_swab); |
bcc44420 GH |
571 | } |
572 | ||
573 | /** | |
574 | * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer | |
ab298c29 TZ |
575 | * @dst: Array of RGB565 destination buffers |
576 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
577 | * within @dst; can be NULL if scanlines are stored next to each other. | |
504a51d7 | 578 | * @src: Array of XRGB8888 source buffer |
bcc44420 GH |
579 | * @fb: DRM framebuffer |
580 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 581 | * @state: Transform and conversion state |
d653bd39 | 582 | * @swab: Swap bytes |
bcc44420 | 583 | * |
ab298c29 TZ |
584 | * This function copies parts of a framebuffer to display memory and converts the |
585 | * color format during the process. Destination and framebuffer formats must match. The | |
504a51d7 | 586 | * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at |
ab298c29 TZ |
587 | * least as many entries as there are planes in @fb's format. Each entry stores the |
588 | * value for the format's respective color plane at the same index. | |
589 | * | |
590 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
591 | * top-left corner). | |
592 | * | |
593 | * Drivers can use this function for RGB565 devices that don't support XRGB8888 natively. | |
bcc44420 | 594 | */ |
ab298c29 | 595 | void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, |
504a51d7 | 596 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
4cd24d4b TZ |
597 | const struct drm_rect *clip, struct drm_format_conv_state *state, |
598 | bool swab) | |
bcc44420 | 599 | { |
f241b064 TZ |
600 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { |
601 | 2, | |
ab298c29 | 602 | }; |
f241b064 | 603 | |
ab298c29 TZ |
604 | void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels); |
605 | ||
cce6bedb | 606 | if (swab) |
ab298c29 | 607 | xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line; |
cce6bedb | 608 | else |
ab298c29 | 609 | xfrm_line = drm_fb_xrgb8888_to_rgb565_line; |
7415287e | 610 | |
4cd24d4b | 611 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, xfrm_line); |
bcc44420 | 612 | } |
ab298c29 | 613 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); |
bcc44420 | 614 | |
10cd592e TZ |
615 | static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels) |
616 | { | |
b39e5ba0 | 617 | drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xrgb1555); |
10cd592e TZ |
618 | } |
619 | ||
620 | /** | |
621 | * drm_fb_xrgb8888_to_xrgb1555 - Convert XRGB8888 to XRGB1555 clip buffer | |
622 | * @dst: Array of XRGB1555 destination buffers | |
623 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
624 | * within @dst; can be NULL if scanlines are stored next to each other. | |
625 | * @src: Array of XRGB8888 source buffer | |
626 | * @fb: DRM framebuffer | |
627 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 628 | * @state: Transform and conversion state |
10cd592e TZ |
629 | * |
630 | * This function copies parts of a framebuffer to display memory and converts | |
631 | * the color format during the process. The parameters @dst, @dst_pitch and | |
632 | * @src refer to arrays. Each array must have at least as many entries as | |
633 | * there are planes in @fb's format. Each entry stores the value for the | |
634 | * format's respective color plane at the same index. | |
635 | * | |
636 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
637 | * top-left corner). | |
638 | * | |
639 | * Drivers can use this function for XRGB1555 devices that don't support | |
640 | * XRGB8888 natively. | |
641 | */ | |
642 | void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch, | |
643 | const struct iosys_map *src, const struct drm_framebuffer *fb, | |
4cd24d4b | 644 | const struct drm_rect *clip, struct drm_format_conv_state *state) |
10cd592e TZ |
645 | { |
646 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { | |
647 | 2, | |
648 | }; | |
649 | ||
4cd24d4b | 650 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
10cd592e TZ |
651 | drm_fb_xrgb8888_to_xrgb1555_line); |
652 | } | |
653 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555); | |
654 | ||
655 | static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsigned int pixels) | |
656 | { | |
b39e5ba0 | 657 | drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_argb1555); |
10cd592e TZ |
658 | } |
659 | ||
660 | /** | |
661 | * drm_fb_xrgb8888_to_argb1555 - Convert XRGB8888 to ARGB1555 clip buffer | |
662 | * @dst: Array of ARGB1555 destination buffers | |
663 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
664 | * within @dst; can be NULL if scanlines are stored next to each other. | |
665 | * @src: Array of XRGB8888 source buffer | |
666 | * @fb: DRM framebuffer | |
667 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 668 | * @state: Transform and conversion state |
10cd592e TZ |
669 | * |
670 | * This function copies parts of a framebuffer to display memory and converts | |
671 | * the color format during the process. The parameters @dst, @dst_pitch and | |
672 | * @src refer to arrays. Each array must have at least as many entries as | |
673 | * there are planes in @fb's format. Each entry stores the value for the | |
674 | * format's respective color plane at the same index. | |
675 | * | |
676 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
677 | * top-left corner). | |
678 | * | |
679 | * Drivers can use this function for ARGB1555 devices that don't support | |
680 | * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion. | |
681 | */ | |
682 | void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch, | |
683 | const struct iosys_map *src, const struct drm_framebuffer *fb, | |
4cd24d4b | 684 | const struct drm_rect *clip, struct drm_format_conv_state *state) |
10cd592e TZ |
685 | { |
686 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { | |
687 | 2, | |
688 | }; | |
689 | ||
4cd24d4b | 690 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
10cd592e TZ |
691 | drm_fb_xrgb8888_to_argb1555_line); |
692 | } | |
693 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555); | |
694 | ||
695 | static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsigned int pixels) | |
696 | { | |
b39e5ba0 | 697 | drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgba5551); |
10cd592e TZ |
698 | } |
699 | ||
700 | /** | |
701 | * drm_fb_xrgb8888_to_rgba5551 - Convert XRGB8888 to RGBA5551 clip buffer | |
702 | * @dst: Array of RGBA5551 destination buffers | |
703 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
704 | * within @dst; can be NULL if scanlines are stored next to each other. | |
705 | * @src: Array of XRGB8888 source buffer | |
706 | * @fb: DRM framebuffer | |
707 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 708 | * @state: Transform and conversion state |
10cd592e TZ |
709 | * |
710 | * This function copies parts of a framebuffer to display memory and converts | |
711 | * the color format during the process. The parameters @dst, @dst_pitch and | |
712 | * @src refer to arrays. Each array must have at least as many entries as | |
713 | * there are planes in @fb's format. Each entry stores the value for the | |
714 | * format's respective color plane at the same index. | |
715 | * | |
716 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
717 | * top-left corner). | |
718 | * | |
719 | * Drivers can use this function for RGBA5551 devices that don't support | |
720 | * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion. | |
721 | */ | |
722 | void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch, | |
723 | const struct iosys_map *src, const struct drm_framebuffer *fb, | |
4cd24d4b | 724 | const struct drm_rect *clip, struct drm_format_conv_state *state) |
10cd592e TZ |
725 | { |
726 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { | |
727 | 2, | |
728 | }; | |
729 | ||
4cd24d4b | 730 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
10cd592e TZ |
731 | drm_fb_xrgb8888_to_rgba5551_line); |
732 | } | |
733 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551); | |
734 | ||
a6fdb669 | 735 | static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels) |
ec3de7a4 | 736 | { |
f46bf572 | 737 | drm_fb_xfrm_line_32to24(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb888); |
ec3de7a4 GH |
738 | } |
739 | ||
bcf80d6e NT |
740 | /** |
741 | * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer | |
c4863ce0 TZ |
742 | * @dst: Array of RGB888 destination buffers |
743 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
744 | * within @dst; can be NULL if scanlines are stored next to each other. | |
504a51d7 | 745 | * @src: Array of XRGB8888 source buffers |
bcf80d6e NT |
746 | * @fb: DRM framebuffer |
747 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 748 | * @state: Transform and conversion state |
bcf80d6e | 749 | * |
c4863ce0 TZ |
750 | * This function copies parts of a framebuffer to display memory and converts the |
751 | * color format during the process. Destination and framebuffer formats must match. The | |
504a51d7 | 752 | * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at |
c4863ce0 TZ |
753 | * least as many entries as there are planes in @fb's format. Each entry stores the |
754 | * value for the format's respective color plane at the same index. | |
755 | * | |
756 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
757 | * top-left corner). | |
ec3de7a4 GH |
758 | * |
759 | * Drivers can use this function for RGB888 devices that don't natively | |
760 | * support XRGB8888. | |
ec3de7a4 | 761 | */ |
c4863ce0 | 762 | void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch, |
504a51d7 | 763 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
4cd24d4b | 764 | const struct drm_rect *clip, struct drm_format_conv_state *state) |
ec3de7a4 | 765 | { |
f241b064 TZ |
766 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { |
767 | 3, | |
c4863ce0 TZ |
768 | }; |
769 | ||
4cd24d4b | 770 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
f241b064 | 771 | drm_fb_xrgb8888_to_rgb888_line); |
ec3de7a4 | 772 | } |
c4863ce0 | 773 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); |
ec3de7a4 | 774 | |
c9043706 KK |
775 | static void drm_fb_xrgb8888_to_bgr888_line(void *dbuf, const void *sbuf, unsigned int pixels) |
776 | { | |
f46bf572 | 777 | drm_fb_xfrm_line_32to24(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_bgr888); |
c9043706 KK |
778 | } |
779 | ||
780 | /** | |
781 | * drm_fb_xrgb8888_to_bgr888 - Convert XRGB8888 to BGR888 clip buffer | |
782 | * @dst: Array of BGR888 destination buffers | |
783 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
784 | * within @dst; can be NULL if scanlines are stored next to each other. | |
785 | * @src: Array of XRGB8888 source buffers | |
786 | * @fb: DRM framebuffer | |
787 | * @clip: Clip rectangle area to copy | |
788 | * @state: Transform and conversion state | |
789 | * | |
790 | * This function copies parts of a framebuffer to display memory and converts the | |
791 | * color format during the process. Destination and framebuffer formats must match. The | |
792 | * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at | |
793 | * least as many entries as there are planes in @fb's format. Each entry stores the | |
794 | * value for the format's respective color plane at the same index. | |
795 | * | |
796 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
797 | * top-left corner). | |
798 | * | |
799 | * Drivers can use this function for BGR888 devices that don't natively | |
800 | * support XRGB8888. | |
801 | */ | |
802 | void drm_fb_xrgb8888_to_bgr888(struct iosys_map *dst, const unsigned int *dst_pitch, | |
803 | const struct iosys_map *src, const struct drm_framebuffer *fb, | |
804 | const struct drm_rect *clip, struct drm_format_conv_state *state) | |
805 | { | |
806 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { | |
807 | 3, | |
808 | }; | |
809 | ||
810 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, | |
811 | drm_fb_xrgb8888_to_bgr888_line); | |
812 | } | |
813 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_bgr888); | |
814 | ||
175073d6 TZ |
815 | static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) |
816 | { | |
d55d0b06 | 817 | drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_argb8888); |
175073d6 TZ |
818 | } |
819 | ||
820 | /** | |
821 | * drm_fb_xrgb8888_to_argb8888 - Convert XRGB8888 to ARGB8888 clip buffer | |
822 | * @dst: Array of ARGB8888 destination buffers | |
823 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
824 | * within @dst; can be NULL if scanlines are stored next to each other. | |
825 | * @src: Array of XRGB8888 source buffer | |
826 | * @fb: DRM framebuffer | |
827 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 828 | * @state: Transform and conversion state |
175073d6 TZ |
829 | * |
830 | * This function copies parts of a framebuffer to display memory and converts the | |
831 | * color format during the process. The parameters @dst, @dst_pitch and @src refer | |
832 | * to arrays. Each array must have at least as many entries as there are planes in | |
833 | * @fb's format. Each entry stores the value for the format's respective color plane | |
834 | * at the same index. | |
835 | * | |
836 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
837 | * top-left corner). | |
838 | * | |
839 | * Drivers can use this function for ARGB8888 devices that don't support XRGB8888 | |
840 | * natively. It sets an opaque alpha channel as part of the conversion. | |
841 | */ | |
842 | void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch, | |
843 | const struct iosys_map *src, const struct drm_framebuffer *fb, | |
4cd24d4b | 844 | const struct drm_rect *clip, struct drm_format_conv_state *state) |
175073d6 TZ |
845 | { |
846 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { | |
847 | 4, | |
848 | }; | |
849 | ||
4cd24d4b | 850 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
175073d6 TZ |
851 | drm_fb_xrgb8888_to_argb8888_line); |
852 | } | |
853 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888); | |
854 | ||
9abecb1d TR |
855 | static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels) |
856 | { | |
d55d0b06 | 857 | drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_abgr8888); |
9abecb1d TR |
858 | } |
859 | ||
860 | static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch, | |
861 | const struct iosys_map *src, | |
862 | const struct drm_framebuffer *fb, | |
4cd24d4b TZ |
863 | const struct drm_rect *clip, |
864 | struct drm_format_conv_state *state) | |
9abecb1d TR |
865 | { |
866 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { | |
867 | 4, | |
868 | }; | |
869 | ||
4cd24d4b | 870 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
9abecb1d TR |
871 | drm_fb_xrgb8888_to_abgr8888_line); |
872 | } | |
873 | ||
874 | static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels) | |
875 | { | |
d55d0b06 | 876 | drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xbgr8888); |
9abecb1d TR |
877 | } |
878 | ||
879 | static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch, | |
880 | const struct iosys_map *src, | |
881 | const struct drm_framebuffer *fb, | |
4cd24d4b TZ |
882 | const struct drm_rect *clip, |
883 | struct drm_format_conv_state *state) | |
9abecb1d TR |
884 | { |
885 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { | |
886 | 4, | |
887 | }; | |
888 | ||
4cd24d4b | 889 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
9abecb1d TR |
890 | drm_fb_xrgb8888_to_xbgr8888_line); |
891 | } | |
892 | ||
a6fdb669 | 893 | static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) |
877691b9 | 894 | { |
d55d0b06 | 895 | drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xrgb2101010); |
877691b9 HM |
896 | } |
897 | ||
898 | /** | |
ce73f456 TZ |
899 | * drm_fb_xrgb8888_to_xrgb2101010 - Convert XRGB8888 to XRGB2101010 clip buffer |
900 | * @dst: Array of XRGB2101010 destination buffers | |
901 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
902 | * within @dst; can be NULL if scanlines are stored next to each other. | |
504a51d7 | 903 | * @src: Array of XRGB8888 source buffers |
877691b9 HM |
904 | * @fb: DRM framebuffer |
905 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 906 | * @state: Transform and conversion state |
877691b9 | 907 | * |
ce73f456 TZ |
908 | * This function copies parts of a framebuffer to display memory and converts the |
909 | * color format during the process. Destination and framebuffer formats must match. The | |
504a51d7 | 910 | * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at |
ce73f456 TZ |
911 | * least as many entries as there are planes in @fb's format. Each entry stores the |
912 | * value for the format's respective color plane at the same index. | |
913 | * | |
914 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
915 | * top-left corner). | |
916 | * | |
917 | * Drivers can use this function for XRGB2101010 devices that don't support XRGB8888 | |
918 | * natively. | |
877691b9 | 919 | */ |
ce73f456 | 920 | void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, |
504a51d7 | 921 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
4cd24d4b TZ |
922 | const struct drm_rect *clip, |
923 | struct drm_format_conv_state *state) | |
877691b9 | 924 | { |
f241b064 TZ |
925 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { |
926 | 4, | |
ce73f456 TZ |
927 | }; |
928 | ||
4cd24d4b | 929 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
f241b064 | 930 | drm_fb_xrgb8888_to_xrgb2101010_line); |
877691b9 | 931 | } |
45311431 | 932 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010); |
877691b9 | 933 | |
56119bfb TZ |
934 | static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) |
935 | { | |
d55d0b06 | 936 | drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_argb2101010); |
56119bfb TZ |
937 | } |
938 | ||
939 | /** | |
940 | * drm_fb_xrgb8888_to_argb2101010 - Convert XRGB8888 to ARGB2101010 clip buffer | |
941 | * @dst: Array of ARGB2101010 destination buffers | |
942 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
943 | * within @dst; can be NULL if scanlines are stored next to each other. | |
944 | * @src: Array of XRGB8888 source buffers | |
945 | * @fb: DRM framebuffer | |
946 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 947 | * @state: Transform and conversion state |
56119bfb TZ |
948 | * |
949 | * This function copies parts of a framebuffer to display memory and converts | |
950 | * the color format during the process. The parameters @dst, @dst_pitch and | |
951 | * @src refer to arrays. Each array must have at least as many entries as | |
952 | * there are planes in @fb's format. Each entry stores the value for the | |
953 | * format's respective color plane at the same index. | |
954 | * | |
955 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
956 | * top-left corner). | |
957 | * | |
958 | * Drivers can use this function for ARGB2101010 devices that don't support XRGB8888 | |
959 | * natively. | |
960 | */ | |
961 | void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, | |
962 | const struct iosys_map *src, const struct drm_framebuffer *fb, | |
4cd24d4b TZ |
963 | const struct drm_rect *clip, |
964 | struct drm_format_conv_state *state) | |
56119bfb TZ |
965 | { |
966 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { | |
967 | 4, | |
968 | }; | |
969 | ||
4cd24d4b | 970 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
56119bfb TZ |
971 | drm_fb_xrgb8888_to_argb2101010_line); |
972 | } | |
973 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010); | |
974 | ||
a6fdb669 | 975 | static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels) |
4a564e59 | 976 | { |
a376dcf4 | 977 | drm_fb_xfrm_line_32to8(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_r8_bt601); |
4a564e59 JMC |
978 | } |
979 | ||
7415287e GH |
980 | /** |
981 | * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale | |
7bef6449 TZ |
982 | * @dst: Array of 8-bit grayscale destination buffers |
983 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
984 | * within @dst; can be NULL if scanlines are stored next to each other. | |
504a51d7 | 985 | * @src: Array of XRGB8888 source buffers |
7415287e GH |
986 | * @fb: DRM framebuffer |
987 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 988 | * @state: Transform and conversion state |
7415287e | 989 | * |
7bef6449 TZ |
990 | * This function copies parts of a framebuffer to display memory and converts the |
991 | * color format during the process. Destination and framebuffer formats must match. The | |
504a51d7 | 992 | * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at |
7bef6449 TZ |
993 | * least as many entries as there are planes in @fb's format. Each entry stores the |
994 | * value for the format's respective color plane at the same index. | |
7415287e | 995 | * |
7bef6449 TZ |
996 | * This function does not apply clipping on @dst (i.e. the destination is at the |
997 | * top-left corner). | |
7415287e | 998 | * |
7bef6449 TZ |
999 | * DRM doesn't have native monochrome or grayscale support. Drivers can use this |
1000 | * function for grayscale devices that don't support XRGB8888 natively.Such | |
1001 | * drivers can announce the commonly supported XR24 format to userspace and use | |
1002 | * this function to convert to the native format. Monochrome drivers will use the | |
1003 | * most significant bit, where 1 means foreground color and 0 background color. | |
1004 | * ITU BT.601 is being used for the RGB -> luma (brightness) conversion. | |
7415287e | 1005 | */ |
7bef6449 | 1006 | void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch, |
504a51d7 | 1007 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
4cd24d4b | 1008 | const struct drm_rect *clip, struct drm_format_conv_state *state) |
7415287e | 1009 | { |
f241b064 TZ |
1010 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { |
1011 | 1, | |
7bef6449 TZ |
1012 | }; |
1013 | ||
4cd24d4b | 1014 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, |
f241b064 | 1015 | drm_fb_xrgb8888_to_gray8_line); |
7415287e GH |
1016 | } |
1017 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); | |
1018 | ||
966a0d49 TZ |
1019 | static void drm_fb_argb8888_to_argb4444_line(void *dbuf, const void *sbuf, unsigned int pixels) |
1020 | { | |
b39e5ba0 | 1021 | drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_argb8888_to_argb4444); |
966a0d49 TZ |
1022 | } |
1023 | ||
1024 | /** | |
1025 | * drm_fb_argb8888_to_argb4444 - Convert ARGB8888 to ARGB4444 clip buffer | |
1026 | * @dst: Array of ARGB4444 destination buffers | |
1027 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
1028 | * within @dst; can be NULL if scanlines are stored next to each other. | |
1029 | * @src: Array of ARGB8888 source buffer | |
1030 | * @fb: DRM framebuffer | |
1031 | * @clip: Clip rectangle area to copy | |
1032 | * @state: Transform and conversion state | |
1033 | * | |
1034 | * This function copies parts of a framebuffer to display memory and converts | |
1035 | * the color format during the process. The parameters @dst, @dst_pitch and | |
1036 | * @src refer to arrays. Each array must have at least as many entries as | |
1037 | * there are planes in @fb's format. Each entry stores the value for the | |
1038 | * format's respective color plane at the same index. | |
1039 | * | |
1040 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
1041 | * top-left corner). | |
1042 | * | |
1043 | * Drivers can use this function for ARGB4444 devices that don't support | |
1044 | * ARGB8888 natively. | |
1045 | */ | |
1046 | void drm_fb_argb8888_to_argb4444(struct iosys_map *dst, const unsigned int *dst_pitch, | |
1047 | const struct iosys_map *src, const struct drm_framebuffer *fb, | |
1048 | const struct drm_rect *clip, struct drm_format_conv_state *state) | |
1049 | { | |
1050 | static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { | |
1051 | 2, | |
1052 | }; | |
1053 | ||
1054 | drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, | |
1055 | drm_fb_argb8888_to_argb4444_line); | |
1056 | } | |
1057 | EXPORT_SYMBOL(drm_fb_argb8888_to_argb4444); | |
1058 | ||
900d3e4a | 1059 | /** |
71bf5587 TZ |
1060 | * drm_fb_blit - Copy parts of a framebuffer to display memory |
1061 | * @dst: Array of display-memory addresses to copy to | |
1062 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
1063 | * within @dst; can be NULL if scanlines are stored next to each other. | |
900d3e4a | 1064 | * @dst_format: FOURCC code of the display's color format |
504a51d7 | 1065 | * @src: The framebuffer memory to copy from |
900d3e4a TZ |
1066 | * @fb: The framebuffer to copy from |
1067 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 1068 | * @state: Transform and conversion state |
900d3e4a TZ |
1069 | * |
1070 | * This function copies parts of a framebuffer to display memory. If the | |
1071 | * formats of the display and the framebuffer mismatch, the blit function | |
71bf5587 | 1072 | * will attempt to convert between them during the process. The parameters @dst, |
504a51d7 | 1073 | * @dst_pitch and @src refer to arrays. Each array must have at least as many |
71bf5587 TZ |
1074 | * entries as there are planes in @dst_format's format. Each entry stores the |
1075 | * value for the format's respective color plane at the same index. | |
1076 | * | |
1077 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
1078 | * top-left corner). | |
900d3e4a | 1079 | * |
900d3e4a TZ |
1080 | * Returns: |
1081 | * 0 on success, or | |
1082 | * -EINVAL if the color-format conversion failed, or | |
1083 | * a negative error code otherwise. | |
1084 | */ | |
71bf5587 | 1085 | int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format, |
504a51d7 | 1086 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
4cd24d4b | 1087 | const struct drm_rect *clip, struct drm_format_conv_state *state) |
900d3e4a TZ |
1088 | { |
1089 | uint32_t fb_format = fb->format->format; | |
1090 | ||
f238ac30 | 1091 | if (fb_format == dst_format) { |
504a51d7 | 1092 | drm_fb_memcpy(dst, dst_pitch, src, fb, clip); |
900d3e4a | 1093 | return 0; |
f238ac30 | 1094 | } else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) { |
4cd24d4b | 1095 | drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state); |
f238ac30 TZ |
1096 | return 0; |
1097 | } else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) { | |
4cd24d4b | 1098 | drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state); |
f238ac30 TZ |
1099 | return 0; |
1100 | } else if (fb_format == DRM_FORMAT_XRGB8888) { | |
1101 | if (dst_format == DRM_FORMAT_RGB565) { | |
4cd24d4b | 1102 | drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state, false); |
900d3e4a | 1103 | return 0; |
10cd592e | 1104 | } else if (dst_format == DRM_FORMAT_XRGB1555) { |
4cd24d4b | 1105 | drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, state); |
10cd592e TZ |
1106 | return 0; |
1107 | } else if (dst_format == DRM_FORMAT_ARGB1555) { | |
4cd24d4b | 1108 | drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip, state); |
10cd592e TZ |
1109 | return 0; |
1110 | } else if (dst_format == DRM_FORMAT_RGBA5551) { | |
4cd24d4b | 1111 | drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip, state); |
10cd592e | 1112 | return 0; |
f238ac30 | 1113 | } else if (dst_format == DRM_FORMAT_RGB888) { |
4cd24d4b | 1114 | drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip, state); |
900d3e4a | 1115 | return 0; |
c9043706 KK |
1116 | } else if (dst_format == DRM_FORMAT_BGR888) { |
1117 | drm_fb_xrgb8888_to_bgr888(dst, dst_pitch, src, fb, clip, state); | |
1118 | return 0; | |
175073d6 | 1119 | } else if (dst_format == DRM_FORMAT_ARGB8888) { |
4cd24d4b | 1120 | drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip, state); |
175073d6 | 1121 | return 0; |
9abecb1d | 1122 | } else if (dst_format == DRM_FORMAT_XBGR8888) { |
4cd24d4b | 1123 | drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip, state); |
9abecb1d TR |
1124 | return 0; |
1125 | } else if (dst_format == DRM_FORMAT_ABGR8888) { | |
4cd24d4b | 1126 | drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip, state); |
9abecb1d | 1127 | return 0; |
f238ac30 | 1128 | } else if (dst_format == DRM_FORMAT_XRGB2101010) { |
4cd24d4b | 1129 | drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip, state); |
26c30f22 | 1130 | return 0; |
56119bfb | 1131 | } else if (dst_format == DRM_FORMAT_ARGB2101010) { |
4cd24d4b | 1132 | drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip, state); |
56119bfb | 1133 | return 0; |
f238ac30 | 1134 | } else if (dst_format == DRM_FORMAT_BGRX8888) { |
4cd24d4b | 1135 | drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state); |
e08a99d0 | 1136 | return 0; |
26c30f22 | 1137 | } |
900d3e4a TZ |
1138 | } |
1139 | ||
7e553e2a TZ |
1140 | drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n", |
1141 | &fb_format, &dst_format); | |
1142 | ||
900d3e4a TZ |
1143 | return -EINVAL; |
1144 | } | |
71bf5587 | 1145 | EXPORT_SYMBOL(drm_fb_blit); |
bcf8b616 | 1146 | |
a6fdb669 | 1147 | static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int pixels) |
7392f245 | 1148 | { |
a6fdb669 TZ |
1149 | u8 *dbuf8 = dbuf; |
1150 | const u8 *sbuf8 = sbuf; | |
1151 | ||
7392f245 GU |
1152 | while (pixels) { |
1153 | unsigned int i, bits = min(pixels, 8U); | |
1154 | u8 byte = 0; | |
bcf8b616 | 1155 | |
7392f245 | 1156 | for (i = 0; i < bits; i++, pixels--) { |
a6fdb669 | 1157 | if (*sbuf8++ >= 128) |
7392f245 | 1158 | byte |= BIT(i); |
bcf8b616 | 1159 | } |
a6fdb669 | 1160 | *dbuf8++ = byte; |
bcf8b616 JMC |
1161 | } |
1162 | } | |
1163 | ||
1164 | /** | |
9b13a3fc | 1165 | * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome |
b3aca563 TZ |
1166 | * @dst: Array of monochrome destination buffers (0=black, 1=white) |
1167 | * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines | |
1168 | * within @dst; can be NULL if scanlines are stored next to each other. | |
504a51d7 | 1169 | * @src: Array of XRGB8888 source buffers |
bcf8b616 JMC |
1170 | * @fb: DRM framebuffer |
1171 | * @clip: Clip rectangle area to copy | |
4cd24d4b | 1172 | * @state: Transform and conversion state |
bcf8b616 | 1173 | * |
b3aca563 TZ |
1174 | * This function copies parts of a framebuffer to display memory and converts the |
1175 | * color format during the process. Destination and framebuffer formats must match. The | |
504a51d7 | 1176 | * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at |
b3aca563 TZ |
1177 | * least as many entries as there are planes in @fb's format. Each entry stores the |
1178 | * value for the format's respective color plane at the same index. | |
1179 | * | |
1180 | * This function does not apply clipping on @dst (i.e. the destination is at the | |
1181 | * top-left corner). The first pixel (upper left corner of the clip rectangle) will | |
1182 | * be converted and copied to the first bit (LSB) in the first byte of the monochrome | |
1183 | * destination buffer. If the caller requires that the first pixel in a byte must | |
1184 | * be located at an x-coordinate that is a multiple of 8, then the caller must take | |
1185 | * care itself of supplying a suitable clip rectangle. | |
1186 | * | |
1187 | * DRM doesn't have native monochrome support. Drivers can use this function for | |
1188 | * monochrome devices that don't support XRGB8888 natively. Such drivers can | |
1189 | * announce the commonly supported XR24 format to userspace and use this function | |
1190 | * to convert to the native format. | |
bcf8b616 JMC |
1191 | * |
1192 | * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and | |
9b13a3fc | 1193 | * then the result is converted from grayscale to monochrome. |
bcf8b616 | 1194 | */ |
b3aca563 | 1195 | void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch, |
504a51d7 | 1196 | const struct iosys_map *src, const struct drm_framebuffer *fb, |
4cd24d4b | 1197 | const struct drm_rect *clip, struct drm_format_conv_state *state) |
bcf8b616 | 1198 | { |
b3aca563 TZ |
1199 | static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { |
1200 | 0, 0, 0, 0 | |
1201 | }; | |
bcf8b616 | 1202 | unsigned int linepixels = drm_rect_width(clip); |
7392f245 | 1203 | unsigned int lines = drm_rect_height(clip); |
bcf8b616 JMC |
1204 | unsigned int cpp = fb->format->cpp[0]; |
1205 | unsigned int len_src32 = linepixels * cpp; | |
1206 | struct drm_device *dev = fb->dev; | |
504a51d7 | 1207 | void *vaddr = src[0].vaddr; |
b3aca563 | 1208 | unsigned int dst_pitch_0; |
bcf8b616 | 1209 | unsigned int y; |
b3aca563 | 1210 | u8 *mono = dst[0].vaddr, *gray8; |
bcf8b616 JMC |
1211 | u32 *src32; |
1212 | ||
1213 | if (drm_WARN_ON(dev, fb->format->format != DRM_FORMAT_XRGB8888)) | |
1214 | return; | |
1215 | ||
b3aca563 TZ |
1216 | if (!dst_pitch) |
1217 | dst_pitch = default_dst_pitch; | |
1218 | dst_pitch_0 = dst_pitch[0]; | |
1219 | ||
bcf8b616 | 1220 | /* |
7392f245 | 1221 | * The mono destination buffer contains 1 bit per pixel |
bcf8b616 | 1222 | */ |
b3aca563 TZ |
1223 | if (!dst_pitch_0) |
1224 | dst_pitch_0 = DIV_ROUND_UP(linepixels, 8); | |
bcf8b616 | 1225 | |
bcf8b616 | 1226 | /* |
6bcfe8ea | 1227 | * The dma memory is write-combined so reads are uncached. |
bcf8b616 JMC |
1228 | * Speed up by fetching one line at a time. |
1229 | * | |
9b13a3fc GU |
1230 | * Also, format conversion from XR24 to monochrome are done |
1231 | * line-by-line but are converted to 8-bit grayscale as an | |
1232 | * intermediate step. | |
bcf8b616 JMC |
1233 | * |
1234 | * Allocate a buffer to be used for both copying from the cma | |
1235 | * memory and to store the intermediate grayscale line pixels. | |
1236 | */ | |
4cd24d4b | 1237 | src32 = drm_format_conv_state_reserve(state, len_src32 + linepixels, GFP_KERNEL); |
bcf8b616 JMC |
1238 | if (!src32) |
1239 | return; | |
1240 | ||
1241 | gray8 = (u8 *)src32 + len_src32; | |
1242 | ||
bcf8b616 JMC |
1243 | vaddr += clip_offset(clip, fb->pitches[0], cpp); |
1244 | for (y = 0; y < lines; y++) { | |
1245 | src32 = memcpy(src32, vaddr, len_src32); | |
1246 | drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels); | |
7392f245 | 1247 | drm_fb_gray8_to_mono_line(mono, gray8, linepixels); |
bcf8b616 | 1248 | vaddr += fb->pitches[0]; |
b3aca563 | 1249 | mono += dst_pitch_0; |
bcf8b616 | 1250 | } |
bcf8b616 | 1251 | } |
9b13a3fc | 1252 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono); |
4a85b0b5 | 1253 | |
29fca6d5 TZ |
1254 | static uint32_t drm_fb_nonalpha_fourcc(uint32_t fourcc) |
1255 | { | |
1256 | /* only handle formats with depth != 0 and alpha channel */ | |
1257 | switch (fourcc) { | |
1258 | case DRM_FORMAT_ARGB1555: | |
1259 | return DRM_FORMAT_XRGB1555; | |
1260 | case DRM_FORMAT_ABGR1555: | |
1261 | return DRM_FORMAT_XBGR1555; | |
1262 | case DRM_FORMAT_RGBA5551: | |
1263 | return DRM_FORMAT_RGBX5551; | |
1264 | case DRM_FORMAT_BGRA5551: | |
1265 | return DRM_FORMAT_BGRX5551; | |
1266 | case DRM_FORMAT_ARGB8888: | |
1267 | return DRM_FORMAT_XRGB8888; | |
1268 | case DRM_FORMAT_ABGR8888: | |
1269 | return DRM_FORMAT_XBGR8888; | |
1270 | case DRM_FORMAT_RGBA8888: | |
1271 | return DRM_FORMAT_RGBX8888; | |
1272 | case DRM_FORMAT_BGRA8888: | |
1273 | return DRM_FORMAT_BGRX8888; | |
1274 | case DRM_FORMAT_ARGB2101010: | |
1275 | return DRM_FORMAT_XRGB2101010; | |
1276 | case DRM_FORMAT_ABGR2101010: | |
1277 | return DRM_FORMAT_XBGR2101010; | |
1278 | case DRM_FORMAT_RGBA1010102: | |
1279 | return DRM_FORMAT_RGBX1010102; | |
1280 | case DRM_FORMAT_BGRA1010102: | |
1281 | return DRM_FORMAT_BGRX1010102; | |
1282 | } | |
1283 | ||
1284 | return fourcc; | |
1285 | } | |
1286 | ||
4a85b0b5 TZ |
1287 | static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc) |
1288 | { | |
1289 | const uint32_t *fourccs_end = fourccs + nfourccs; | |
1290 | ||
1291 | while (fourccs < fourccs_end) { | |
1292 | if (*fourccs == fourcc) | |
1293 | return true; | |
1294 | ++fourccs; | |
1295 | } | |
1296 | return false; | |
1297 | } | |
1298 | ||
1299 | /** | |
1300 | * drm_fb_build_fourcc_list - Filters a list of supported color formats against | |
1301 | * the device's native formats | |
1302 | * @dev: DRM device | |
1303 | * @native_fourccs: 4CC codes of natively supported color formats | |
1304 | * @native_nfourccs: The number of entries in @native_fourccs | |
4a85b0b5 TZ |
1305 | * @fourccs_out: Returns 4CC codes of supported color formats |
1306 | * @nfourccs_out: The number of available entries in @fourccs_out | |
1307 | * | |
1308 | * This function create a list of supported color format from natively | |
29fca6d5 | 1309 | * supported formats and additional emulated formats. |
4a85b0b5 TZ |
1310 | * At a minimum, most userspace programs expect at least support for |
1311 | * XRGB8888 on the primary plane. Devices that have to emulate the | |
1312 | * format, and possibly others, can use drm_fb_build_fourcc_list() to | |
1313 | * create a list of supported color formats. The returned list can | |
1314 | * be handed over to drm_universal_plane_init() et al. Native formats | |
29fca6d5 TZ |
1315 | * will go before emulated formats. Native formats with alpha channel |
1316 | * will be replaced by such without, as primary planes usually don't | |
1317 | * support alpha. Other heuristics might be applied | |
4a85b0b5 | 1318 | * to optimize the order. Formats near the beginning of the list are |
29fca6d5 | 1319 | * usually preferred over formats near the end of the list. |
4a85b0b5 TZ |
1320 | * |
1321 | * Returns: | |
1322 | * The number of color-formats 4CC codes returned in @fourccs_out. | |
1323 | */ | |
1324 | size_t drm_fb_build_fourcc_list(struct drm_device *dev, | |
1325 | const u32 *native_fourccs, size_t native_nfourccs, | |
4a85b0b5 TZ |
1326 | u32 *fourccs_out, size_t nfourccs_out) |
1327 | { | |
29fca6d5 TZ |
1328 | /* |
1329 | * XRGB8888 is the default fallback format for most of userspace | |
1330 | * and it's currently the only format that should be emulated for | |
1331 | * the primary plane. Only if there's ever another default fallback, | |
1332 | * it should be added here. | |
1333 | */ | |
1334 | static const uint32_t extra_fourccs[] = { | |
1335 | DRM_FORMAT_XRGB8888, | |
1336 | }; | |
1337 | static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs); | |
1338 | ||
4a85b0b5 TZ |
1339 | u32 *fourccs = fourccs_out; |
1340 | const u32 *fourccs_end = fourccs_out + nfourccs_out; | |
4a85b0b5 TZ |
1341 | size_t i; |
1342 | ||
1343 | /* | |
1344 | * The device's native formats go first. | |
1345 | */ | |
1346 | ||
1347 | for (i = 0; i < native_nfourccs; ++i) { | |
29fca6d5 TZ |
1348 | /* |
1349 | * Several DTs, boot loaders and firmware report native | |
1350 | * alpha formats that are non-alpha formats instead. So | |
1351 | * replace alpha formats by non-alpha formats. | |
1352 | */ | |
1353 | u32 fourcc = drm_fb_nonalpha_fourcc(native_fourccs[i]); | |
4a85b0b5 TZ |
1354 | |
1355 | if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { | |
1356 | continue; /* skip duplicate entries */ | |
1357 | } else if (fourccs == fourccs_end) { | |
1358 | drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc); | |
1359 | continue; /* end of available output buffer */ | |
1360 | } | |
1361 | ||
1362 | drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc); | |
1363 | ||
4a85b0b5 TZ |
1364 | *fourccs = fourcc; |
1365 | ++fourccs; | |
1366 | } | |
1367 | ||
4a85b0b5 TZ |
1368 | /* |
1369 | * The extra formats, emulated by the driver, go second. | |
1370 | */ | |
1371 | ||
29fca6d5 TZ |
1372 | for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) { |
1373 | u32 fourcc = extra_fourccs[i]; | |
4a85b0b5 TZ |
1374 | |
1375 | if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { | |
1376 | continue; /* skip duplicate and native entries */ | |
1377 | } else if (fourccs == fourccs_end) { | |
1378 | drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc); | |
1379 | continue; /* end of available output buffer */ | |
1380 | } | |
1381 | ||
1382 | drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc); | |
1383 | ||
1384 | *fourccs = fourcc; | |
1385 | ++fourccs; | |
1386 | } | |
1387 | ||
4a85b0b5 TZ |
1388 | return fourccs - fourccs_out; |
1389 | } | |
1390 | EXPORT_SYMBOL(drm_fb_build_fourcc_list); |