2020-02-15 19:09:11 +01:00
// SPDX-License-Identifier: GPL-2.0 or MIT
2019-04-05 11:52:15 +02:00
/*
* Copyright ( C ) 2016 Noralf Trønnes
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <linux/module.h>
# include <linux/slab.h>
2019-04-10 08:38:13 +02:00
# include <linux/io.h>
2019-04-05 11:52:15 +02:00
# include <drm/drm_format_helper.h>
# include <drm/drm_framebuffer.h>
# include <drm/drm_fourcc.h>
# include <drm/drm_rect.h>
2019-04-10 08:38:13 +02:00
static unsigned int clip_offset ( struct drm_rect * clip ,
unsigned int pitch , unsigned int cpp )
2019-04-05 11:52:16 +02:00
{
2019-04-10 08:38:13 +02:00
return clip - > y1 * pitch + clip - > x1 * cpp ;
2019-04-05 11:52:16 +02:00
}
2019-04-05 11:52:15 +02:00
/**
* drm_fb_memcpy - Copy clip buffer
* @ dst : Destination buffer
* @ vaddr : Source buffer
* @ fb : DRM framebuffer
* @ clip : Clip rectangle area to copy
2019-04-05 11:52:16 +02:00
*
* This function does not apply clipping on dst , i . e . the destination
* is a small buffer containing the clip rect only .
2019-04-05 11:52:15 +02:00
*/
void drm_fb_memcpy ( void * dst , void * vaddr , struct drm_framebuffer * fb ,
struct drm_rect * clip )
{
2019-05-16 12:31:52 +02:00
unsigned int cpp = fb - > format - > cpp [ 0 ] ;
2019-04-05 11:52:15 +02:00
size_t len = ( clip - > x2 - clip - > x1 ) * cpp ;
2019-04-10 08:38:13 +02:00
unsigned int y , lines = clip - > y2 - clip - > y1 ;
2019-04-05 11:52:15 +02:00
2019-04-10 08:38:13 +02:00
vaddr + = clip_offset ( clip , fb - > pitches [ 0 ] , cpp ) ;
for ( y = 0 ; y < lines ; y + + ) {
memcpy ( dst , vaddr , len ) ;
vaddr + = fb - > pitches [ 0 ] ;
dst + = len ;
}
2019-04-05 11:52:15 +02:00
}
EXPORT_SYMBOL ( drm_fb_memcpy ) ;
2019-04-05 11:52:16 +02:00
/**
* drm_fb_memcpy_dstclip - Copy clip buffer
2019-04-10 08:38:13 +02:00
* @ dst : Destination buffer ( iomem )
2019-04-05 11:52:16 +02:00
* @ vaddr : Source buffer
* @ fb : DRM framebuffer
* @ clip : Clip rectangle area to copy
*
* This function applies clipping on dst , i . e . the destination is a
2019-04-10 08:38:13 +02:00
* full ( iomem ) framebuffer but only the clip rect content is copied over .
2019-04-05 11:52:16 +02:00
*/
2019-04-10 08:38:13 +02:00
void drm_fb_memcpy_dstclip ( void __iomem * dst , void * vaddr ,
struct drm_framebuffer * fb ,
2019-04-05 11:52:16 +02:00
struct drm_rect * clip )
{
2019-05-16 12:31:52 +02:00
unsigned int cpp = fb - > format - > cpp [ 0 ] ;
2019-04-10 08:38:13 +02:00
unsigned int offset = clip_offset ( clip , fb - > pitches [ 0 ] , cpp ) ;
2019-04-05 11:52:16 +02:00
size_t len = ( clip - > x2 - clip - > x1 ) * cpp ;
2019-04-10 08:38:13 +02:00
unsigned int y , lines = clip - > y2 - clip - > y1 ;
2019-04-05 11:52:16 +02:00
2019-04-10 08:38:13 +02:00
vaddr + = offset ;
dst + = offset ;
for ( y = 0 ; y < lines ; y + + ) {
memcpy_toio ( dst , vaddr , len ) ;
vaddr + = fb - > pitches [ 0 ] ;
dst + = fb - > pitches [ 0 ] ;
}
2019-04-05 11:52:16 +02:00
}
EXPORT_SYMBOL ( drm_fb_memcpy_dstclip ) ;
2019-04-05 11:52:15 +02:00
/**
* drm_fb_swab16 - Swap bytes into clip buffer
* @ dst : RGB565 destination buffer
* @ vaddr : RGB565 source buffer
* @ fb : DRM framebuffer
* @ clip : Clip rectangle area to copy
*/
void drm_fb_swab16 ( u16 * dst , void * vaddr , struct drm_framebuffer * fb ,
struct drm_rect * clip )
{
size_t len = ( clip - > x2 - clip - > x1 ) * sizeof ( u16 ) ;
unsigned int x , y ;
u16 * src , * buf ;
/*
* The cma memory is write - combined so reads are uncached .
* Speed up by fetching one line at a time .
*/
buf = kmalloc ( len , GFP_KERNEL ) ;
if ( ! buf )
return ;
for ( y = clip - > y1 ; y < clip - > y2 ; y + + ) {
src = vaddr + ( y * fb - > pitches [ 0 ] ) ;
src + = clip - > x1 ;
memcpy ( buf , src , len ) ;
src = buf ;
for ( x = clip - > x1 ; x < clip - > x2 ; x + + )
* dst + + = swab16 ( * src + + ) ;
}
kfree ( buf ) ;
}
EXPORT_SYMBOL ( drm_fb_swab16 ) ;
2019-04-10 08:38:14 +02:00
static void drm_fb_xrgb8888_to_rgb565_line ( u16 * dbuf , u32 * sbuf ,
unsigned int pixels ,
bool swab )
2019-04-05 11:52:15 +02:00
{
2019-04-10 08:38:14 +02:00
unsigned int x ;
u16 val16 ;
for ( x = 0 ; x < pixels ; x + + ) {
val16 = ( ( sbuf [ x ] & 0x00F80000 ) > > 8 ) |
( ( sbuf [ x ] & 0x0000FC00 ) > > 5 ) |
( ( sbuf [ x ] & 0x000000F8 ) > > 3 ) ;
if ( swab )
dbuf [ x ] = swab16 ( val16 ) ;
else
dbuf [ x ] = val16 ;
2019-04-05 11:52:15 +02:00
}
2019-04-05 11:52:17 +02:00
}
/**
* drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
* @ dst : RGB565 destination buffer
* @ vaddr : XRGB8888 source buffer
* @ fb : DRM framebuffer
* @ clip : Clip rectangle area to copy
2019-04-10 08:38:14 +02:00
* @ swab : Swap bytes
2019-04-05 11:52:17 +02:00
*
* Drivers can use this function for RGB565 devices that don ' t natively
* support XRGB8888 .
*
* This function does not apply clipping on dst , i . e . the destination
* is a small buffer containing the clip rect only .
*/
void drm_fb_xrgb8888_to_rgb565 ( void * dst , void * vaddr ,
struct drm_framebuffer * fb ,
2019-04-10 08:38:14 +02:00
struct drm_rect * clip , bool swab )
2019-04-05 11:52:17 +02:00
{
2019-04-10 08:38:14 +02:00
size_t linepixels = clip - > x2 - clip - > x1 ;
size_t src_len = linepixels * sizeof ( u32 ) ;
size_t dst_len = linepixels * sizeof ( u16 ) ;
unsigned y , lines = clip - > y2 - clip - > y1 ;
void * sbuf ;
/*
* The cma memory is write - combined so reads are uncached .
* Speed up by fetching one line at a time .
*/
sbuf = kmalloc ( src_len , GFP_KERNEL ) ;
if ( ! sbuf )
return ;
vaddr + = clip_offset ( clip , fb - > pitches [ 0 ] , sizeof ( u32 ) ) ;
for ( y = 0 ; y < lines ; y + + ) {
memcpy ( sbuf , vaddr , src_len ) ;
drm_fb_xrgb8888_to_rgb565_line ( dst , sbuf , linepixels , swab ) ;
vaddr + = fb - > pitches [ 0 ] ;
dst + = dst_len ;
}
kfree ( sbuf ) ;
2019-04-05 11:52:15 +02:00
}
EXPORT_SYMBOL ( drm_fb_xrgb8888_to_rgb565 ) ;
2019-04-05 11:52:17 +02:00
/**
* drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer
2019-04-10 08:38:14 +02:00
* @ dst : RGB565 destination buffer ( iomem )
2019-04-05 11:52:17 +02:00
* @ dst_pitch : destination buffer pitch
* @ vaddr : XRGB8888 source buffer
* @ fb : DRM framebuffer
* @ clip : Clip rectangle area to copy
2019-04-10 08:38:14 +02:00
* @ swab : Swap bytes
2019-04-05 11:52:17 +02:00
*
* Drivers can use this function for RGB565 devices that don ' t natively
* support XRGB8888 .
*
* This function applies clipping on dst , i . e . the destination is a
2019-04-10 08:38:14 +02:00
* full ( iomem ) framebuffer but only the clip rect content is copied over .
2019-04-05 11:52:17 +02:00
*/
2019-04-10 08:38:14 +02:00
void drm_fb_xrgb8888_to_rgb565_dstclip ( void __iomem * dst , unsigned int dst_pitch ,
2019-04-05 11:52:17 +02:00
void * vaddr , struct drm_framebuffer * fb ,
2019-04-10 08:38:14 +02:00
struct drm_rect * clip , bool swab )
2019-04-05 11:52:17 +02:00
{
2019-04-10 08:38:14 +02:00
size_t linepixels = clip - > x2 - clip - > x1 ;
size_t dst_len = linepixels * sizeof ( u16 ) ;
unsigned y , lines = clip - > y2 - clip - > y1 ;
void * dbuf ;
dbuf = kmalloc ( dst_len , GFP_KERNEL ) ;
if ( ! dbuf )
return ;
vaddr + = clip_offset ( clip , fb - > pitches [ 0 ] , sizeof ( u32 ) ) ;
dst + = clip_offset ( clip , dst_pitch , sizeof ( u16 ) ) ;
for ( y = 0 ; y < lines ; y + + ) {
drm_fb_xrgb8888_to_rgb565_line ( dbuf , vaddr , linepixels , swab ) ;
memcpy_toio ( dst , dbuf , dst_len ) ;
vaddr + = fb - > pitches [ 0 ] ;
dst + = dst_len ;
}
kfree ( dbuf ) ;
2019-04-05 11:52:17 +02:00
}
EXPORT_SYMBOL ( drm_fb_xrgb8888_to_rgb565_dstclip ) ;
2019-04-10 08:38:15 +02:00
static void drm_fb_xrgb8888_to_rgb888_line ( u8 * dbuf , u32 * sbuf ,
unsigned int pixels )
2019-04-05 11:52:18 +02:00
{
2019-04-10 08:38:15 +02:00
unsigned int x ;
2019-04-05 11:52:18 +02:00
2019-04-10 08:38:15 +02:00
for ( x = 0 ; x < pixels ; x + + ) {
* dbuf + + = ( sbuf [ x ] & 0x000000FF ) > > 0 ;
* dbuf + + = ( sbuf [ x ] & 0x0000FF00 ) > > 8 ;
* dbuf + + = ( sbuf [ x ] & 0x00FF0000 ) > > 16 ;
2019-04-05 11:52:18 +02:00
}
}
/**
* drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer
2019-04-11 06:49:32 +02:00
* @ dst : RGB565 destination buffer ( iomem )
2019-04-05 11:52:18 +02:00
* @ dst_pitch : destination buffer pitch
* @ vaddr : XRGB8888 source buffer
* @ fb : DRM framebuffer
* @ clip : Clip rectangle area to copy
*
* Drivers can use this function for RGB888 devices that don ' t natively
* support XRGB8888 .
*
* This function applies clipping on dst , i . e . the destination is a
2019-04-11 06:49:32 +02:00
* full ( iomem ) framebuffer but only the clip rect content is copied over .
2019-04-05 11:52:18 +02:00
*/
2019-04-11 06:49:32 +02:00
void drm_fb_xrgb8888_to_rgb888_dstclip ( void __iomem * dst , unsigned int dst_pitch ,
2019-04-05 11:52:18 +02:00
void * vaddr , struct drm_framebuffer * fb ,
struct drm_rect * clip )
{
2019-04-10 08:38:15 +02:00
size_t linepixels = clip - > x2 - clip - > x1 ;
size_t dst_len = linepixels * 3 ;
unsigned y , lines = clip - > y2 - clip - > y1 ;
void * dbuf ;
2019-04-05 11:52:18 +02:00
2019-04-10 08:38:15 +02:00
dbuf = kmalloc ( dst_len , GFP_KERNEL ) ;
if ( ! dbuf )
return ;
vaddr + = clip_offset ( clip , fb - > pitches [ 0 ] , sizeof ( u32 ) ) ;
dst + = clip_offset ( clip , dst_pitch , sizeof ( u16 ) ) ;
for ( y = 0 ; y < lines ; y + + ) {
drm_fb_xrgb8888_to_rgb888_line ( dbuf , vaddr , linepixels ) ;
memcpy_toio ( dst , dbuf , dst_len ) ;
vaddr + = fb - > pitches [ 0 ] ;
dst + = dst_len ;
}
kfree ( dbuf ) ;
2019-04-05 11:52:18 +02:00
}
EXPORT_SYMBOL ( drm_fb_xrgb8888_to_rgb888_dstclip ) ;
2019-04-05 11:52:15 +02:00
/**
* drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
* @ dst : 8 - bit grayscale destination buffer
* @ vaddr : XRGB8888 source buffer
* @ fb : DRM framebuffer
* @ clip : Clip rectangle area to copy
*
* Drm doesn ' t have native monochrome or grayscale support .
* Such drivers can announce the commonly supported XR24 format to userspace
* and use this function to convert to the native format .
*
* Monochrome drivers will use the most significant bit ,
* where 1 means foreground color and 0 background color .
*
* ITU BT .601 is used for the RGB - > luma ( brightness ) conversion .
*/
void drm_fb_xrgb8888_to_gray8 ( u8 * dst , void * vaddr , struct drm_framebuffer * fb ,
struct drm_rect * clip )
{
unsigned int len = ( clip - > x2 - clip - > x1 ) * sizeof ( u32 ) ;
unsigned int x , y ;
void * buf ;
u32 * src ;
if ( WARN_ON ( fb - > format - > format ! = DRM_FORMAT_XRGB8888 ) )
return ;
/*
* The cma memory is write - combined so reads are uncached .
* Speed up by fetching one line at a time .
*/
buf = kmalloc ( len , GFP_KERNEL ) ;
if ( ! buf )
return ;
for ( y = clip - > y1 ; y < clip - > y2 ; y + + ) {
src = vaddr + ( y * fb - > pitches [ 0 ] ) ;
src + = clip - > x1 ;
memcpy ( buf , src , len ) ;
src = buf ;
for ( x = clip - > x1 ; x < clip - > x2 ; x + + ) {
u8 r = ( * src & 0x00ff0000 ) > > 16 ;
u8 g = ( * src & 0x0000ff00 ) > > 8 ;
u8 b = * src & 0x000000ff ;
/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
* dst + + = ( 3 * r + 6 * g + b ) / 10 ;
src + + ;
}
}
kfree ( buf ) ;
}
EXPORT_SYMBOL ( drm_fb_xrgb8888_to_gray8 ) ;