2013-06-04 11:22:30 -03:00
/*
* vsp1_lif . c - - R - Car VSP1 LCD Controller Interface
*
2014-02-06 14:42:31 -03:00
* Copyright ( C ) 2013 - 2014 Renesas Electronics Corporation
2013-06-04 11:22:30 -03:00
*
* 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 <media/v4l2-subdev.h>
# include "vsp1.h"
2015-11-22 20:29:25 -02:00
# include "vsp1_dl.h"
2013-06-04 11:22:30 -03:00
# include "vsp1_lif.h"
# define LIF_MIN_SIZE 2U
2016-03-25 06:51:06 -03:00
# define LIF_MAX_SIZE 8190U
2013-06-04 11:22:30 -03:00
/* -----------------------------------------------------------------------------
* Device Access
*/
2015-11-22 20:29:25 -02:00
static inline void vsp1_lif_write ( struct vsp1_lif * lif , struct vsp1_dl_list * dl ,
u32 reg , u32 data )
2013-06-04 11:22:30 -03:00
{
2015-11-22 20:29:25 -02:00
vsp1_dl_list_write ( dl , reg , data ) ;
2013-06-04 11:22:30 -03:00
}
/* -----------------------------------------------------------------------------
2015-11-17 13:10:26 -02:00
* V4L2 Subdevice Operations
2013-06-04 11:22:30 -03:00
*/
static int lif_enum_mbus_code ( struct v4l2_subdev * subdev ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2013-06-04 11:22: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_AYUV8_1X32 ,
2013-06-04 11:22: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-06-04 11:22:30 -03:00
}
static int lif_enum_frame_size ( struct v4l2_subdev * subdev ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2013-06-04 11:22: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 , LIF_MIN_SIZE ,
LIF_MIN_SIZE , LIF_MAX_SIZE ,
LIF_MAX_SIZE ) ;
2013-06-04 11:22:30 -03:00
}
2015-11-01 15:18:32 -02:00
static int lif_set_format ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
2013-06-04 11:22:30 -03:00
struct v4l2_subdev_format * fmt )
{
struct vsp1_lif * lif = to_lif ( subdev ) ;
2015-11-15 19:14:22 -02:00
struct v4l2_subdev_pad_config * config ;
2013-06-04 11:22:30 -03:00
struct v4l2_mbus_framefmt * format ;
2016-06-26 08:09:31 -03:00
int ret = 0 ;
mutex_lock ( & lif - > entity . lock ) ;
2013-06-04 11:22:30 -03:00
2015-11-15 19:14:22 -02:00
config = vsp1_entity_get_pad_config ( & lif - > 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-06-04 11:22: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_AYUV8_1X32 )
fmt - > format . code = MEDIA_BUS_FMT_AYUV8_1X32 ;
2013-06-04 11:22:30 -03:00
2015-11-15 19:14:22 -02:00
format = vsp1_entity_get_pad_format ( & lif - > entity , config , fmt - > pad ) ;
2013-06-04 11:22:30 -03:00
if ( fmt - > pad = = LIF_PAD_SOURCE ) {
/* The LIF source format is always identical to its sink
* format .
*/
fmt - > format = * format ;
2016-06-26 08:09:31 -03:00
goto done ;
2013-06-04 11:22:30 -03:00
}
format - > code = fmt - > format . code ;
format - > width = clamp_t ( unsigned int , fmt - > format . width ,
LIF_MIN_SIZE , LIF_MAX_SIZE ) ;
format - > height = clamp_t ( unsigned int , fmt - > format . height ,
LIF_MIN_SIZE , LIF_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 ( & lif - > entity , config ,
LIF_PAD_SOURCE ) ;
2013-06-04 11:22:30 -03:00
* format = fmt - > format ;
2016-06-26 08:09:31 -03:00
done :
mutex_unlock ( & lif - > entity . lock ) ;
return ret ;
2013-06-04 11:22:30 -03:00
}
2016-06-17 21:11:26 -03:00
static const struct v4l2_subdev_pad_ops lif_pad_ops = {
2015-11-15 20:09:08 -02:00
. init_cfg = vsp1_entity_init_cfg ,
2013-06-04 11:22:30 -03:00
. enum_mbus_code = lif_enum_mbus_code ,
. enum_frame_size = lif_enum_frame_size ,
2016-02-24 21:10:13 -03:00
. get_fmt = vsp1_subdev_get_pad_format ,
2013-06-04 11:22:30 -03:00
. set_fmt = lif_set_format ,
} ;
2016-06-17 21:11:26 -03:00
static const struct v4l2_subdev_ops lif_ops = {
2013-06-04 11:22:30 -03:00
. pad = & lif_pad_ops ,
} ;
2015-11-17 13:10:26 -02:00
/* -----------------------------------------------------------------------------
* VSP1 Entity Operations
*/
2016-01-14 14:17:32 -02:00
static void lif_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
{
const struct v4l2_mbus_framefmt * format ;
struct vsp1_lif * lif = to_lif ( & entity - > subdev ) ;
unsigned int hbth = 1300 ;
unsigned int obth = 400 ;
unsigned int lbth = 200 ;
2016-09-11 19:39:30 -03:00
if ( params ! = VSP1_ENTITY_PARAMS_INIT )
2016-06-11 04:07:56 -03:00
return ;
2015-11-17 13:10:26 -02:00
format = vsp1_entity_get_pad_format ( & lif - > entity , lif - > entity . config ,
LIF_PAD_SOURCE ) ;
obth = min ( obth , ( format - > width + 1 ) / 2 * format - > height - 4 ) ;
2015-11-22 20:29:25 -02:00
vsp1_lif_write ( lif , dl , VI6_LIF_CSBTH ,
2015-11-17 13:10:26 -02:00
( hbth < < VI6_LIF_CSBTH_HBTH_SHIFT ) |
( lbth < < VI6_LIF_CSBTH_LBTH_SHIFT ) ) ;
2015-11-22 20:29:25 -02:00
vsp1_lif_write ( lif , dl , VI6_LIF_CTRL ,
2015-11-17 13:10:26 -02:00
( obth < < VI6_LIF_CTRL_OBTH_SHIFT ) |
( format - > code = = 0 ? VI6_LIF_CTRL_CFMT : 0 ) |
VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN ) ;
}
static const struct vsp1_entity_operations lif_entity_ops = {
. configure = lif_configure ,
} ;
2013-06-04 11:22:30 -03:00
/* -----------------------------------------------------------------------------
* Initialization and Cleanup
*/
struct vsp1_lif * vsp1_lif_create ( struct vsp1_device * vsp1 )
{
struct vsp1_lif * lif ;
int ret ;
lif = devm_kzalloc ( vsp1 - > dev , sizeof ( * lif ) , GFP_KERNEL ) ;
if ( lif = = NULL )
return ERR_PTR ( - ENOMEM ) ;
2015-11-17 13:10:26 -02:00
lif - > entity . ops = & lif_entity_ops ;
2013-06-04 11:22:30 -03:00
lif - > entity . type = VSP1_ENTITY_LIF ;
2016-02-15 22:10:26 -02:00
/* The LIF is never exposed to userspace, but media entity registration
* requires a function to be set . Use PROC_VIDEO_PIXEL_FORMATTER just to
* avoid triggering a WARN_ON ( ) , the value won ' t be seen anywhere .
*/
ret = vsp1_entity_init ( vsp1 , & lif - > entity , " lif " , 2 , & lif_ops ,
MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER ) ;
2013-06-04 11:22:30 -03:00
if ( ret < 0 )
return ERR_PTR ( ret ) ;
return lif ;
}