drm/tinydrm: Fix fbdev pixel format
[linux-2.6-block.git] / drivers / gpu / drm / drm_format_helper.c
CommitLineData
7415287e
GH
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>
bf4f6d16 13#include <linux/io.h>
7415287e
GH
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
bf4f6d16
GH
20static unsigned int clip_offset(struct drm_rect *clip,
21 unsigned int pitch, unsigned int cpp)
26f024f5 22{
bf4f6d16 23 return clip->y1 * pitch + clip->x1 * cpp;
26f024f5
GH
24}
25
7415287e
GH
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
26f024f5
GH
32 *
33 * This function does not apply clipping on dst, i.e. the destination
34 * is a small buffer containing the clip rect only.
7415287e
GH
35 */
36void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
37 struct drm_rect *clip)
38{
39 unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
7415287e 40 size_t len = (clip->x2 - clip->x1) * cpp;
bf4f6d16 41 unsigned int y, lines = clip->y2 - clip->y1;
7415287e 42
bf4f6d16
GH
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 }
7415287e
GH
49}
50EXPORT_SYMBOL(drm_fb_memcpy);
51
26f024f5
GH
52/**
53 * drm_fb_memcpy_dstclip - Copy clip buffer
bf4f6d16 54 * @dst: Destination buffer (iomem)
26f024f5
GH
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
bf4f6d16 60 * full (iomem) framebuffer but only the clip rect content is copied over.
26f024f5 61 */
bf4f6d16
GH
62void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
63 struct drm_framebuffer *fb,
26f024f5
GH
64 struct drm_rect *clip)
65{
66 unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
bf4f6d16 67 unsigned int offset = clip_offset(clip, fb->pitches[0], cpp);
26f024f5 68 size_t len = (clip->x2 - clip->x1) * cpp;
bf4f6d16 69 unsigned int y, lines = clip->y2 - clip->y1;
26f024f5 70
bf4f6d16
GH
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 }
26f024f5
GH
78}
79EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
80
7415287e
GH
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 */
88void drm_fb_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
89 struct drm_rect *clip)
90{
91 size_t len = (clip->x2 - clip->x1) * sizeof(u16);
92 unsigned int x, y;
93 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 buf = kmalloc(len, GFP_KERNEL);
100 if (!buf)
101 return;
102
103 for (y = clip->y1; y < clip->y2; y++) {
104 src = vaddr + (y * fb->pitches[0]);
105 src += clip->x1;
106 memcpy(buf, src, len);
107 src = buf;
108 for (x = clip->x1; x < clip->x2; x++)
109 *dst++ = swab16(*src++);
110 }
111
112 kfree(buf);
113}
114EXPORT_SYMBOL(drm_fb_swab16);
115
d653bd39
GH
116static void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf,
117 unsigned int pixels,
118 bool swab)
7415287e 119{
d653bd39
GH
120 unsigned int x;
121 u16 val16;
122
123 for (x = 0; x < pixels; x++) {
124 val16 = ((sbuf[x] & 0x00F80000) >> 8) |
125 ((sbuf[x] & 0x0000FC00) >> 5) |
126 ((sbuf[x] & 0x000000F8) >> 3);
127 if (swab)
128 dbuf[x] = swab16(val16);
129 else
130 dbuf[x] = val16;
7415287e 131 }
bcc44420
GH
132}
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
d653bd39 140 * @swab: Swap bytes
bcc44420
GH
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 */
148void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
149 struct drm_framebuffer *fb,
d653bd39 150 struct drm_rect *clip, bool swab)
bcc44420 151{
d653bd39
GH
152 size_t linepixels = clip->x2 - clip->x1;
153 size_t src_len = linepixels * sizeof(u32);
154 size_t dst_len = linepixels * sizeof(u16);
155 unsigned y, lines = clip->y2 - clip->y1;
156 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 sbuf = kmalloc(src_len, GFP_KERNEL);
163 if (!sbuf)
164 return;
165
166 vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
167 for (y = 0; y < lines; y++) {
168 memcpy(sbuf, vaddr, src_len);
169 drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels, swab);
170 vaddr += fb->pitches[0];
171 dst += dst_len;
172 }
173
174 kfree(sbuf);
7415287e
GH
175}
176EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
177
bcc44420
GH
178/**
179 * drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer
d653bd39 180 * @dst: RGB565 destination buffer (iomem)
bcc44420
GH
181 * @dst_pitch: destination buffer pitch
182 * @vaddr: XRGB8888 source buffer
183 * @fb: DRM framebuffer
184 * @clip: Clip rectangle area to copy
d653bd39 185 * @swab: Swap bytes
bcc44420
GH
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
d653bd39 191 * full (iomem) framebuffer but only the clip rect content is copied over.
bcc44420 192 */
d653bd39 193void drm_fb_xrgb8888_to_rgb565_dstclip(void __iomem *dst, unsigned int dst_pitch,
bcc44420 194 void *vaddr, struct drm_framebuffer *fb,
d653bd39 195 struct drm_rect *clip, bool swab)
bcc44420 196{
d653bd39
GH
197 size_t linepixels = clip->x2 - clip->x1;
198 size_t dst_len = linepixels * sizeof(u16);
199 unsigned y, lines = clip->y2 - clip->y1;
200 void *dbuf;
201
202 dbuf = kmalloc(dst_len, GFP_KERNEL);
203 if (!dbuf)
204 return;
205
206 vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
207 dst += clip_offset(clip, dst_pitch, sizeof(u16));
208 for (y = 0; y < lines; y++) {
209 drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels, swab);
210 memcpy_toio(dst, dbuf, dst_len);
211 vaddr += fb->pitches[0];
212 dst += dst_len;
213 }
214
215 kfree(dbuf);
bcc44420
GH
216}
217EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
218
5c5373b5
GH
219static void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf,
220 unsigned int pixels)
ec3de7a4 221{
5c5373b5 222 unsigned int x;
ec3de7a4 223
5c5373b5
GH
224 for (x = 0; x < pixels; x++) {
225 *dbuf++ = (sbuf[x] & 0x000000FF) >> 0;
226 *dbuf++ = (sbuf[x] & 0x0000FF00) >> 8;
227 *dbuf++ = (sbuf[x] & 0x00FF0000) >> 16;
ec3de7a4 228 }
ec3de7a4
GH
229}
230
231/**
232 * drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer
233 * @dst: RGB565 destination buffer
234 * @dst_pitch: destination buffer pitch
235 * @vaddr: XRGB8888 source buffer
236 * @fb: DRM framebuffer
237 * @clip: Clip rectangle area to copy
238 * @dstclip: Clip destination too.
239 *
240 * Drivers can use this function for RGB888 devices that don't natively
241 * support XRGB8888.
242 *
243 * This function applies clipping on dst, i.e. the destination is a
244 * full framebuffer but only the clip rect content is copied over.
245 */
246void drm_fb_xrgb8888_to_rgb888_dstclip(void *dst, unsigned int dst_pitch,
247 void *vaddr, struct drm_framebuffer *fb,
248 struct drm_rect *clip)
249{
5c5373b5
GH
250 size_t linepixels = clip->x2 - clip->x1;
251 size_t dst_len = linepixels * 3;
252 unsigned y, lines = clip->y2 - clip->y1;
253 void *dbuf;
ec3de7a4 254
5c5373b5
GH
255 dbuf = kmalloc(dst_len, GFP_KERNEL);
256 if (!dbuf)
257 return;
258
259 vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
260 dst += clip_offset(clip, dst_pitch, sizeof(u16));
261 for (y = 0; y < lines; y++) {
262 drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels);
263 memcpy_toio(dst, dbuf, dst_len);
264 vaddr += fb->pitches[0];
265 dst += dst_len;
266 }
267
268 kfree(dbuf);
ec3de7a4
GH
269}
270EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip);
271
7415287e
GH
272/**
273 * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
274 * @dst: 8-bit grayscale destination buffer
275 * @vaddr: XRGB8888 source buffer
276 * @fb: DRM framebuffer
277 * @clip: Clip rectangle area to copy
278 *
279 * Drm doesn't have native monochrome or grayscale support.
280 * Such drivers can announce the commonly supported XR24 format to userspace
281 * and use this function to convert to the native format.
282 *
283 * Monochrome drivers will use the most significant bit,
284 * where 1 means foreground color and 0 background color.
285 *
286 * ITU BT.601 is used for the RGB -> luma (brightness) conversion.
287 */
288void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
289 struct drm_rect *clip)
290{
291 unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
292 unsigned int x, y;
293 void *buf;
294 u32 *src;
295
296 if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
297 return;
298 /*
299 * The cma memory is write-combined so reads are uncached.
300 * Speed up by fetching one line at a time.
301 */
302 buf = kmalloc(len, GFP_KERNEL);
303 if (!buf)
304 return;
305
306 for (y = clip->y1; y < clip->y2; y++) {
307 src = vaddr + (y * fb->pitches[0]);
308 src += clip->x1;
309 memcpy(buf, src, len);
310 src = buf;
311 for (x = clip->x1; x < clip->x2; x++) {
312 u8 r = (*src & 0x00ff0000) >> 16;
313 u8 g = (*src & 0x0000ff00) >> 8;
314 u8 b = *src & 0x000000ff;
315
316 /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
317 *dst++ = (3 * r + 6 * g + b) / 10;
318 src++;
319 }
320 }
321
322 kfree(buf);
323}
324EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
325