2015-11-11 23:04:44 -02:00
/*
* vsp1_clu . c - - R - Car VSP1 Cubic Look - Up Table
*
* Copyright ( C ) 2015 - 2016 Renesas Electronics 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/slab.h>
# include <media/v4l2-subdev.h>
# include "vsp1.h"
# include "vsp1_clu.h"
# include "vsp1_dl.h"
# define CLU_MIN_SIZE 4U
# define CLU_MAX_SIZE 8190U
/* -----------------------------------------------------------------------------
* Device Access
*/
static inline void vsp1_clu_write ( struct vsp1_clu * clu , struct vsp1_dl_list * dl ,
u32 reg , u32 data )
{
vsp1_dl_list_write ( dl , reg , data ) ;
}
/* -----------------------------------------------------------------------------
* Controls
*/
# define V4L2_CID_VSP1_CLU_TABLE (V4L2_CID_USER_BASE | 0x1001)
# define V4L2_CID_VSP1_CLU_MODE (V4L2_CID_USER_BASE | 0x1002)
# define V4L2_CID_VSP1_CLU_MODE_2D 0
# define V4L2_CID_VSP1_CLU_MODE_3D 1
static int clu_set_table ( struct vsp1_clu * clu , struct v4l2_ctrl * ctrl )
{
struct vsp1_dl_body * dlb ;
unsigned int i ;
dlb = vsp1_dl_fragment_alloc ( clu - > entity . vsp1 , 1 + 17 * 17 * 17 ) ;
if ( ! dlb )
return - ENOMEM ;
vsp1_dl_fragment_write ( dlb , VI6_CLU_ADDR , 0 ) ;
for ( i = 0 ; i < 17 * 17 * 17 ; + + i )
vsp1_dl_fragment_write ( dlb , VI6_CLU_DATA , ctrl - > p_new . p_u32 [ i ] ) ;
2016-06-11 04:11:27 -03:00
spin_lock_irq ( & clu - > lock ) ;
2015-11-11 23:04:44 -02:00
swap ( clu - > clu , dlb ) ;
2016-06-11 04:11:27 -03:00
spin_unlock_irq ( & clu - > lock ) ;
2015-11-11 23:04:44 -02:00
vsp1_dl_fragment_free ( dlb ) ;
return 0 ;
}
static int clu_s_ctrl ( struct v4l2_ctrl * ctrl )
{
struct vsp1_clu * clu =
container_of ( ctrl - > handler , struct vsp1_clu , ctrls ) ;
switch ( ctrl - > id ) {
case V4L2_CID_VSP1_CLU_TABLE :
clu_set_table ( clu , ctrl ) ;
break ;
case V4L2_CID_VSP1_CLU_MODE :
clu - > mode = ctrl - > val ;
break ;
}
return 0 ;
}
static const struct v4l2_ctrl_ops clu_ctrl_ops = {
. s_ctrl = clu_s_ctrl ,
} ;
static const struct v4l2_ctrl_config clu_table_control = {
. ops = & clu_ctrl_ops ,
. id = V4L2_CID_VSP1_CLU_TABLE ,
. name = " Look-Up Table " ,
. type = V4L2_CTRL_TYPE_U32 ,
. min = 0x00000000 ,
. max = 0x00ffffff ,
. step = 1 ,
. def = 0 ,
. dims = { 17 , 17 , 17 } ,
} ;
static const char * const clu_mode_menu [ ] = {
" 2D " ,
" 3D " ,
NULL ,
} ;
static const struct v4l2_ctrl_config clu_mode_control = {
. ops = & clu_ctrl_ops ,
. id = V4L2_CID_VSP1_CLU_MODE ,
. name = " Mode " ,
. type = V4L2_CTRL_TYPE_MENU ,
. min = 0 ,
. max = 1 ,
. def = 1 ,
. qmenu = clu_mode_menu ,
} ;
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Pad Operations
*/
static int clu_enum_mbus_code ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_mbus_code_enum * code )
{
static const unsigned int codes [ ] = {
MEDIA_BUS_FMT_ARGB8888_1X32 ,
MEDIA_BUS_FMT_AHSV8888_1X32 ,
MEDIA_BUS_FMT_AYUV8_1X32 ,
} ;
return vsp1_subdev_enum_mbus_code ( subdev , cfg , code , codes ,
ARRAY_SIZE ( codes ) ) ;
}
static int clu_enum_frame_size ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_frame_size_enum * fse )
{
return vsp1_subdev_enum_frame_size ( subdev , cfg , fse , CLU_MIN_SIZE ,
CLU_MIN_SIZE , CLU_MAX_SIZE ,
CLU_MAX_SIZE ) ;
}
static int clu_set_format ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_format * fmt )
{
struct vsp1_clu * clu = to_clu ( subdev ) ;
struct v4l2_subdev_pad_config * config ;
struct v4l2_mbus_framefmt * format ;
2016-06-26 08:09:31 -03:00
int ret = 0 ;
mutex_lock ( & clu - > entity . lock ) ;
2015-11-11 23:04:44 -02:00
config = vsp1_entity_get_pad_config ( & clu - > entity , cfg , fmt - > which ) ;
2016-06-26 08:09:31 -03:00
if ( ! config ) {
ret = - EINVAL ;
goto done ;
}
2015-11-11 23:04:44 -02:00
/* Default to YUV if the requested format is not supported. */
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 ;
format = vsp1_entity_get_pad_format ( & clu - > entity , config , fmt - > pad ) ;
if ( fmt - > pad = = CLU_PAD_SOURCE ) {
/* The CLU output format can't be modified. */
fmt - > format = * format ;
2016-06-26 08:09:31 -03:00
goto done ;
2015-11-11 23:04:44 -02:00
}
format - > code = fmt - > format . code ;
format - > width = clamp_t ( unsigned int , fmt - > format . width ,
CLU_MIN_SIZE , CLU_MAX_SIZE ) ;
format - > height = clamp_t ( unsigned int , fmt - > format . height ,
CLU_MIN_SIZE , CLU_MAX_SIZE ) ;
format - > field = V4L2_FIELD_NONE ;
format - > colorspace = V4L2_COLORSPACE_SRGB ;
fmt - > format = * format ;
/* Propagate the format to the source pad. */
format = vsp1_entity_get_pad_format ( & clu - > entity , config ,
CLU_PAD_SOURCE ) ;
* format = fmt - > format ;
2016-06-26 08:09:31 -03:00
done :
mutex_unlock ( & clu - > entity . lock ) ;
return ret ;
2015-11-11 23:04:44 -02:00
}
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations
*/
static const struct v4l2_subdev_pad_ops clu_pad_ops = {
. init_cfg = vsp1_entity_init_cfg ,
. enum_mbus_code = clu_enum_mbus_code ,
. enum_frame_size = clu_enum_frame_size ,
. get_fmt = vsp1_subdev_get_pad_format ,
. set_fmt = clu_set_format ,
} ;
static const struct v4l2_subdev_ops clu_ops = {
. pad = & clu_pad_ops ,
} ;
/* -----------------------------------------------------------------------------
* VSP1 Entity Operations
*/
static void clu_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-11 23:04:44 -02:00
{
struct vsp1_clu * clu = to_clu ( & entity - > subdev ) ;
2016-06-11 04:11:27 -03:00
struct vsp1_dl_body * dlb ;
unsigned long flags ;
2015-11-11 23:04:44 -02:00
u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN ;
2016-09-11 19:39:30 -03:00
switch ( params ) {
case VSP1_ENTITY_PARAMS_INIT : {
2016-09-19 15:18:01 -03:00
/*
* The format can ' t be changed during streaming , only verify it
2016-09-11 19:39:30 -03:00
* at setup time and store the information internally for future
* runtime configuration calls .
*/
2016-06-11 04:11:27 -03:00
struct v4l2_mbus_framefmt * format ;
format = vsp1_entity_get_pad_format ( & clu - > entity ,
clu - > entity . config ,
CLU_PAD_SINK ) ;
clu - > yuv_mode = format - > code = = MEDIA_BUS_FMT_AYUV8_1X32 ;
2016-09-11 19:39:30 -03:00
break ;
2016-06-11 04:11:27 -03:00
}
2015-11-11 23:04:44 -02: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 :
/* 2D mode can only be used with the YCbCr pixel encoding. */
if ( clu - > mode = = V4L2_CID_VSP1_CLU_MODE_2D & & clu - > yuv_mode )
ctrl | = VI6_CLU_CTRL_AX1I_2D | VI6_CLU_CTRL_AX2I_2D
| VI6_CLU_CTRL_OS0_2D | VI6_CLU_CTRL_OS1_2D
| VI6_CLU_CTRL_OS2_2D | VI6_CLU_CTRL_M2D ;
2015-11-11 23:04:44 -02:00
2016-09-11 19:39:30 -03:00
vsp1_clu_write ( clu , dl , VI6_CLU_CTRL , ctrl ) ;
2015-11-11 23:04:44 -02:00
2016-09-11 19:39:30 -03:00
spin_lock_irqsave ( & clu - > lock , flags ) ;
dlb = clu - > clu ;
clu - > clu = NULL ;
spin_unlock_irqrestore ( & clu - > lock , flags ) ;
2015-11-11 23:04:44 -02:00
2016-09-11 19:39:30 -03:00
if ( dlb )
vsp1_dl_list_add_fragment ( dl , dlb ) ;
break ;
}
2015-11-11 23:04:44 -02:00
}
static const struct vsp1_entity_operations clu_entity_ops = {
. configure = clu_configure ,
} ;
/* -----------------------------------------------------------------------------
* Initialization and Cleanup
*/
struct vsp1_clu * vsp1_clu_create ( struct vsp1_device * vsp1 )
{
struct vsp1_clu * clu ;
int ret ;
clu = devm_kzalloc ( vsp1 - > dev , sizeof ( * clu ) , GFP_KERNEL ) ;
if ( clu = = NULL )
return ERR_PTR ( - ENOMEM ) ;
2016-06-11 04:11:27 -03:00
spin_lock_init ( & clu - > lock ) ;
2015-11-11 23:04:44 -02:00
clu - > entity . ops = & clu_entity_ops ;
clu - > entity . type = VSP1_ENTITY_CLU ;
ret = vsp1_entity_init ( vsp1 , & clu - > entity , " clu " , 2 , & clu_ops ,
MEDIA_ENT_F_PROC_VIDEO_LUT ) ;
if ( ret < 0 )
return ERR_PTR ( ret ) ;
/* Initialize the control handler. */
v4l2_ctrl_handler_init ( & clu - > ctrls , 2 ) ;
v4l2_ctrl_new_custom ( & clu - > ctrls , & clu_table_control , NULL ) ;
v4l2_ctrl_new_custom ( & clu - > ctrls , & clu_mode_control , NULL ) ;
clu - > entity . subdev . ctrl_handler = & clu - > ctrls ;
if ( clu - > ctrls . error ) {
dev_err ( vsp1 - > dev , " clu: failed to initialize controls \n " ) ;
ret = clu - > ctrls . error ;
vsp1_entity_destroy ( & clu - > entity ) ;
return ERR_PTR ( ret ) ;
}
v4l2_ctrl_handler_setup ( & clu - > ctrls ) ;
return clu ;
}