2013-06-04 11:22:30 -03:00
/*
* vsp1_entity . c - - R - Car VSP1 Base Entity
*
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/media-entity.h>
2013-07-10 12:03:30 -03:00
# include <media/v4l2-ctrls.h>
2013-06-04 11:22:30 -03:00
# include <media/v4l2-subdev.h>
# include "vsp1.h"
2015-11-01 10:46:25 -02:00
# include "vsp1_dl.h"
2013-06-04 11:22:30 -03:00
# include "vsp1_entity.h"
2015-11-01 10:46:25 -02:00
# include "vsp1_pipe.h"
void vsp1_mod_write ( struct vsp1_entity * e , u32 reg , u32 data )
{
struct vsp1_pipeline * pipe = to_vsp1_pipeline ( & e - > subdev . entity ) ;
2015-11-01 15:18:56 -02:00
vsp1_dl_list_write ( pipe - > dl , reg , data ) ;
2015-11-01 10:46:25 -02:00
}
2013-06-04 11:22:30 -03:00
2015-08-02 18:58:31 -03:00
void vsp1_entity_route_setup ( struct vsp1_entity * source )
{
struct vsp1_entity * sink ;
if ( source - > route - > reg = = 0 )
return ;
sink = container_of ( source - > sink , struct vsp1_entity , subdev . entity ) ;
2015-09-07 01:40:25 -03:00
vsp1_mod_write ( source , source - > route - > reg ,
sink - > route - > inputs [ source - > sink_pad ] ) ;
2015-08-02 18:58:31 -03:00
}
2013-06-04 11:22:30 -03:00
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations
*/
struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format ( struct vsp1_entity * entity ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2013-06-04 11:22:30 -03:00
unsigned int pad , u32 which )
{
switch ( which ) {
case V4L2_SUBDEV_FORMAT_TRY :
2015-03-04 01:47:54 -08:00
return v4l2_subdev_get_try_format ( & entity - > subdev , cfg , pad ) ;
2013-06-04 11:22:30 -03:00
case V4L2_SUBDEV_FORMAT_ACTIVE :
return & entity - > formats [ pad ] ;
default :
return NULL ;
}
}
/*
* vsp1_entity_init_formats - Initialize formats on all pads
* @ subdev : V4L2 subdevice
2015-03-04 01:47:54 -08:00
* @ cfg : V4L2 subdev pad configuration
2013-06-04 11:22:30 -03:00
*
2015-03-04 01:47:54 -08:00
* Initialize all pad formats with default values . If cfg is not NULL , try
2013-06-04 11:22:30 -03:00
* formats are initialized on the file handle . Otherwise active formats are
* initialized on the device .
*/
void vsp1_entity_init_formats ( 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_format format ;
unsigned int pad ;
for ( pad = 0 ; pad < subdev - > entity . num_pads - 1 ; + + pad ) {
memset ( & format , 0 , sizeof ( format ) ) ;
format . pad = pad ;
2015-03-04 01:47:54 -08:00
format . which = cfg ? V4L2_SUBDEV_FORMAT_TRY
2013-06-04 11:22:30 -03:00
: V4L2_SUBDEV_FORMAT_ACTIVE ;
2015-03-04 01:47:54 -08:00
v4l2_subdev_call ( subdev , pad , set_fmt , cfg , & format ) ;
2013-06-04 11:22:30 -03:00
}
}
static int vsp1_entity_open ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_fh * fh )
{
2015-03-04 01:47:54 -08:00
vsp1_entity_init_formats ( subdev , fh - > pad ) ;
2013-06-04 11:22:30 -03:00
return 0 ;
}
const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops = {
. open = vsp1_entity_open ,
} ;
/* -----------------------------------------------------------------------------
* Media Operations
*/
2015-08-05 17:14:41 -03:00
int vsp1_entity_link_setup ( struct media_entity * entity ,
const struct media_pad * local ,
const struct media_pad * remote , u32 flags )
2013-06-04 11:22:30 -03:00
{
struct vsp1_entity * source ;
if ( ! ( local - > flags & MEDIA_PAD_FL_SOURCE ) )
return 0 ;
source = container_of ( local - > entity , struct vsp1_entity , subdev . entity ) ;
if ( ! source - > route )
return 0 ;
if ( flags & MEDIA_LNK_FL_ENABLED ) {
if ( source - > sink )
return - EBUSY ;
source - > sink = remote - > entity ;
2013-07-10 18:37:27 -03:00
source - > sink_pad = remote - > index ;
2013-06-04 11:22:30 -03:00
} else {
source - > sink = NULL ;
2013-07-10 18:37:27 -03:00
source - > sink_pad = 0 ;
2013-06-04 11:22:30 -03:00
}
return 0 ;
}
/* -----------------------------------------------------------------------------
* Initialization
*/
2013-07-10 18:37:27 -03:00
static const struct vsp1_route vsp1_routes [ ] = {
2013-07-10 18:03:46 -03:00
{ VSP1_ENTITY_BRU , 0 , VI6_DPR_BRU_ROUTE ,
{ VI6_DPR_NODE_BRU_IN ( 0 ) , VI6_DPR_NODE_BRU_IN ( 1 ) ,
2015-09-07 08:05:39 -03:00
VI6_DPR_NODE_BRU_IN ( 2 ) , VI6_DPR_NODE_BRU_IN ( 3 ) ,
VI6_DPR_NODE_BRU_IN ( 4 ) } } ,
2013-07-10 18:37:27 -03:00
{ VSP1_ENTITY_HSI , 0 , VI6_DPR_HSI_ROUTE , { VI6_DPR_NODE_HSI , } } ,
{ VSP1_ENTITY_HST , 0 , VI6_DPR_HST_ROUTE , { VI6_DPR_NODE_HST , } } ,
{ VSP1_ENTITY_LIF , 0 , 0 , { VI6_DPR_NODE_LIF , } } ,
{ VSP1_ENTITY_LUT , 0 , VI6_DPR_LUT_ROUTE , { VI6_DPR_NODE_LUT , } } ,
{ VSP1_ENTITY_RPF , 0 , VI6_DPR_RPF_ROUTE ( 0 ) , { VI6_DPR_NODE_RPF ( 0 ) , } } ,
{ VSP1_ENTITY_RPF , 1 , VI6_DPR_RPF_ROUTE ( 1 ) , { VI6_DPR_NODE_RPF ( 1 ) , } } ,
{ VSP1_ENTITY_RPF , 2 , VI6_DPR_RPF_ROUTE ( 2 ) , { VI6_DPR_NODE_RPF ( 2 ) , } } ,
{ VSP1_ENTITY_RPF , 3 , VI6_DPR_RPF_ROUTE ( 3 ) , { VI6_DPR_NODE_RPF ( 3 ) , } } ,
{ VSP1_ENTITY_RPF , 4 , VI6_DPR_RPF_ROUTE ( 4 ) , { VI6_DPR_NODE_RPF ( 4 ) , } } ,
{ VSP1_ENTITY_SRU , 0 , VI6_DPR_SRU_ROUTE , { VI6_DPR_NODE_SRU , } } ,
{ VSP1_ENTITY_UDS , 0 , VI6_DPR_UDS_ROUTE ( 0 ) , { VI6_DPR_NODE_UDS ( 0 ) , } } ,
{ VSP1_ENTITY_UDS , 1 , VI6_DPR_UDS_ROUTE ( 1 ) , { VI6_DPR_NODE_UDS ( 1 ) , } } ,
{ VSP1_ENTITY_UDS , 2 , VI6_DPR_UDS_ROUTE ( 2 ) , { VI6_DPR_NODE_UDS ( 2 ) , } } ,
{ VSP1_ENTITY_WPF , 0 , 0 , { VI6_DPR_NODE_WPF ( 0 ) , } } ,
{ VSP1_ENTITY_WPF , 1 , 0 , { VI6_DPR_NODE_WPF ( 1 ) , } } ,
{ VSP1_ENTITY_WPF , 2 , 0 , { VI6_DPR_NODE_WPF ( 2 ) , } } ,
{ VSP1_ENTITY_WPF , 3 , 0 , { VI6_DPR_NODE_WPF ( 3 ) , } } ,
} ;
2013-06-04 11:22:30 -03:00
int vsp1_entity_init ( struct vsp1_device * vsp1 , struct vsp1_entity * entity ,
unsigned int num_pads )
{
unsigned int i ;
2013-07-10 18:37:27 -03:00
for ( i = 0 ; i < ARRAY_SIZE ( vsp1_routes ) ; + + i ) {
if ( vsp1_routes [ i ] . type = = entity - > type & &
vsp1_routes [ i ] . index = = entity - > index ) {
entity - > route = & vsp1_routes [ i ] ;
2013-06-04 11:22:30 -03:00
break ;
}
}
2013-07-10 18:37:27 -03:00
if ( i = = ARRAY_SIZE ( vsp1_routes ) )
2013-06-04 11:22:30 -03:00
return - EINVAL ;
entity - > vsp1 = vsp1 ;
entity - > source_pad = num_pads - 1 ;
/* Allocate formats and pads. */
entity - > formats = devm_kzalloc ( vsp1 - > dev ,
num_pads * sizeof ( * entity - > formats ) ,
GFP_KERNEL ) ;
if ( entity - > formats = = NULL )
return - ENOMEM ;
entity - > pads = devm_kzalloc ( vsp1 - > dev , num_pads * sizeof ( * entity - > pads ) ,
GFP_KERNEL ) ;
if ( entity - > pads = = NULL )
return - ENOMEM ;
/* Initialize pads. */
for ( i = 0 ; i < num_pads - 1 ; + + i )
entity - > pads [ i ] . flags = MEDIA_PAD_FL_SINK ;
entity - > pads [ num_pads - 1 ] . flags = MEDIA_PAD_FL_SOURCE ;
/* Initialize the media entity. */
2015-12-11 07:44:40 -02:00
return media_entity_pads_init ( & entity - > subdev . entity , num_pads ,
2015-08-06 09:25:57 -03:00
entity - > pads ) ;
2013-06-04 11:22:30 -03:00
}
void vsp1_entity_destroy ( struct vsp1_entity * entity )
{
2015-11-14 22:27:52 -02:00
if ( entity - > destroy )
entity - > destroy ( entity ) ;
2013-07-10 12:03:30 -03:00
if ( entity - > subdev . ctrl_handler )
v4l2_ctrl_handler_free ( entity - > subdev . ctrl_handler ) ;
2013-06-04 11:22:30 -03:00
media_entity_cleanup ( & entity - > subdev . entity ) ;
}