To prepare for the removal of the vsp1_entity.state field, pass the state to all entity operations that needs to access it, instead of accessing the state from the entity inside the operation handlers. This lowers the number of accesses to the field. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
176 lines
4.4 KiB
C
176 lines
4.4 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* vsp1_hsit.c -- R-Car VSP1 Hue Saturation value (Inverse) Transform
|
|
*
|
|
* Copyright (C) 2013 Renesas Corporation
|
|
*
|
|
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
|
*/
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/gfp.h>
|
|
|
|
#include <media/v4l2-subdev.h>
|
|
|
|
#include "vsp1.h"
|
|
#include "vsp1_dl.h"
|
|
#include "vsp1_hsit.h"
|
|
|
|
#define HSIT_MIN_SIZE 4U
|
|
#define HSIT_MAX_SIZE 8190U
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Device Access
|
|
*/
|
|
|
|
static inline void vsp1_hsit_write(struct vsp1_hsit *hsit,
|
|
struct vsp1_dl_body *dlb, u32 reg, u32 data)
|
|
{
|
|
vsp1_dl_body_write(dlb, reg, data);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* V4L2 Subdevice Operations
|
|
*/
|
|
|
|
static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
|
|
struct v4l2_subdev_state *sd_state,
|
|
struct v4l2_subdev_mbus_code_enum *code)
|
|
{
|
|
struct vsp1_hsit *hsit = to_hsit(subdev);
|
|
|
|
if (code->index > 0)
|
|
return -EINVAL;
|
|
|
|
if ((code->pad == HSIT_PAD_SINK && !hsit->inverse) |
|
|
(code->pad == HSIT_PAD_SOURCE && hsit->inverse))
|
|
code->code = MEDIA_BUS_FMT_ARGB8888_1X32;
|
|
else
|
|
code->code = MEDIA_BUS_FMT_AHSV8888_1X32;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
|
|
struct v4l2_subdev_state *sd_state,
|
|
struct v4l2_subdev_frame_size_enum *fse)
|
|
{
|
|
return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
|
|
HSIT_MIN_SIZE,
|
|
HSIT_MIN_SIZE, HSIT_MAX_SIZE,
|
|
HSIT_MAX_SIZE);
|
|
}
|
|
|
|
static int hsit_set_format(struct v4l2_subdev *subdev,
|
|
struct v4l2_subdev_state *sd_state,
|
|
struct v4l2_subdev_format *fmt)
|
|
{
|
|
struct vsp1_hsit *hsit = to_hsit(subdev);
|
|
struct v4l2_subdev_state *state;
|
|
struct v4l2_mbus_framefmt *format;
|
|
int ret = 0;
|
|
|
|
mutex_lock(&hsit->entity.lock);
|
|
|
|
state = vsp1_entity_get_state(&hsit->entity, sd_state, fmt->which);
|
|
if (!state) {
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
format = v4l2_subdev_state_get_format(state, fmt->pad);
|
|
|
|
if (fmt->pad == HSIT_PAD_SOURCE) {
|
|
/*
|
|
* The HST and HSI output format code and resolution can't be
|
|
* modified.
|
|
*/
|
|
fmt->format = *format;
|
|
goto done;
|
|
}
|
|
|
|
format->code = hsit->inverse ? MEDIA_BUS_FMT_AHSV8888_1X32
|
|
: MEDIA_BUS_FMT_ARGB8888_1X32;
|
|
format->width = clamp_t(unsigned int, fmt->format.width,
|
|
HSIT_MIN_SIZE, HSIT_MAX_SIZE);
|
|
format->height = clamp_t(unsigned int, fmt->format.height,
|
|
HSIT_MIN_SIZE, HSIT_MAX_SIZE);
|
|
format->field = V4L2_FIELD_NONE;
|
|
format->colorspace = V4L2_COLORSPACE_SRGB;
|
|
|
|
fmt->format = *format;
|
|
|
|
/* Propagate the format to the source pad. */
|
|
format = v4l2_subdev_state_get_format(state, HSIT_PAD_SOURCE);
|
|
*format = fmt->format;
|
|
format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
|
|
: MEDIA_BUS_FMT_AHSV8888_1X32;
|
|
|
|
done:
|
|
mutex_unlock(&hsit->entity.lock);
|
|
return ret;
|
|
}
|
|
|
|
static const struct v4l2_subdev_pad_ops hsit_pad_ops = {
|
|
.enum_mbus_code = hsit_enum_mbus_code,
|
|
.enum_frame_size = hsit_enum_frame_size,
|
|
.get_fmt = vsp1_subdev_get_pad_format,
|
|
.set_fmt = hsit_set_format,
|
|
};
|
|
|
|
static const struct v4l2_subdev_ops hsit_ops = {
|
|
.pad = &hsit_pad_ops,
|
|
};
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* VSP1 Entity Operations
|
|
*/
|
|
|
|
static void hsit_configure_stream(struct vsp1_entity *entity,
|
|
struct v4l2_subdev_state *state,
|
|
struct vsp1_pipeline *pipe,
|
|
struct vsp1_dl_list *dl,
|
|
struct vsp1_dl_body *dlb)
|
|
{
|
|
struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
|
|
|
|
if (hsit->inverse)
|
|
vsp1_hsit_write(hsit, dlb, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
|
|
else
|
|
vsp1_hsit_write(hsit, dlb, VI6_HST_CTRL, VI6_HST_CTRL_EN);
|
|
}
|
|
|
|
static const struct vsp1_entity_operations hsit_entity_ops = {
|
|
.configure_stream = hsit_configure_stream,
|
|
};
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Initialization and Cleanup
|
|
*/
|
|
|
|
struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
|
|
{
|
|
struct vsp1_hsit *hsit;
|
|
int ret;
|
|
|
|
hsit = devm_kzalloc(vsp1->dev, sizeof(*hsit), GFP_KERNEL);
|
|
if (hsit == NULL)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
hsit->inverse = inverse;
|
|
|
|
hsit->entity.ops = &hsit_entity_ops;
|
|
|
|
if (inverse)
|
|
hsit->entity.type = VSP1_ENTITY_HSI;
|
|
else
|
|
hsit->entity.type = VSP1_ENTITY_HST;
|
|
|
|
ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst",
|
|
2, &hsit_ops,
|
|
MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV);
|
|
if (ret < 0)
|
|
return ERR_PTR(ret);
|
|
|
|
return hsit;
|
|
}
|