2013-06-04 11:22:30 -03:00
/*
* vsp1_rwpf . c - - R - Car VSP1 Read and Write Pixel Formatters
*
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 <media/v4l2-subdev.h>
# include "vsp1.h"
# include "vsp1_rwpf.h"
# include "vsp1_video.h"
# define RWPF_MIN_WIDTH 1
# define RWPF_MIN_HEIGHT 1
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Pad Operations
*/
int vsp1_rwpf_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
} ;
if ( code - > index > = ARRAY_SIZE ( codes ) )
return - EINVAL ;
code - > code = codes [ code - > index ] ;
return 0 ;
}
int vsp1_rwpf_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 )
{
struct vsp1_rwpf * rwpf = to_rwpf ( subdev ) ;
struct v4l2_mbus_framefmt * format ;
2015-03-04 01:47:58 -08:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , cfg , fse - > pad ,
fse - > which ) ;
2013-06-04 11:22:30 -03:00
if ( fse - > index | | fse - > code ! = format - > code )
return - EINVAL ;
if ( fse - > pad = = RWPF_PAD_SINK ) {
fse - > min_width = RWPF_MIN_WIDTH ;
fse - > max_width = rwpf - > max_width ;
fse - > min_height = RWPF_MIN_HEIGHT ;
fse - > max_height = rwpf - > max_height ;
} else {
/* The size on the source pad are fixed and always identical to
* the size on the sink pad .
*/
fse - > min_width = format - > width ;
fse - > max_width = format - > width ;
fse - > min_height = format - > height ;
fse - > max_height = format - > height ;
}
return 0 ;
}
2013-08-24 20:49:58 -03:00
static struct v4l2_rect *
2015-11-01 15:18:32 -02:00
vsp1_rwpf_get_crop ( struct vsp1_rwpf * rwpf , struct v4l2_subdev_pad_config * cfg ,
u32 which )
2013-08-24 20:49:58 -03:00
{
switch ( which ) {
case V4L2_SUBDEV_FORMAT_TRY :
2015-11-01 15:18:32 -02:00
return v4l2_subdev_get_try_crop ( & rwpf - > entity . subdev , cfg ,
RWPF_PAD_SINK ) ;
2013-08-24 20:49:58 -03:00
case V4L2_SUBDEV_FORMAT_ACTIVE :
return & rwpf - > crop ;
default :
return NULL ;
}
}
2015-11-01 15:18:32 -02:00
int vsp1_rwpf_get_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_rwpf * rwpf = to_rwpf ( subdev ) ;
2015-03-04 01:47:54 -08:00
fmt - > format = * vsp1_entity_get_pad_format ( & rwpf - > entity , cfg , fmt - > pad ,
2013-06-04 11:22:30 -03:00
fmt - > which ) ;
return 0 ;
}
2015-11-01 15:18:32 -02:00
int vsp1_rwpf_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_rwpf * rwpf = to_rwpf ( subdev ) ;
struct v4l2_mbus_framefmt * format ;
2013-08-24 20:49:58 -03:00
struct v4l2_rect * crop ;
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-03-04 01:47:54 -08:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , cfg , fmt - > pad ,
2013-06-04 11:22:30 -03:00
fmt - > which ) ;
if ( fmt - > pad = = RWPF_PAD_SOURCE ) {
/* The RWPF performs format conversion but can't scale, only the
* format code can be changed on the source pad .
*/
format - > code = fmt - > format . code ;
fmt - > format = * format ;
return 0 ;
}
format - > code = fmt - > format . code ;
format - > width = clamp_t ( unsigned int , fmt - > format . width ,
RWPF_MIN_WIDTH , rwpf - > max_width ) ;
format - > height = clamp_t ( unsigned int , fmt - > format . height ,
RWPF_MIN_HEIGHT , rwpf - > max_height ) ;
format - > field = V4L2_FIELD_NONE ;
format - > colorspace = V4L2_COLORSPACE_SRGB ;
fmt - > format = * format ;
2013-08-24 20:49:58 -03:00
/* Update the sink crop rectangle. */
2015-03-04 01:47:54 -08:00
crop = vsp1_rwpf_get_crop ( rwpf , cfg , fmt - > which ) ;
2013-08-24 20:49:58 -03:00
crop - > left = 0 ;
crop - > top = 0 ;
crop - > width = fmt - > format . width ;
crop - > height = fmt - > format . height ;
2013-06-04 11:22:30 -03:00
/* Propagate the format to the source pad. */
2015-03-04 01:47:54 -08:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , cfg , RWPF_PAD_SOURCE ,
2013-06-04 11:22:30 -03:00
fmt - > which ) ;
* format = fmt - > format ;
return 0 ;
}
2013-08-24 20:49:58 -03:00
int vsp1_rwpf_get_selection ( struct v4l2_subdev * subdev ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2013-08-24 20:49:58 -03:00
struct v4l2_subdev_selection * sel )
{
struct vsp1_rwpf * rwpf = to_rwpf ( subdev ) ;
struct v4l2_mbus_framefmt * format ;
/* Cropping is implemented on the sink pad. */
if ( sel - > pad ! = RWPF_PAD_SINK )
return - EINVAL ;
switch ( sel - > target ) {
case V4L2_SEL_TGT_CROP :
2015-03-04 01:47:54 -08:00
sel - > r = * vsp1_rwpf_get_crop ( rwpf , cfg , sel - > which ) ;
2013-08-24 20:49:58 -03:00
break ;
case V4L2_SEL_TGT_CROP_BOUNDS :
2015-03-04 01:47:54 -08:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , cfg ,
2013-08-24 20:49:58 -03:00
RWPF_PAD_SINK , sel - > which ) ;
sel - > r . left = 0 ;
sel - > r . top = 0 ;
sel - > r . width = format - > width ;
sel - > r . height = format - > height ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
int vsp1_rwpf_set_selection ( struct v4l2_subdev * subdev ,
2015-03-04 01:47:54 -08:00
struct v4l2_subdev_pad_config * cfg ,
2013-08-24 20:49:58 -03:00
struct v4l2_subdev_selection * sel )
{
struct vsp1_rwpf * rwpf = to_rwpf ( subdev ) ;
struct v4l2_mbus_framefmt * format ;
struct v4l2_rect * crop ;
/* Cropping is implemented on the sink pad. */
if ( sel - > pad ! = RWPF_PAD_SINK )
return - EINVAL ;
if ( sel - > target ! = V4L2_SEL_TGT_CROP )
return - EINVAL ;
/* Make sure the crop rectangle is entirely contained in the image. The
* WPF top and left offsets are limited to 255.
*/
2015-03-04 01:47:54 -08:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , cfg , RWPF_PAD_SINK ,
2013-08-24 20:49:58 -03:00
sel - > which ) ;
2015-05-28 09:59:39 -03:00
/* Restrict the crop rectangle coordinates to multiples of 2 to avoid
* shifting the color plane .
*/
if ( format - > code = = MEDIA_BUS_FMT_AYUV8_1X32 ) {
sel - > r . left = ALIGN ( sel - > r . left , 2 ) ;
sel - > r . top = ALIGN ( sel - > r . top , 2 ) ;
sel - > r . width = round_down ( sel - > r . width , 2 ) ;
sel - > r . height = round_down ( sel - > r . height , 2 ) ;
}
2013-08-24 20:49:58 -03:00
sel - > r . left = min_t ( unsigned int , sel - > r . left , format - > width - 2 ) ;
sel - > r . top = min_t ( unsigned int , sel - > r . top , format - > height - 2 ) ;
if ( rwpf - > entity . type = = VSP1_ENTITY_WPF ) {
sel - > r . left = min_t ( unsigned int , sel - > r . left , 255 ) ;
sel - > r . top = min_t ( unsigned int , sel - > r . top , 255 ) ;
}
sel - > r . width = min_t ( unsigned int , sel - > r . width ,
format - > width - sel - > r . left ) ;
sel - > r . height = min_t ( unsigned int , sel - > r . height ,
format - > height - sel - > r . top ) ;
2015-03-04 01:47:54 -08:00
crop = vsp1_rwpf_get_crop ( rwpf , cfg , sel - > which ) ;
2013-08-24 20:49:58 -03:00
* crop = sel - > r ;
/* Propagate the format to the source pad. */
2015-03-04 01:47:54 -08:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , cfg , RWPF_PAD_SOURCE ,
2013-08-24 20:49:58 -03:00
sel - > which ) ;
format - > width = crop - > width ;
format - > height = crop - > height ;
return 0 ;
}
2015-11-01 12:19:42 -02:00
/* -----------------------------------------------------------------------------
* Controls
*/
static int vsp1_rwpf_s_ctrl ( struct v4l2_ctrl * ctrl )
{
struct vsp1_rwpf * rwpf =
container_of ( ctrl - > handler , struct vsp1_rwpf , ctrls ) ;
switch ( ctrl - > id ) {
case V4L2_CID_ALPHA_COMPONENT :
rwpf - > alpha = ctrl - > val ;
break ;
}
return 0 ;
}
static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
. s_ctrl = vsp1_rwpf_s_ctrl ,
} ;
int vsp1_rwpf_init_ctrls ( struct vsp1_rwpf * rwpf )
{
rwpf - > alpha = 255 ;
v4l2_ctrl_handler_init ( & rwpf - > ctrls , 1 ) ;
v4l2_ctrl_new_std ( & rwpf - > ctrls , & vsp1_rwpf_ctrl_ops ,
V4L2_CID_ALPHA_COMPONENT , 0 , 255 , 1 , 255 ) ;
rwpf - > entity . subdev . ctrl_handler = & rwpf - > ctrls ;
return rwpf - > ctrls . error ;
}