2013-07-10 19:03:30 +04:00
/*
* vsp1_lut . c - - R - Car VSP1 Look - Up Table
*
* Copyright ( C ) 2013 Renesas Corporation
*
* Contact : Laurent Pinchart ( laurent . pinchart @ ideasonboard . com )
*
* 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/device.h>
# include <linux/gfp.h>
# include <linux/vsp1.h>
# include <media/v4l2-subdev.h>
# include "vsp1.h"
2015-11-23 01:29:25 +03:00
# include "vsp1_dl.h"
2013-07-10 19:03:30 +04:00
# include "vsp1_lut.h"
# define LUT_MIN_SIZE 4U
# define LUT_MAX_SIZE 8190U
/* -----------------------------------------------------------------------------
* Device Access
*/
2015-11-23 01:29:25 +03:00
static inline void vsp1_lut_write ( struct vsp1_lut * lut , struct vsp1_dl_list * dl ,
u32 reg , u32 data )
2013-07-10 19:03:30 +04:00
{
2015-11-23 01:29:25 +03:00
vsp1_dl_list_write ( dl , reg , data ) ;
2013-07-10 19:03:30 +04:00
}
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Core Operations
*/
2016-03-03 20:17:11 +03:00
static int lut_set_table ( struct vsp1_lut * lut , struct vsp1_lut_config * config )
2013-07-10 19:03:30 +04:00
{
2016-03-03 20:17:11 +03:00
struct vsp1_dl_body * dlb ;
unsigned int i ;
dlb = vsp1_dl_fragment_alloc ( lut - > entity . vsp1 , ARRAY_SIZE ( config - > lut ) ) ;
if ( ! dlb )
return - ENOMEM ;
for ( i = 0 ; i < ARRAY_SIZE ( config - > lut ) ; + + i )
vsp1_dl_fragment_write ( dlb , VI6_LUT_TABLE + 4 * i ,
config - > lut [ i ] ) ;
mutex_lock ( & lut - > lock ) ;
swap ( lut - > lut , dlb ) ;
mutex_unlock ( & lut - > lock ) ;
vsp1_dl_fragment_free ( dlb ) ;
return 0 ;
2013-07-10 19:03:30 +04:00
}
static long lut_ioctl ( struct v4l2_subdev * subdev , unsigned int cmd , void * arg )
{
struct vsp1_lut * lut = to_lut ( subdev ) ;
switch ( cmd ) {
case VIDIOC_VSP1_LUT_CONFIG :
2016-03-03 20:17:11 +03:00
return lut_set_table ( lut , arg ) ;
2013-07-10 19:03:30 +04:00
default :
return - ENOIOCTLCMD ;
}
}
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Pad Operations
*/
static int lut_enum_mbus_code ( struct v4l2_subdev * subdev ,
2015-03-04 12:47:54 +03:00
struct v4l2_subdev_pad_config * cfg ,
2013-07-10 19:03:30 +04:00
struct v4l2_subdev_mbus_code_enum * code )
{
static const unsigned int codes [ ] = {
2014-11-10 20:28:31 +03:00
MEDIA_BUS_FMT_ARGB8888_1X32 ,
MEDIA_BUS_FMT_AHSV8888_1X32 ,
MEDIA_BUS_FMT_AYUV8_1X32 ,
2013-07-10 19:03:30 +04:00
} ;
2016-02-25 02:25:42 +03:00
return vsp1_subdev_enum_mbus_code ( subdev , cfg , code , codes ,
ARRAY_SIZE ( codes ) ) ;
2013-07-10 19:03:30 +04:00
}
static int lut_enum_frame_size ( struct v4l2_subdev * subdev ,
2015-03-04 12:47:54 +03:00
struct v4l2_subdev_pad_config * cfg ,
2013-07-10 19:03:30 +04:00
struct v4l2_subdev_frame_size_enum * fse )
{
2016-02-25 02:25:42 +03:00
return vsp1_subdev_enum_frame_size ( subdev , cfg , fse , LUT_MIN_SIZE ,
LUT_MIN_SIZE , LUT_MAX_SIZE ,
LUT_MAX_SIZE ) ;
2013-07-10 19:03:30 +04:00
}
2015-11-01 20:18:32 +03:00
static int lut_set_format ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
2013-07-10 19:03:30 +04:00
struct v4l2_subdev_format * fmt )
{
struct vsp1_lut * lut = to_lut ( subdev ) ;
2015-11-16 00:14:22 +03:00
struct v4l2_subdev_pad_config * config ;
2013-07-10 19:03:30 +04:00
struct v4l2_mbus_framefmt * format ;
2015-11-16 00:14:22 +03:00
config = vsp1_entity_get_pad_config ( & lut - > entity , cfg , fmt - > which ) ;
if ( ! config )
return - EINVAL ;
2013-07-10 19:03:30 +04:00
/* Default to YUV if the requested format is not supported. */
2014-11-10 20:28:31 +03:00
if ( fmt - > format . code ! = MEDIA_BUS_FMT_ARGB8888_1X32 & &
fmt - > format . code ! = MEDIA_BUS_FMT_AHSV8888_1X32 & &
fmt - > format . code ! = MEDIA_BUS_FMT_AYUV8_1X32 )
fmt - > format . code = MEDIA_BUS_FMT_AYUV8_1X32 ;
2013-07-10 19:03:30 +04:00
2015-11-16 00:14:22 +03:00
format = vsp1_entity_get_pad_format ( & lut - > entity , config , fmt - > pad ) ;
2013-07-10 19:03:30 +04:00
if ( fmt - > pad = = LUT_PAD_SOURCE ) {
/* The LUT output format can't be modified. */
fmt - > format = * format ;
return 0 ;
}
2015-11-16 07:07:58 +03:00
format - > code = fmt - > format . code ;
2013-07-10 19:03:30 +04:00
format - > width = clamp_t ( unsigned int , fmt - > format . width ,
LUT_MIN_SIZE , LUT_MAX_SIZE ) ;
format - > height = clamp_t ( unsigned int , fmt - > format . height ,
LUT_MIN_SIZE , LUT_MAX_SIZE ) ;
format - > field = V4L2_FIELD_NONE ;
format - > colorspace = V4L2_COLORSPACE_SRGB ;
fmt - > format = * format ;
/* Propagate the format to the source pad. */
2015-11-16 00:14:22 +03:00
format = vsp1_entity_get_pad_format ( & lut - > entity , config ,
LUT_PAD_SOURCE ) ;
2013-07-10 19:03:30 +04:00
* format = fmt - > format ;
return 0 ;
}
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations
*/
2016-06-18 03:11:26 +03:00
static const struct v4l2_subdev_core_ops lut_core_ops = {
2013-07-10 19:03:30 +04:00
. ioctl = lut_ioctl ,
} ;
2016-06-18 03:11:26 +03:00
static const struct v4l2_subdev_pad_ops lut_pad_ops = {
2015-11-16 01:09:08 +03:00
. init_cfg = vsp1_entity_init_cfg ,
2013-07-10 19:03:30 +04:00
. enum_mbus_code = lut_enum_mbus_code ,
. enum_frame_size = lut_enum_frame_size ,
2016-02-25 03:10:13 +03:00
. get_fmt = vsp1_subdev_get_pad_format ,
2013-07-10 19:03:30 +04:00
. set_fmt = lut_set_format ,
} ;
2016-06-18 03:11:26 +03:00
static const struct v4l2_subdev_ops lut_ops = {
2013-07-10 19:03:30 +04:00
. core = & lut_core_ops ,
. pad = & lut_pad_ops ,
} ;
2015-11-17 18:10:26 +03:00
/* -----------------------------------------------------------------------------
* VSP1 Entity Operations
*/
2016-01-14 19:17:32 +03:00
static void lut_configure ( struct vsp1_entity * entity ,
struct vsp1_pipeline * pipe ,
struct vsp1_dl_list * dl )
2015-11-17 18:10:26 +03:00
{
struct vsp1_lut * lut = to_lut ( & entity - > subdev ) ;
2015-11-23 01:29:25 +03:00
vsp1_lut_write ( lut , dl , VI6_LUT_CTRL , VI6_LUT_CTRL_EN ) ;
2016-03-03 20:17:11 +03:00
mutex_lock ( & lut - > lock ) ;
if ( lut - > lut ) {
vsp1_dl_list_add_fragment ( dl , lut - > lut ) ;
lut - > lut = NULL ;
}
mutex_unlock ( & lut - > lock ) ;
2015-11-17 18:10:26 +03:00
}
static const struct vsp1_entity_operations lut_entity_ops = {
. configure = lut_configure ,
} ;
2013-07-10 19:03:30 +04:00
/* -----------------------------------------------------------------------------
* Initialization and Cleanup
*/
struct vsp1_lut * vsp1_lut_create ( struct vsp1_device * vsp1 )
{
struct vsp1_lut * lut ;
int ret ;
lut = devm_kzalloc ( vsp1 - > dev , sizeof ( * lut ) , GFP_KERNEL ) ;
if ( lut = = NULL )
return ERR_PTR ( - ENOMEM ) ;
2016-05-14 00:15:59 +03:00
mutex_init ( & lut - > lock ) ;
2015-11-17 18:10:26 +03:00
lut - > entity . ops = & lut_entity_ops ;
2013-07-10 19:03:30 +04:00
lut - > entity . type = VSP1_ENTITY_LUT ;
2016-02-16 03:10:26 +03:00
ret = vsp1_entity_init ( vsp1 , & lut - > entity , " lut " , 2 , & lut_ops ,
MEDIA_ENT_F_PROC_VIDEO_LUT ) ;
2013-07-10 19:03:30 +04:00
if ( ret < 0 )
return ERR_PTR ( ret ) ;
return lut ;
}