2018-04-23 00:33:20 +03:00
// SPDX-License-Identifier: GPL-2.0+
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 )
*/
# include <linux/device.h>
# include <linux/gfp.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
2018-05-18 23:41:59 +03:00
# define LUT_SIZE 256
2013-07-10 19:03:30 +04:00
/* -----------------------------------------------------------------------------
* Device Access
*/
2018-05-18 23:42:02 +03:00
static inline void vsp1_lut_write ( struct vsp1_lut * lut ,
struct vsp1_dl_body * dlb , u32 reg , u32 data )
2013-07-10 19:03:30 +04:00
{
2018-05-18 23:42:02 +03:00
vsp1_dl_body_write ( dlb , reg , data ) ;
2013-07-10 19:03:30 +04:00
}
/* -----------------------------------------------------------------------------
2016-05-13 19:52:11 +03:00
* Controls
2013-07-10 19:03:30 +04:00
*/
2016-05-13 19: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 19:03:30 +04:00
{
2016-03-03 20:17:11 +03:00
struct vsp1_dl_body * dlb ;
unsigned int i ;
2018-05-18 23:41:59 +03:00
dlb = vsp1_dl_body_get ( lut - > pool ) ;
2016-03-03 20:17:11 +03:00
if ( ! dlb )
return - ENOMEM ;
2018-05-18 23:41:59 +03:00
for ( i = 0 ; i < LUT_SIZE ; + + i )
2018-05-18 23:41:56 +03:00
vsp1_dl_body_write ( dlb , VI6_LUT_TABLE + 4 * i ,
2016-05-13 19:52:11 +03:00
ctrl - > p_new . p_u32 [ i ] ) ;
2016-03-03 20:17:11 +03:00
2016-06-11 10:11:27 +03:00
spin_lock_irq ( & lut - > lock ) ;
2016-03-03 20:17:11 +03:00
swap ( lut - > lut , dlb ) ;
2016-06-11 10:11:27 +03:00
spin_unlock_irq ( & lut - > lock ) ;
2016-03-03 20:17:11 +03:00
2018-05-18 23:41:59 +03:00
vsp1_dl_body_put ( dlb ) ;
2016-03-03 20:17:11 +03:00
return 0 ;
2013-07-10 19:03:30 +04:00
}
2016-05-13 19:52:11 +03:00
static int lut_s_ctrl ( struct v4l2_ctrl * ctrl )
2013-07-10 19:03:30 +04:00
{
2016-05-13 19:52:11 +03:00
struct vsp1_lut * lut =
container_of ( ctrl - > handler , struct vsp1_lut , ctrls ) ;
2013-07-10 19:03:30 +04:00
2016-05-13 19:52:11 +03:00
switch ( ctrl - > id ) {
case V4L2_CID_VSP1_LUT_TABLE :
lut_set_table ( lut , ctrl ) ;
break ;
2013-07-10 19:03:30 +04:00
}
2016-05-13 19:52:11 +03:00
return 0 ;
2013-07-10 19:03:30 +04:00
}
2016-05-13 19: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 ,
2018-05-18 23:41:59 +03:00
. dims = { LUT_SIZE } ,
2016-05-13 19:52:11 +03:00
} ;
2013-07-10 19:03:30 +04:00
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Pad Operations
*/
2017-11-27 22:59:45 +03:00
static const unsigned int lut_codes [ ] = {
MEDIA_BUS_FMT_ARGB8888_1X32 ,
MEDIA_BUS_FMT_AHSV8888_1X32 ,
MEDIA_BUS_FMT_AYUV8_1X32 ,
} ;
2013-07-10 19:03:30 +04:00
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 )
{
2017-11-27 22:59:45 +03:00
return vsp1_subdev_enum_mbus_code ( subdev , cfg , code , lut_codes ,
ARRAY_SIZE ( lut_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 )
{
2017-11-27 22:59:45 +03:00
return vsp1_subdev_set_pad_format ( subdev , cfg , fmt , lut_codes ,
ARRAY_SIZE ( lut_codes ) ,
LUT_MIN_SIZE , LUT_MIN_SIZE ,
LUT_MAX_SIZE , LUT_MAX_SIZE ) ;
2013-07-10 19:03:30 +04:00
}
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations
*/
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
. pad = & lut_pad_ops ,
} ;
2015-11-17 18:10:26 +03:00
/* -----------------------------------------------------------------------------
* VSP1 Entity Operations
*/
2018-05-18 23:42:01 +03:00
static void lut_configure_stream ( struct vsp1_entity * entity ,
struct vsp1_pipeline * pipe ,
2018-05-18 23:42:02 +03:00
struct vsp1_dl_body * dlb )
2015-11-17 18:10:26 +03:00
{
struct vsp1_lut * lut = to_lut ( & entity - > subdev ) ;
2016-05-13 19:52:11 +03:00
2018-05-18 23:42:02 +03:00
vsp1_lut_write ( lut , dlb , VI6_LUT_CTRL , VI6_LUT_CTRL_EN ) ;
2018-05-18 23:42:01 +03:00
}
2016-09-12 15:50:13 +03:00
2018-05-18 23:42:01 +03:00
static void lut_configure_frame ( struct vsp1_entity * entity ,
struct vsp1_pipeline * pipe ,
2018-05-18 23:42:02 +03:00
struct vsp1_dl_list * dl ,
struct vsp1_dl_body * dlb )
2018-05-18 23:42:01 +03:00
{
struct vsp1_lut * lut = to_lut ( & entity - > subdev ) ;
2018-05-18 23:42:02 +03:00
struct vsp1_dl_body * lut_dlb ;
2018-05-18 23:42:01 +03:00
unsigned long flags ;
2016-06-11 10:11:27 +03:00
2018-05-18 23:42:01 +03:00
spin_lock_irqsave ( & lut - > lock , flags ) ;
2018-05-18 23:42:02 +03:00
lut_dlb = lut - > lut ;
2018-05-18 23:42:01 +03:00
lut - > lut = NULL ;
spin_unlock_irqrestore ( & lut - > lock , flags ) ;
2018-05-18 23:42:00 +03:00
2018-05-18 23:42:02 +03:00
if ( lut_dlb ) {
vsp1_dl_list_add_body ( dl , lut_dlb ) ;
2018-05-18 23:42:00 +03:00
2018-05-18 23:42:01 +03:00
/* Release our local reference. */
2018-05-18 23:42:02 +03:00
vsp1_dl_body_put ( lut_dlb ) ;
2016-09-12 01:39:30 +03:00
}
2015-11-17 18:10:26 +03:00
}
2018-05-18 23:41:59 +03:00
static void lut_destroy ( struct vsp1_entity * entity )
{
struct vsp1_lut * lut = to_lut ( & entity - > subdev ) ;
vsp1_dl_body_pool_destroy ( lut - > pool ) ;
}
2015-11-17 18:10:26 +03:00
static const struct vsp1_entity_operations lut_entity_ops = {
2018-05-18 23:42:01 +03:00
. configure_stream = lut_configure_stream ,
. configure_frame = lut_configure_frame ,
2018-05-18 23:41:59 +03:00
. destroy = lut_destroy ,
2015-11-17 18:10:26 +03:00
} ;
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-06-11 10:11:27 +03:00
spin_lock_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 ) ;
2018-05-18 23:41:59 +03:00
/*
* Pre - allocate a body pool , with 3 bodies allowing a userspace update
* before the hardware has committed a previous set of tables , handling
* both the queued and pending dl entries .
*/
lut - > pool = vsp1_dl_body_pool_create ( vsp1 , 3 , LUT_SIZE , 0 ) ;
if ( ! lut - > pool )
return ERR_PTR ( - ENOMEM ) ;
2016-05-13 19: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 19:03:30 +04:00
return lut ;
}