2013-06-04 11:22:30 -03:00
/*
* vsp1_rpf . c - - R - Car VSP1 Read Pixel Formatter
*
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 <media/v4l2-subdev.h>
# include "vsp1.h"
# include "vsp1_rwpf.h"
# include "vsp1_video.h"
# define RPF_MAX_WIDTH 8190
# define RPF_MAX_HEIGHT 8190
/* -----------------------------------------------------------------------------
* Device Access
*/
static inline void vsp1_rpf_write ( struct vsp1_rwpf * rpf , u32 reg , u32 data )
{
2015-09-07 01:40:25 -03:00
vsp1_mod_write ( & rpf - > entity , reg + rpf - > entity . index * VI6_RPF_OFFSET ,
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
*/
2015-11-17 13:10:26 -02:00
static struct v4l2_subdev_pad_ops rpf_pad_ops = {
. init_cfg = vsp1_entity_init_cfg ,
. enum_mbus_code = vsp1_rwpf_enum_mbus_code ,
. enum_frame_size = vsp1_rwpf_enum_frame_size ,
. get_fmt = vsp1_rwpf_get_format ,
. set_fmt = vsp1_rwpf_set_format ,
. get_selection = vsp1_rwpf_get_selection ,
. set_selection = vsp1_rwpf_set_selection ,
} ;
static struct v4l2_subdev_ops rpf_ops = {
. pad = & rpf_pad_ops ,
} ;
/* -----------------------------------------------------------------------------
* VSP1 Entity Operations
*/
static void rpf_set_memory ( struct vsp1_entity * entity )
2013-06-04 11:22:30 -03:00
{
2015-11-17 13:10:26 -02:00
struct vsp1_rwpf * rpf = entity_to_rwpf ( entity ) ;
vsp1_rpf_write ( rpf , VI6_RPF_SRCM_ADDR_Y ,
rpf - > mem . addr [ 0 ] + rpf - > offsets [ 0 ] ) ;
vsp1_rpf_write ( rpf , VI6_RPF_SRCM_ADDR_C0 ,
rpf - > mem . addr [ 1 ] + rpf - > offsets [ 1 ] ) ;
vsp1_rpf_write ( rpf , VI6_RPF_SRCM_ADDR_C1 ,
rpf - > mem . addr [ 2 ] + rpf - > offsets [ 1 ] ) ;
}
static void rpf_configure ( struct vsp1_entity * entity )
{
struct vsp1_pipeline * pipe = to_vsp1_pipeline ( & entity - > subdev . entity ) ;
struct vsp1_rwpf * rpf = to_rwpf ( & entity - > subdev ) ;
2015-07-28 14:00:43 -03:00
const struct vsp1_format_info * fmtinfo = rpf - > fmtinfo ;
const struct v4l2_pix_format_mplane * format = & rpf - > format ;
2015-11-15 19:14:22 -02:00
const struct v4l2_mbus_framefmt * source_format ;
const struct v4l2_mbus_framefmt * sink_format ;
2015-11-15 19:14:22 -02:00
const struct v4l2_rect * crop ;
unsigned int left = 0 ;
unsigned int top = 0 ;
2013-06-04 11:22:30 -03:00
u32 pstride ;
u32 infmt ;
2014-05-21 19:00:05 -03:00
2013-08-24 20:49:58 -03:00
/* Source size, stride and crop offsets.
*
* The crop offsets correspond to the location of the crop rectangle top
* left corner in the plane buffer . Only two offsets are needed , as
* planes 2 and 3 always have identical strides .
*/
2015-11-15 19:14:22 -02:00
crop = vsp1_rwpf_get_crop ( rpf , rpf - > entity . config ) ;
2013-06-04 11:22:30 -03:00
vsp1_rpf_write ( rpf , VI6_RPF_SRC_BSIZE ,
2013-08-24 20:49:58 -03:00
( crop - > width < < VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT ) |
( crop - > height < < VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT ) ) ;
2013-06-04 11:22:30 -03:00
vsp1_rpf_write ( rpf , VI6_RPF_SRC_ESIZE ,
2013-08-24 20:49:58 -03:00
( crop - > width < < VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT ) |
( crop - > height < < VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT ) ) ;
2013-06-04 11:22:30 -03:00
2013-08-24 20:49:58 -03:00
rpf - > offsets [ 0 ] = crop - > top * format - > plane_fmt [ 0 ] . bytesperline
+ crop - > left * fmtinfo - > bpp [ 0 ] / 8 ;
2013-06-04 11:22:30 -03:00
pstride = format - > plane_fmt [ 0 ] . bytesperline
< < VI6_RPF_SRCM_PSTRIDE_Y_SHIFT ;
2014-11-26 22:25:01 -03:00
2013-08-24 20:49:58 -03:00
if ( format - > num_planes > 1 ) {
rpf - > offsets [ 1 ] = crop - > top * format - > plane_fmt [ 1 ] . bytesperline
+ crop - > left * fmtinfo - > bpp [ 1 ] / 8 ;
2013-06-04 11:22:30 -03:00
pstride | = format - > plane_fmt [ 1 ] . bytesperline
< < VI6_RPF_SRCM_PSTRIDE_C_SHIFT ;
2015-11-01 13:48:11 -02:00
} else {
rpf - > offsets [ 1 ] = 0 ;
2013-08-24 20:49:58 -03:00
}
2013-06-04 11:22:30 -03:00
vsp1_rpf_write ( rpf , VI6_RPF_SRCM_PSTRIDE , pstride ) ;
/* Format */
2015-11-15 19:14:22 -02:00
sink_format = vsp1_entity_get_pad_format ( & rpf - > entity ,
rpf - > entity . config ,
RWPF_PAD_SINK ) ;
source_format = vsp1_entity_get_pad_format ( & rpf - > entity ,
rpf - > entity . config ,
RWPF_PAD_SOURCE ) ;
2013-06-04 11:22:30 -03:00
infmt = VI6_RPF_INFMT_CIPM
| ( fmtinfo - > hwfmt < < VI6_RPF_INFMT_RDFMT_SHIFT ) ;
if ( fmtinfo - > swap_yc )
infmt | = VI6_RPF_INFMT_SPYCS ;
if ( fmtinfo - > swap_uv )
infmt | = VI6_RPF_INFMT_SPUVS ;
2015-11-15 19:14:22 -02:00
if ( sink_format - > code ! = source_format - > code )
2013-06-04 11:22:30 -03:00
infmt | = VI6_RPF_INFMT_CSC ;
vsp1_rpf_write ( rpf , VI6_RPF_INFMT , infmt ) ;
vsp1_rpf_write ( rpf , VI6_RPF_DSWAP , fmtinfo - > swap ) ;
2013-07-10 18:03:46 -03:00
/* Output location */
2015-11-15 19:14:22 -02:00
if ( pipe - > bru ) {
const struct v4l2_rect * compose ;
compose = vsp1_entity_get_pad_compose ( pipe - > bru ,
pipe - > bru - > config ,
rpf - > bru_input ) ;
left = compose - > left ;
top = compose - > top ;
}
2013-07-10 18:03:46 -03:00
vsp1_rpf_write ( rpf , VI6_RPF_LOC ,
2015-11-15 19:14:22 -02:00
( left < < VI6_RPF_LOC_HCOORD_SHIFT ) |
( top < < VI6_RPF_LOC_VCOORD_SHIFT ) ) ;
2013-06-04 11:22:30 -03:00
2014-05-21 19:00:05 -03:00
/* Use the alpha channel (extended to 8 bits) when available or an
* alpha value set through the V4L2_CID_ALPHA_COMPONENT control
* otherwise . Disable color keying .
2013-06-04 11:22:30 -03:00
*/
2014-05-26 20:12:53 -03:00
vsp1_rpf_write ( rpf , VI6_RPF_ALPH_SEL , VI6_RPF_ALPH_SEL_AEXT_EXT |
( fmtinfo - > alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
: VI6_RPF_ALPH_SEL_ASEL_FIXED ) ) ;
2015-08-05 16:57:35 -03:00
vsp1_rpf_write ( rpf , VI6_RPF_VRTCOL_SET ,
2015-11-01 12:19:42 -02:00
rpf - > alpha < < VI6_RPF_VRTCOL_SET_LAYA_SHIFT ) ;
vsp1_pipeline_propagate_alpha ( pipe , & rpf - > entity , rpf - > alpha ) ;
2015-08-05 16:57:35 -03:00
2013-06-04 11:22:30 -03:00
vsp1_rpf_write ( rpf , VI6_RPF_MSK_CTRL , 0 ) ;
vsp1_rpf_write ( rpf , VI6_RPF_CKEY_CTRL , 0 ) ;
}
2015-11-17 12:23:23 -02:00
static const struct vsp1_entity_operations rpf_entity_ops = {
2015-07-28 16:04:47 -03:00
. set_memory = rpf_set_memory ,
2015-11-17 13:10:26 -02:00
. configure = rpf_configure ,
2013-06-04 11:22:30 -03:00
} ;
/* -----------------------------------------------------------------------------
* Initialization and Cleanup
*/
struct vsp1_rwpf * vsp1_rpf_create ( struct vsp1_device * vsp1 , unsigned int index )
{
struct vsp1_rwpf * rpf ;
2015-11-15 19:42:01 -02:00
char name [ 6 ] ;
2013-06-04 11:22:30 -03:00
int ret ;
rpf = devm_kzalloc ( vsp1 - > dev , sizeof ( * rpf ) , GFP_KERNEL ) ;
if ( rpf = = NULL )
return ERR_PTR ( - ENOMEM ) ;
rpf - > max_width = RPF_MAX_WIDTH ;
rpf - > max_height = RPF_MAX_HEIGHT ;
2015-11-17 12:23:23 -02:00
rpf - > entity . ops = & rpf_entity_ops ;
2013-06-04 11:22:30 -03:00
rpf - > entity . type = VSP1_ENTITY_RPF ;
rpf - > entity . index = index ;
2015-11-15 19:42:01 -02:00
sprintf ( name , " rpf.%u " , index ) ;
ret = vsp1_entity_init ( vsp1 , & rpf - > entity , name , 2 , & rpf_ops ) ;
2013-06-04 11:22:30 -03:00
if ( ret < 0 )
return ERR_PTR ( ret ) ;
2014-05-21 19:00:05 -03:00
/* Initialize the control handler. */
2015-11-01 12:19:42 -02:00
ret = vsp1_rwpf_init_ctrls ( rpf ) ;
if ( ret < 0 ) {
2014-05-21 19:00:05 -03:00
dev_err ( vsp1 - > dev , " rpf%u: failed to initialize controls \n " ,
index ) ;
goto error ;
}
2013-06-04 11:22:30 -03:00
return rpf ;
2014-05-28 12:49:13 -03:00
error :
vsp1_entity_destroy ( & rpf - > entity ) ;
2013-06-04 11:22:30 -03:00
return ERR_PTR ( ret ) ;
}