diff options
Diffstat (limited to 'drivers/media/platform/vsp1/vsp1_lut.c')
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_lut.c | 172 |
1 files changed, 67 insertions, 105 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 4b89095e7b5f..aa09e59f0ab8 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -18,6 +18,7 @@ #include <media/v4l2-subdev.h> #include "vsp1.h" +#include "vsp1_dl.h" #include "vsp1_lut.h" #define LUT_MIN_SIZE 4U @@ -27,19 +28,35 @@ * Device Access */ -static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data) +static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl, + u32 reg, u32 data) { - vsp1_write(lut->entity.vsp1, reg, data); + vsp1_dl_list_write(dl, reg, data); } /* ----------------------------------------------------------------------------- * V4L2 Subdevice Core Operations */ -static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config) +static int lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config) { - memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut, - sizeof(config->lut)); + struct vsp1_dl_body *dlb; + unsigned int i; + + dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, ARRAY_SIZE(config->lut)); + if (!dlb) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(config->lut); ++i) + vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i, + config->lut[i]); + + mutex_lock(&lut->lock); + swap(lut->lut, dlb); + mutex_unlock(&lut->lock); + + vsp1_dl_fragment_free(dlb); + return 0; } static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) @@ -48,8 +65,7 @@ static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_VSP1_LUT_CONFIG: - lut_configure(lut, arg); - return 0; + return lut_set_table(lut, arg); default: return -ENOIOCTLCMD; @@ -57,22 +73,6 @@ static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) } /* ----------------------------------------------------------------------------- - * V4L2 Subdevice Video Operations - */ - -static int lut_s_stream(struct v4l2_subdev *subdev, int enable) -{ - struct vsp1_lut *lut = to_lut(subdev); - - if (!enable) - return 0; - - vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); - - return 0; -} - -/* ----------------------------------------------------------------------------- * V4L2 Subdevice Pad Operations */ @@ -85,85 +85,39 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, MEDIA_BUS_FMT_AHSV8888_1X32, MEDIA_BUS_FMT_AYUV8_1X32, }; - struct vsp1_lut *lut = to_lut(subdev); - struct v4l2_mbus_framefmt *format; - - if (code->pad == LUT_PAD_SINK) { - if (code->index >= ARRAY_SIZE(codes)) - return -EINVAL; - - code->code = codes[code->index]; - } else { - /* The LUT can't perform format conversion, the sink format is - * always identical to the source format. - */ - if (code->index) - return -EINVAL; - - format = vsp1_entity_get_pad_format(&lut->entity, cfg, - LUT_PAD_SINK, code->which); - code->code = format->code; - } - return 0; + return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, + ARRAY_SIZE(codes)); } static int lut_enum_frame_size(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { - struct vsp1_lut *lut = to_lut(subdev); - struct v4l2_mbus_framefmt *format; - - format = vsp1_entity_get_pad_format(&lut->entity, cfg, - fse->pad, fse->which); - - if (fse->index || fse->code != format->code) - return -EINVAL; - - if (fse->pad == LUT_PAD_SINK) { - fse->min_width = LUT_MIN_SIZE; - fse->max_width = LUT_MAX_SIZE; - fse->min_height = LUT_MIN_SIZE; - fse->max_height = LUT_MAX_SIZE; - } 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; -} - -static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vsp1_lut *lut = to_lut(subdev); - - fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, - fmt->which); - - return 0; + return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE, + LUT_MIN_SIZE, LUT_MAX_SIZE, + LUT_MAX_SIZE); } -static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, +static int lut_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_lut *lut = to_lut(subdev); + struct v4l2_subdev_pad_config *config; struct v4l2_mbus_framefmt *format; + config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which); + if (!config) + return -EINVAL; + /* Default to YUV if the requested format is not supported. */ if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 && fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; - format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, - fmt->which); + format = vsp1_entity_get_pad_format(&lut->entity, config, fmt->pad); if (fmt->pad == LUT_PAD_SOURCE) { /* The LUT output format can't be modified. */ @@ -171,6 +125,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con return 0; } + format->code = fmt->format.code; format->width = clamp_t(unsigned int, fmt->format.width, LUT_MIN_SIZE, LUT_MAX_SIZE); format->height = clamp_t(unsigned int, fmt->format.height, @@ -181,8 +136,8 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con fmt->format = *format; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE, - fmt->which); + format = vsp1_entity_get_pad_format(&lut->entity, config, + LUT_PAD_SOURCE); *format = fmt->format; return 0; @@ -196,30 +151,49 @@ static struct v4l2_subdev_core_ops lut_core_ops = { .ioctl = lut_ioctl, }; -static struct v4l2_subdev_video_ops lut_video_ops = { - .s_stream = lut_s_stream, -}; - static struct v4l2_subdev_pad_ops lut_pad_ops = { + .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = lut_enum_mbus_code, .enum_frame_size = lut_enum_frame_size, - .get_fmt = lut_get_format, + .get_fmt = vsp1_subdev_get_pad_format, .set_fmt = lut_set_format, }; static struct v4l2_subdev_ops lut_ops = { .core = &lut_core_ops, - .video = &lut_video_ops, .pad = &lut_pad_ops, }; /* ----------------------------------------------------------------------------- + * VSP1 Entity Operations + */ + +static void lut_configure(struct vsp1_entity *entity, + struct vsp1_pipeline *pipe, + struct vsp1_dl_list *dl) +{ + struct vsp1_lut *lut = to_lut(&entity->subdev); + + vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); + + mutex_lock(&lut->lock); + if (lut->lut) { + vsp1_dl_list_add_fragment(dl, lut->lut); + lut->lut = NULL; + } + mutex_unlock(&lut->lock); +} + +static const struct vsp1_entity_operations lut_entity_ops = { + .configure = lut_configure, +}; + +/* ----------------------------------------------------------------------------- * Initialization and Cleanup */ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) { - struct v4l2_subdev *subdev; struct vsp1_lut *lut; int ret; @@ -227,24 +201,12 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) if (lut == NULL) return ERR_PTR(-ENOMEM); + lut->entity.ops = &lut_entity_ops; lut->entity.type = VSP1_ENTITY_LUT; - ret = vsp1_entity_init(vsp1, &lut->entity, 2); + ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops); if (ret < 0) return ERR_PTR(ret); - /* Initialize the V4L2 subdev. */ - subdev = &lut->entity.subdev; - v4l2_subdev_init(subdev, &lut_ops); - - subdev->entity.ops = &vsp1->media_ops; - subdev->internal_ops = &vsp1_subdev_internal_ops; - snprintf(subdev->name, sizeof(subdev->name), "%s lut", - dev_name(vsp1->dev)); - v4l2_set_subdevdata(subdev, lut); - subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - vsp1_entity_init_formats(subdev, NULL); - return lut; } |