Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 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 * 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 */
 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 * 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 */
 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 * 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
116static void drm_fb_xrgb8888_to_rgb565_line(u16 *dbuf, u32 *sbuf,
117					   unsigned int pixels,
118					   bool swab)
119{
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;
131	}
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
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 */
148void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
149			       struct drm_framebuffer *fb,
150			       struct drm_rect *clip, bool swab)
151{
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);
175}
176EXPORT_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 */
193void 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	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);
216}
217EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
218
219static void drm_fb_xrgb8888_to_rgb888_line(u8 *dbuf, u32 *sbuf,
220					   unsigned int pixels)
221{
222	unsigned int x;
223
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;
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 */
245void 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	size_t linepixels = clip->x2 - clip->x1;
250	size_t dst_len = linepixels * 3;
251	unsigned y, lines = clip->y2 - clip->y1;
252	void *dbuf;
253
254	dbuf = kmalloc(dst_len, GFP_KERNEL);
255	if (!dbuf)
256		return;
257
258	vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
259	dst += clip_offset(clip, dst_pitch, sizeof(u16));
260	for (y = 0; y < lines; y++) {
261		drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels);
262		memcpy_toio(dst, dbuf, dst_len);
263		vaddr += fb->pitches[0];
264		dst += dst_len;
265	}
266
267	kfree(dbuf);
268}
269EXPORT_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 */
287void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
288			       struct drm_rect *clip)
289{
290	unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
291	unsigned int x, y;
292	void *buf;
293	u32 *src;
294
295	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	buf = kmalloc(len, GFP_KERNEL);
302	if (!buf)
303		return;
304
305	for (y = clip->y1; y < clip->y2; y++) {
306		src = vaddr + (y * fb->pitches[0]);
307		src += clip->x1;
308		memcpy(buf, src, len);
309		src = buf;
310		for (x = clip->x1; x < clip->x2; x++) {
311			u8 r = (*src & 0x00ff0000) >> 16;
312			u8 g = (*src & 0x0000ff00) >> 8;
313			u8 b =  *src & 0x000000ff;
314
315			/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
316			*dst++ = (3 * r + 6 * g + b) / 10;
317			src++;
318		}
319	}
320
321	kfree(buf);
322}
323EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
324