2018-04-22 17:33:20 -04:00
// SPDX-License-Identifier: GPL-2.0+
2013-07-10 12:03:30 -03:00
/*
* vsp1_lut . c - - R - Car VSP1 Look - Up Table
*
* Copyright ( C ) 2013 Renesas Corporation
*
* Contact : Laurent Pinchart ( laurent . pinchart @ ideasonboard . com )
*/
# include <linux/device.h>
# include <linux/gfp.h>
# include <media/v4l2-subdev.h>
# include "vsp1.h"
2015-11-22 20:29:25 -02:00
# include "vsp1_dl.h"
2013-07-10 12:03:30 -03:00
# include "vsp1_lut.h"
# define LUT_MIN_SIZE 4U
# define LUT_MAX_SIZE 8190U
/* -----------------------------------------------------------------------------
* Device Access
*/
2015-11-22 20:29:25 -02:00
static inline void vsp1_lut_write ( struct vsp1_lut * lut , struct vsp1_dl_list * dl ,
u32 reg , u32 data )
2013-07-10 12:03:30 -03:00
{
2015-11-22 20:29:25 -02:00
vsp1_dl_list_write ( dl , reg , data ) ;
2013-07-10 12:03:30 -03:00
}
/* -----------------------------------------------------------------------------
2016-05-13 13:52:11 -03:00
* Controls
2013-07-10 12:03:30 -03:00
*/
2016-05-13 13:52:11 -03:00
# define V4L2_CID_VSP1_LUT_TABLE (V4L2_CID_USER_BASE | 0x1001)
static int lut_set_table ( struct vsp1_lut * lut , struct v4l2_ctrl * ctrl )
2013-07-10 12:03:30 -03:00
{
2016-03-03 14:17:11 -03:00
struct vsp1_dl_body * dlb ;
unsigned int i ;
2016-05-13 13:52:11 -03:00
dlb = vsp1_dl_fragment_alloc ( lut - > entity . vsp1 , 256 ) ;
2016-03-03 14:17:11 -03:00
if ( ! dlb )
return - ENOMEM ;
2016-05-13 13:52:11 -03:00
for ( i = 0 ; i < 256 ; + + i )
2016-03-03 14:17:11 -03:00
vsp1_dl_fragment_write ( dlb , VI6_LUT_TABLE + 4 * i ,
2016-05-13 13:52:11 -03:00
ctrl - > p_new . p_u32 [ i ] ) ;
2016-03-03 14:17:11 -03:00
2016-06-11 04:11:27 -03:00
spin_lock_irq ( & lut - > lock ) ;
2016-03-03 14:17:11 -03:00
swap ( lut - > lut , dlb ) ;
2016-06-11 04:11:27 -03:00
spin_unlock_irq ( & lut - > lock ) ;
2016-03-03 14:17:11 -03:00
vsp1_dl_fragment_free ( dlb ) ;
return 0 ;
2013-07-10 12:03:30 -03:00
}
2016-05-13 13:52:11 -03:00
static int lut_s_ctrl ( struct v4l2_ctrl * ctrl )
2013-07-10 12:03:30 -03:00
{
2016-05-13 13:52:11 -03:00
struct vsp1_lut * lut =
container_of ( ctrl - > handler , struct vsp1_lut , ctrls ) ;
2013-07-10 12:03:30 -03:00
2016-05-13 13:52:11 -03:00
switch ( ctrl - > id ) {
case V4L2_CID_VSP1_LUT_TABLE :
lut_set_table ( lut , ctrl ) ;
break ;
2013-07-10 12:03:30 -03:00
}
2016-05-13 13:52:11 -03:00
return 0 ;
2013-07-10 12:03:30 -03:00
}
2016-05-13 13:52:11 -03:00
static const struct v4l2_ctrl_ops lut_ctrl_ops = {
. s_ctrl = lut_s_ctrl ,
} ;
static const struct v4l2_ctrl_config lut_table_control = {
. ops = & lut_ctrl_ops ,
. id = V4L2_CID_VSP1_LUT_TABLE ,
. name = " Look-Up Table " ,
. type = V4L2_CTRL_TYPE_U32 ,
. min = 0x00000000 ,
. max = 0x00ffffff ,
. step = 1 ,
. def = 0 ,
. dims = { 256 } ,
} ;
2013-07-10 12:03:30 -03:00
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Pad Operations
*/
static int lut_enum_mbus_code ( struct v4l2_subdev * subdev ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2013-07-10 12:03:30 -03:00
struct v4l2_subdev_mbus_code_enum * code )
{
static const unsigned int codes [ ] = {
2014-11-10 14:28:31 -03:00
MEDIA_BUS_FMT_ARGB8888_1X32 ,
MEDIA_BUS_FMT_AHSV8888_1X32 ,
MEDIA_BUS_FMT_AYUV8_1X32 ,
2013-07-10 12:03:30 -03:00
} ;
2016-02-24 20:25:42 -03:00
return vsp1_subdev_enum_mbus_code ( subdev , cfg , code , codes ,
ARRAY_SIZE ( codes ) ) ;
2013-07-10 12:03:30 -03:00
}
static int lut_enum_frame_size ( struct v4l2_subdev * subdev ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2013-07-10 12:03:30 -03:00
struct v4l2_subdev_frame_size_enum * fse )
{
2016-02-24 20: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 12:03:30 -03:00
}
2015-11-01 15:18:32 -02:00
static int lut_set_format ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
2013-07-10 12:03:30 -03:00
struct v4l2_subdev_format * fmt )
{
struct vsp1_lut * lut = to_lut ( subdev ) ;
2015-11-15 19:14:22 -02:00
struct v4l2_subdev_pad_config * config ;
2013-07-10 12:03:30 -03:00
struct v4l2_mbus_framefmt * format ;
2016-06-26 08:09:31 -03:00
int ret = 0 ;
mutex_lock ( & lut - > entity . lock ) ;
2013-07-10 12:03:30 -03:00
2015-11-15 19:14:22 -02:00
config = vsp1_entity_get_pad_config ( & lut - > entity , cfg , fmt - > which ) ;
2016-06-26 08:09:31 -03:00
if ( ! config ) {
ret = - EINVAL ;
goto done ;
}
2015-11-15 19:14:22 -02:00
2013-07-10 12:03:30 -03:00
/* Default to YUV if the requested format is not supported. */
2014-11-10 14: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 12:03:30 -03:00
2015-11-15 19:14:22 -02:00
format = vsp1_entity_get_pad_format ( & lut - > entity , config , fmt - > pad ) ;
2013-07-10 12:03:30 -03:00
if ( fmt - > pad = = LUT_PAD_SOURCE ) {
/* The LUT output format can't be modified. */
fmt - > format = * format ;
2016-06-26 08:09:31 -03:00
goto done ;
2013-07-10 12:03:30 -03:00
}
2015-11-16 02:07:58 -02:00
format - > code = fmt - > format . code ;
2013-07-10 12:03:30 -03: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-15 19:14:22 -02:00
format = vsp1_entity_get_pad_format ( & lut - > entity , config ,
LUT_PAD_SOURCE ) ;
2013-07-10 12:03:30 -03:00
* format = fmt - > format ;
2016-06-26 08:09:31 -03:00
done :
mutex_unlock ( & lut - > entity . lock ) ;
return ret ;
2013-07-10 12:03:30 -03:00
}
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations
*/
2016-06-17 21:11:26 -03:00
static const struct v4l2_subdev_pad_ops lut_pad_ops = {
2015-11-15 20:09:08 -02:00
. init_cfg = vsp1_entity_init_cfg ,
2013-07-10 12:03:30 -03:00
. enum_mbus_code = lut_enum_mbus_code ,
. enum_frame_size = lut_enum_frame_size ,
2016-02-24 21:10:13 -03:00
. get_fmt = vsp1_subdev_get_pad_format ,
2013-07-10 12:03:30 -03:00
. set_fmt = lut_set_format ,
} ;
2016-06-17 21:11:26 -03:00
static const struct v4l2_subdev_ops lut_ops = {
2013-07-10 12:03:30 -03:00
. pad = & lut_pad_ops ,
} ;
2015-11-17 13:10:26 -02:00
/* -----------------------------------------------------------------------------
* VSP1 Entity Operations
*/
2016-01-14 14:17:32 -02:00
static void lut_configure ( struct vsp1_entity * entity ,
struct vsp1_pipeline * pipe ,
2016-09-11 19:39:30 -03:00
struct vsp1_dl_list * dl ,
enum vsp1_entity_params params )
2015-11-17 13:10:26 -02:00
{
struct vsp1_lut * lut = to_lut ( & entity - > subdev ) ;
2016-06-11 04:11:27 -03:00
struct vsp1_dl_body * dlb ;
unsigned long flags ;
2015-11-17 13:10:26 -02:00
2016-09-11 19:39:30 -03:00
switch ( params ) {
case VSP1_ENTITY_PARAMS_INIT :
2016-06-11 04:11:27 -03:00
vsp1_lut_write ( lut , dl , VI6_LUT_CTRL , VI6_LUT_CTRL_EN ) ;
2016-09-11 19:39:30 -03:00
break ;
2016-05-13 13:52:11 -03:00
2016-09-12 09:50:13 -03:00
case VSP1_ENTITY_PARAMS_PARTITION :
break ;
2016-09-11 19:39:30 -03:00
case VSP1_ENTITY_PARAMS_RUNTIME :
spin_lock_irqsave ( & lut - > lock , flags ) ;
dlb = lut - > lut ;
lut - > lut = NULL ;
spin_unlock_irqrestore ( & lut - > lock , flags ) ;
2016-06-11 04:11:27 -03:00
2016-09-11 19:39:30 -03:00
if ( dlb )
vsp1_dl_list_add_fragment ( dl , dlb ) ;
break ;
}
2015-11-17 13:10:26 -02:00
}
static const struct vsp1_entity_operations lut_entity_ops = {
. configure = lut_configure ,
} ;
2013-07-10 12:03:30 -03: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-06-11 04:11:27 -03:00
spin_lock_init ( & lut - > lock ) ;
2015-11-17 13:10:26 -02:00
lut - > entity . ops = & lut_entity_ops ;
2013-07-10 12:03:30 -03:00
lut - > entity . type = VSP1_ENTITY_LUT ;
2016-02-15 22:10:26 -02:00
ret = vsp1_entity_init ( vsp1 , & lut - > entity , " lut " , 2 , & lut_ops ,
MEDIA_ENT_F_PROC_VIDEO_LUT ) ;
2013-07-10 12:03:30 -03:00
if ( ret < 0 )
return ERR_PTR ( ret ) ;
2016-05-13 13:52:11 -03:00
/* Initialize the control handler. */
v4l2_ctrl_handler_init ( & lut - > ctrls , 1 ) ;
v4l2_ctrl_new_custom ( & lut - > ctrls , & lut_table_control , NULL ) ;
lut - > entity . subdev . ctrl_handler = & lut - > ctrls ;
if ( lut - > ctrls . error ) {
dev_err ( vsp1 - > dev , " lut: failed to initialize controls \n " ) ;
ret = lut - > ctrls . error ;
vsp1_entity_destroy ( & lut - > entity ) ;
return ERR_PTR ( ret ) ;
}
v4l2_ctrl_handler_setup ( & lut - > ctrls ) ;
2013-07-10 12:03:30 -03:00
return lut ;
}