2016-06-09 12:54:08 +03:00
/*
* Copyright ( c ) 2016 Laurent Pinchart < laurent . pinchart @ ideasonboard . com >
*
* DRM core format related functions
*
* Permission to use , copy , modify , distribute , and sell this software and its
* documentation for any purpose is hereby granted without fee , provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation , and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific ,
* written prior permission . The copyright holders make no representations
* about the suitability of this software for any purpose . It is provided " as
* is " without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS , IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL , INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE ,
* DATA OR PROFITS , WHETHER IN AN ACTION OF CONTRACT , NEGLIGENCE OR OTHER
* TORTIOUS ACTION , ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE .
*/
# include <linux/bug.h>
# include <linux/ctype.h>
# include <linux/export.h>
# include <linux/kernel.h>
# include <drm/drmP.h>
# include <drm/drm_fourcc.h>
static char printable_char ( int c )
{
return isascii ( c ) & & isprint ( c ) ? c : ' ? ' ;
}
2016-08-29 10:27:54 +02:00
/**
* drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
* @ bpp : bits per pixels
* @ depth : bit depth per pixel
*
* Computes a drm fourcc pixel format code for the given @ bpp / @ depth values .
* Useful in fbdev emulation code , since that deals in those values .
*/
uint32_t drm_mode_legacy_fb_format ( uint32_t bpp , uint32_t depth )
{
uint32_t fmt ;
switch ( bpp ) {
case 8 :
fmt = DRM_FORMAT_C8 ;
break ;
case 16 :
if ( depth = = 15 )
fmt = DRM_FORMAT_XRGB1555 ;
else
fmt = DRM_FORMAT_RGB565 ;
break ;
case 24 :
fmt = DRM_FORMAT_RGB888 ;
break ;
case 32 :
if ( depth = = 24 )
fmt = DRM_FORMAT_XRGB8888 ;
else if ( depth = = 30 )
fmt = DRM_FORMAT_XRGB2101010 ;
else
fmt = DRM_FORMAT_ARGB8888 ;
break ;
default :
DRM_ERROR ( " bad bpp, assuming x8r8g8b8 pixel format \n " ) ;
fmt = DRM_FORMAT_XRGB8888 ;
break ;
}
return fmt ;
}
EXPORT_SYMBOL ( drm_mode_legacy_fb_format ) ;
2016-06-09 12:54:08 +03:00
/**
2016-11-12 01:12:56 +00:00
* drm_get_format_name - fill a string with a drm fourcc format ' s name
2016-06-09 12:54:08 +03:00
* @ format : format to compute name of
2016-11-12 01:12:56 +00:00
* @ buf : caller - supplied buffer
2016-06-09 12:54:08 +03:00
*/
2016-11-12 01:12:56 +00:00
const char * drm_get_format_name ( uint32_t format , struct drm_format_name_buf * buf )
2016-06-09 12:54:08 +03:00
{
2016-11-12 01:12:56 +00:00
snprintf ( buf - > str , sizeof ( buf - > str ) ,
2016-06-09 12:54:08 +03:00
" %c%c%c%c %s-endian (0x%08x) " ,
printable_char ( format & 0xff ) ,
printable_char ( ( format > > 8 ) & 0xff ) ,
printable_char ( ( format > > 16 ) & 0xff ) ,
printable_char ( ( format > > 24 ) & 0x7f ) ,
format & DRM_FORMAT_BIG_ENDIAN ? " big " : " little " ,
format ) ;
2016-11-12 01:12:56 +00:00
return buf - > str ;
2016-06-09 12:54:08 +03:00
}
EXPORT_SYMBOL ( drm_get_format_name ) ;
2016-10-18 01:41:12 +03:00
/*
* Internal function to query information for a given format . See
* drm_format_info ( ) for the public API .
2016-10-18 01:41:09 +03:00
*/
2016-10-18 01:41:12 +03:00
const struct drm_format_info * __drm_format_info ( u32 format )
2016-10-18 01:41:09 +03:00
{
static const struct drm_format_info formats [ ] = {
{ . format = DRM_FORMAT_C8 , . depth = 8 , . num_planes = 1 , . cpp = { 1 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGB332 , . depth = 8 , . num_planes = 1 , . cpp = { 1 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGR233 , . depth = 8 , . num_planes = 1 , . cpp = { 1 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_XRGB4444 , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_XBGR4444 , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGBX4444 , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGRX4444 , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_ARGB4444 , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_ABGR4444 , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGBA4444 , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGRA4444 , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_XRGB1555 , . depth = 15 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_XBGR1555 , . depth = 15 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGBX5551 , . depth = 15 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGRX5551 , . depth = 15 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_ARGB1555 , . depth = 15 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_ABGR1555 , . depth = 15 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGBA5551 , . depth = 15 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGRA5551 , . depth = 15 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGB565 , . depth = 16 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGR565 , . depth = 16 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGB888 , . depth = 24 , . num_planes = 1 , . cpp = { 3 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGR888 , . depth = 24 , . num_planes = 1 , . cpp = { 3 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_XRGB8888 , . depth = 24 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_XBGR8888 , . depth = 24 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGBX8888 , . depth = 24 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGRX8888 , . depth = 24 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
2015-01-09 11:05:13 +01:00
{ . format = DRM_FORMAT_RGB565_A8 , . depth = 24 , . num_planes = 2 , . cpp = { 2 , 1 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGR565_A8 , . depth = 24 , . num_planes = 2 , . cpp = { 2 , 1 , 0 } , . hsub = 1 , . vsub = 1 } ,
2016-10-18 01:41:09 +03:00
{ . format = DRM_FORMAT_XRGB2101010 , . depth = 30 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_XBGR2101010 , . depth = 30 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGBX1010102 , . depth = 30 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGRX1010102 , . depth = 30 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_ARGB2101010 , . depth = 30 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_ABGR2101010 , . depth = 30 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGBA1010102 , . depth = 30 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGRA1010102 , . depth = 30 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_ARGB8888 , . depth = 32 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_ABGR8888 , . depth = 32 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGBA8888 , . depth = 32 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGRA8888 , . depth = 32 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
2015-01-09 11:05:13 +01:00
{ . format = DRM_FORMAT_RGB888_A8 , . depth = 32 , . num_planes = 2 , . cpp = { 3 , 1 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGR888_A8 , . depth = 32 , . num_planes = 2 , . cpp = { 3 , 1 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_XRGB8888_A8 , . depth = 32 , . num_planes = 2 , . cpp = { 4 , 1 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_XBGR8888_A8 , . depth = 32 , . num_planes = 2 , . cpp = { 4 , 1 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_RGBX8888_A8 , . depth = 32 , . num_planes = 2 , . cpp = { 4 , 1 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_BGRX8888_A8 , . depth = 32 , . num_planes = 2 , . cpp = { 4 , 1 , 0 } , . hsub = 1 , . vsub = 1 } ,
2016-10-18 01:41:09 +03:00
{ . format = DRM_FORMAT_YUV410 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 4 , . vsub = 4 } ,
{ . format = DRM_FORMAT_YVU410 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 4 , . vsub = 4 } ,
{ . format = DRM_FORMAT_YUV411 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 4 , . vsub = 1 } ,
{ . format = DRM_FORMAT_YVU411 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 4 , . vsub = 1 } ,
{ . format = DRM_FORMAT_YUV420 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 2 , . vsub = 2 } ,
{ . format = DRM_FORMAT_YVU420 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 2 , . vsub = 2 } ,
{ . format = DRM_FORMAT_YUV422 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 2 , . vsub = 1 } ,
{ . format = DRM_FORMAT_YVU422 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 2 , . vsub = 1 } ,
{ . format = DRM_FORMAT_YUV444 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_YVU444 , . depth = 0 , . num_planes = 3 , . cpp = { 1 , 1 , 1 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_NV12 , . depth = 0 , . num_planes = 2 , . cpp = { 1 , 2 , 0 } , . hsub = 2 , . vsub = 2 } ,
{ . format = DRM_FORMAT_NV21 , . depth = 0 , . num_planes = 2 , . cpp = { 1 , 2 , 0 } , . hsub = 2 , . vsub = 2 } ,
{ . format = DRM_FORMAT_NV16 , . depth = 0 , . num_planes = 2 , . cpp = { 1 , 2 , 0 } , . hsub = 2 , . vsub = 1 } ,
{ . format = DRM_FORMAT_NV61 , . depth = 0 , . num_planes = 2 , . cpp = { 1 , 2 , 0 } , . hsub = 2 , . vsub = 1 } ,
{ . format = DRM_FORMAT_NV24 , . depth = 0 , . num_planes = 2 , . cpp = { 1 , 2 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_NV42 , . depth = 0 , . num_planes = 2 , . cpp = { 1 , 2 , 0 } , . hsub = 1 , . vsub = 1 } ,
{ . format = DRM_FORMAT_YUYV , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 2 , . vsub = 1 } ,
{ . format = DRM_FORMAT_YVYU , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 2 , . vsub = 1 } ,
{ . format = DRM_FORMAT_UYVY , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 2 , . vsub = 1 } ,
{ . format = DRM_FORMAT_VYUY , . depth = 0 , . num_planes = 1 , . cpp = { 2 , 0 , 0 } , . hsub = 2 , . vsub = 1 } ,
{ . format = DRM_FORMAT_AYUV , . depth = 0 , . num_planes = 1 , . cpp = { 4 , 0 , 0 } , . hsub = 1 , . vsub = 1 } ,
} ;
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( formats ) ; + + i ) {
if ( formats [ i ] . format = = format )
return & formats [ i ] ;
}
return NULL ;
}
2016-10-18 01:41:12 +03:00
/**
* drm_format_info - query information for a given format
* @ format : pixel format ( DRM_FORMAT_ * )
*
* The caller should only pass a supported pixel format to this function .
* Unsupported pixel formats will generate a warning in the kernel log .
*
* Returns :
* The instance of struct drm_format_info that describes the pixel format , or
* NULL if the format is unsupported .
*/
const struct drm_format_info * drm_format_info ( u32 format )
{
const struct drm_format_info * info ;
info = __drm_format_info ( format ) ;
WARN_ON ( ! info ) ;
return info ;
}
2016-10-18 01:41:09 +03:00
EXPORT_SYMBOL ( drm_format_info ) ;
2017-03-21 20:12:16 +02:00
/**
* drm_get_format_info - query information for a given framebuffer configuration
* @ dev : DRM device
* @ mode_cmd : metadata from the userspace fb creation request
*
* Returns :
* The instance of struct drm_format_info that describes the pixel format , or
* NULL if the format is unsupported .
*/
const struct drm_format_info *
drm_get_format_info ( struct drm_device * dev ,
const struct drm_mode_fb_cmd2 * mode_cmd )
{
const struct drm_format_info * info = NULL ;
if ( dev - > mode_config . funcs - > get_format_info )
info = dev - > mode_config . funcs - > get_format_info ( mode_cmd ) ;
if ( ! info )
info = drm_format_info ( mode_cmd - > pixel_format ) ;
return info ;
}
EXPORT_SYMBOL ( drm_get_format_info ) ;
2016-06-09 12:54:08 +03:00
/**
* drm_format_num_planes - get the number of planes for format
* @ format : pixel format ( DRM_FORMAT_ * )
*
* Returns :
* The number of planes used by the specified pixel format .
*/
int drm_format_num_planes ( uint32_t format )
{
2016-10-18 01:41:10 +03:00
const struct drm_format_info * info ;
info = drm_format_info ( format ) ;
return info ? info - > num_planes : 1 ;
2016-06-09 12:54:08 +03:00
}
EXPORT_SYMBOL ( drm_format_num_planes ) ;
/**
* drm_format_plane_cpp - determine the bytes per pixel value
* @ format : pixel format ( DRM_FORMAT_ * )
* @ plane : plane index
*
* Returns :
* The bytes per pixel value for the specified plane .
*/
int drm_format_plane_cpp ( uint32_t format , int plane )
{
2016-10-18 01:41:10 +03:00
const struct drm_format_info * info ;
2016-06-09 12:54:08 +03:00
2016-10-18 01:41:10 +03:00
info = drm_format_info ( format ) ;
if ( ! info | | plane > = info - > num_planes )
2016-06-09 12:54:08 +03:00
return 0 ;
2016-10-18 01:41:10 +03:00
return info - > cpp [ plane ] ;
2016-06-09 12:54:08 +03:00
}
EXPORT_SYMBOL ( drm_format_plane_cpp ) ;
/**
* drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
* @ format : pixel format ( DRM_FORMAT_ * )
*
* Returns :
* The horizontal chroma subsampling factor for the
* specified pixel format .
*/
int drm_format_horz_chroma_subsampling ( uint32_t format )
{
2016-10-18 01:41:10 +03:00
const struct drm_format_info * info ;
info = drm_format_info ( format ) ;
return info ? info - > hsub : 1 ;
2016-06-09 12:54:08 +03:00
}
EXPORT_SYMBOL ( drm_format_horz_chroma_subsampling ) ;
/**
* drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
* @ format : pixel format ( DRM_FORMAT_ * )
*
* Returns :
* The vertical chroma subsampling factor for the
* specified pixel format .
*/
int drm_format_vert_chroma_subsampling ( uint32_t format )
{
2016-10-18 01:41:10 +03:00
const struct drm_format_info * info ;
info = drm_format_info ( format ) ;
return info ? info - > vsub : 1 ;
2016-06-09 12:54:08 +03:00
}
EXPORT_SYMBOL ( drm_format_vert_chroma_subsampling ) ;
/**
* drm_format_plane_width - width of the plane given the first plane
* @ width : width of the first plane
* @ format : pixel format
* @ plane : plane index
*
* Returns :
* The width of @ plane , given that the width of the first plane is @ width .
*/
int drm_format_plane_width ( int width , uint32_t format , int plane )
{
2016-10-18 01:41:10 +03:00
const struct drm_format_info * info ;
info = drm_format_info ( format ) ;
if ( ! info | | plane > = info - > num_planes )
2016-06-09 12:54:08 +03:00
return 0 ;
if ( plane = = 0 )
return width ;
2016-10-18 01:41:10 +03:00
return width / info - > hsub ;
2016-06-09 12:54:08 +03:00
}
EXPORT_SYMBOL ( drm_format_plane_width ) ;
/**
* drm_format_plane_height - height of the plane given the first plane
* @ height : height of the first plane
* @ format : pixel format
* @ plane : plane index
*
* Returns :
* The height of @ plane , given that the height of the first plane is @ height .
*/
int drm_format_plane_height ( int height , uint32_t format , int plane )
{
2016-10-18 01:41:10 +03:00
const struct drm_format_info * info ;
info = drm_format_info ( format ) ;
if ( ! info | | plane > = info - > num_planes )
2016-06-09 12:54:08 +03:00
return 0 ;
if ( plane = = 0 )
return height ;
2016-10-18 01:41:10 +03:00
return height / info - > vsub ;
2016-06-09 12:54:08 +03:00
}
EXPORT_SYMBOL ( drm_format_plane_height ) ;