staging: bcm2835_codec: Add support for the ISP as an M2M device
authorDave Stevenson <dave.stevenson@raspberrypi.org>
Wed, 13 Feb 2019 14:07:52 +0000 (14:07 +0000)
committerpopcornmix <popcornmix@gmail.com>
Mon, 13 May 2019 23:08:21 +0000 (00:08 +0100)
The MMAL ISP component can also use this same V4L2 wrapper to
provide a M2M format conversion and resizer.
Instantiate 3 V4L2 devices now, one for each of decode, encode,
and isp.
The ISP currently doesn't expose any controls via V4L2, but this
can be extended in the future.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c

index 7b8de26..f9fd5e8 100644 (file)
@@ -54,10 +54,26 @@ static int encode_video_nr = 11;
 module_param(encode_video_nr, int, 0644);
 MODULE_PARM_DESC(encode_video_nr, "encoder video device number");
 
+static int isp_video_nr = 12;
+module_param(isp_video_nr, int, 0644);
+MODULE_PARM_DESC(isp_video_nr, "isp video device number");
+
 static unsigned int debug;
 module_param(debug, uint, 0644);
 MODULE_PARM_DESC(debug, "activates debug info (0-3)");
 
+enum bcm2835_codec_role {
+       DECODE,
+       ENCODE,
+       ISP,
+};
+
+static const char * const components[] = {
+       "ril.video_decode",
+       "ril.video_encode",
+       "ril.isp",
+};
+
 #define MIN_W          32
 #define MIN_H          32
 #define MAX_W          1920
@@ -373,7 +389,7 @@ struct bcm2835_codec_dev {
        atomic_t                num_inst;
 
        /* allocated mmal instance and components */
-       bool                    decode;  /* Is this instance a decoder? */
+       enum bcm2835_codec_role role;
        /* The list of formats supported on input and output queues. */
        struct bcm2835_codec_fmt_list   supported_fmts[2];
 
@@ -558,7 +574,7 @@ static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx,
                port->es.video.frame_rate.den = 1;
        } else {
                /* Compressed format - leave resolution as 0 for decode */
-               if (ctx->dev->decode) {
+               if (ctx->dev->role == DECODE) {
                        port->es.video.width = 0;
                        port->es.video.height = 0;
                        port->es.video.crop.width = 0;
@@ -1089,7 +1105,8 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
        v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
                 q_data->bytesperline, q_data->sizeimage);
 
-       if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
+       if (ctx->dev->role == DECODE &&
+           q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
            f->fmt.pix.width && f->fmt.pix.height) {
                /*
                 * On the decoder, if provided with a resolution on the input
@@ -1188,7 +1205,8 @@ static int vidioc_g_selection(struct file *file, void *priv,
        bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
                                                                true : false;
 
-       if (capture_queue ^ ctx->dev->decode)
+       if ((ctx->dev->role == DECODE && !capture_queue) ||
+           (ctx->dev->role == ENCODE && capture_queue))
                /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
                return -EINVAL;
 
@@ -1196,7 +1214,8 @@ static int vidioc_g_selection(struct file *file, void *priv,
        if (!q_data)
                return -EINVAL;
 
-       if (ctx->dev->decode) {
+       switch (ctx->dev->role) {
+       case DECODE:
                switch (s->target) {
                case V4L2_SEL_TGT_COMPOSE_DEFAULT:
                case V4L2_SEL_TGT_COMPOSE:
@@ -1214,7 +1233,8 @@ static int vidioc_g_selection(struct file *file, void *priv,
                default:
                        return -EINVAL;
                }
-       } else {
+               break;
+       case ENCODE:
                switch (s->target) {
                case V4L2_SEL_TGT_CROP_DEFAULT:
                case V4L2_SEL_TGT_CROP_BOUNDS:
@@ -1232,6 +1252,9 @@ static int vidioc_g_selection(struct file *file, void *priv,
                default:
                        return -EINVAL;
                }
+               break;
+       case ISP:
+               break;
        }
 
        return 0;
@@ -1249,7 +1272,8 @@ static int vidioc_s_selection(struct file *file, void *priv,
                 __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
                 s->r.width, s->r.height);
 
-       if (capture_queue ^ ctx->dev->decode)
+       if ((ctx->dev->role == DECODE && !capture_queue) ||
+           (ctx->dev->role == ENCODE && capture_queue))
                /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
                return -EINVAL;
 
@@ -1257,7 +1281,8 @@ static int vidioc_s_selection(struct file *file, void *priv,
        if (!q_data)
                return -EINVAL;
 
-       if (ctx->dev->decode) {
+       switch (ctx->dev->role) {
+       case DECODE:
                switch (s->target) {
                case V4L2_SEL_TGT_COMPOSE:
                        /* Accept cropped image */
@@ -1272,7 +1297,8 @@ static int vidioc_s_selection(struct file *file, void *priv,
                default:
                        return -EINVAL;
                }
-       } else {
+               break;
+       case ENCODE:
                switch (s->target) {
                case V4L2_SEL_TGT_CROP:
                        /* Only support crop from (0,0) */
@@ -1287,6 +1313,9 @@ static int vidioc_s_selection(struct file *file, void *priv,
                default:
                        return -EINVAL;
                }
+               break;
+       case ISP:
+               break;
        }
 
        return 0;
@@ -1490,7 +1519,7 @@ static int vidioc_try_decoder_cmd(struct file *file, void *priv,
 {
        struct bcm2835_codec_ctx *ctx = file2ctx(file);
 
-       if (!ctx->dev->decode)
+       if (ctx->dev->role != DECODE)
                return -EINVAL;
 
        switch (cmd->cmd) {
@@ -1564,7 +1593,7 @@ static int vidioc_try_encoder_cmd(struct file *file, void *priv,
 {
        struct bcm2835_codec_ctx *ctx = file2ctx(file);
 
-       if (ctx->dev->decode)
+       if (ctx->dev->role != ENCODE)
                return -EINVAL;
 
        switch (cmd->cmd) {
@@ -1697,12 +1726,11 @@ static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx)
        unsigned int enable = 1;
        int ret;
 
-       ret = vchiq_mmal_component_init(dev->instance, dev->decode ?
-                                       "ril.video_decode" : "ril.video_encode",
+       ret = vchiq_mmal_component_init(dev->instance, components[dev->role],
                                        &ctx->component);
        if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n",
-                        __func__, dev->decode ? "decode" : "encode");
+               v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n",
+                        __func__, components[dev->role]);
                return -ENOMEM;
        }
 
@@ -1729,13 +1757,7 @@ static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx)
        if (ret < 0)
                goto destroy_component;
 
-       if (dev->decode) {
-               if (ctx->q_data[V4L2_M2M_DST].sizeimage <
-                       ctx->component->output[0].minimum_buffer.size)
-                       v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
-                                ctx->q_data[V4L2_M2M_DST].sizeimage,
-                                ctx->component->output[0].minimum_buffer.size);
-       } else {
+       if (dev->role == ENCODE) {
                if (ctx->q_data[V4L2_M2M_SRC].sizeimage <
                        ctx->component->output[0].minimum_buffer.size)
                        v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
@@ -1744,6 +1766,12 @@ static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx)
 
                /* Now we have a component we can set all the ctrls */
                bcm2835_codec_set_ctrls(ctx);
+       } else {
+               if (ctx->q_data[V4L2_M2M_DST].sizeimage <
+                       ctx->component->output[0].minimum_buffer.size)
+                       v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
+                                ctx->q_data[V4L2_M2M_DST].sizeimage,
+                                ctx->component->output[0].minimum_buffer.size);
        }
 
        return 0;
@@ -2090,8 +2118,6 @@ static int bcm2835_codec_open(struct file *file)
        struct v4l2_ctrl_handler *hdl;
        int rc = 0;
 
-       v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n",
-                dev->decode ? "decode" : "encode");
        if (mutex_lock_interruptible(&dev->dev_mutex)) {
                v4l2_err(&dev->v4l2_dev, "Mutex fail\n");
                return -ERESTARTSYS;
@@ -2104,7 +2130,8 @@ static int bcm2835_codec_open(struct file *file)
 
        ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false);
        ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true);
-       if (dev->decode) {
+       switch (dev->role) {
+       case DECODE:
                /*
                 * Input width and height are irrelevant as they will be defined
                 * by the bitstream not the format. Required by V4L2 though.
@@ -2126,7 +2153,8 @@ static int bcm2835_codec_open(struct file *file)
                        get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
                                      ctx->q_data[V4L2_M2M_DST].height,
                                      ctx->q_data[V4L2_M2M_DST].fmt);
-       } else {
+               break;
+       case ENCODE:
                ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
                ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
                ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT;
@@ -2144,6 +2172,9 @@ static int bcm2835_codec_open(struct file *file)
                ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT;
                ctx->q_data[V4L2_M2M_DST].sizeimage =
                                                DEF_COMP_BUF_SIZE_720P_OR_LESS;
+               break;
+       case ISP:
+               break;
        }
 
        ctx->colorspace = V4L2_COLORSPACE_REC709;
@@ -2154,7 +2185,7 @@ static int bcm2835_codec_open(struct file *file)
        file->private_data = &ctx->fh;
        ctx->dev = dev;
        hdl = &ctx->hdl;
-       if (!dev->decode) {
+       if (dev->role == ENCODE) {
                /* Encode controls */
                v4l2_ctrl_handler_init(hdl, 6);
 
@@ -2303,14 +2334,11 @@ static int bcm2835_codec_get_supported_fmts(struct bcm2835_codec_dev *dev)
        unsigned int i, j, num_encodings;
        int ret;
 
-       ret = vchiq_mmal_component_init(dev->instance,
-                                       dev->decode ?
-                                               "ril.video_decode" :
-                                               "ril.video_encode",
+       ret = vchiq_mmal_component_init(dev->instance, components[dev->role],
                                        &component);
        if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n",
-                        __func__);
+               v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n",
+                        __func__, components[dev->role]);
                return -ENOMEM;
        }
 
@@ -2406,12 +2434,13 @@ destroy_component:
 
 static int bcm2835_codec_create(struct platform_device *pdev,
                                struct bcm2835_codec_dev **new_dev,
-                               bool decode)
+                               enum bcm2835_codec_role role)
 {
        struct bcm2835_codec_dev *dev;
        struct video_device *vfd;
        int video_nr;
        int ret;
+       const static char *roles[] = {"decode", "encode", "isp"};
 
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
@@ -2419,7 +2448,7 @@ static int bcm2835_codec_create(struct platform_device *pdev,
 
        dev->pdev = pdev;
 
-       dev->decode = decode;
+       dev->role = role;
 
        ret = vchiq_mmal_init(&dev->instance);
        if (ret)
@@ -2441,14 +2470,27 @@ static int bcm2835_codec_create(struct platform_device *pdev,
        vfd->lock = &dev->dev_mutex;
        vfd->v4l2_dev = &dev->v4l2_dev;
 
-       if (dev->decode) {
+       switch (role) {
+       case DECODE:
                v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
                v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
                video_nr = decode_video_nr;
-       } else {
+               break;
+       case ENCODE:
                v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
                v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
                video_nr = encode_video_nr;
+               break;
+       case ISP:
+               v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
+               v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
+               v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
+               v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
+               video_nr = isp_video_nr;
+               break;
+       default:
+               ret = -EINVAL;
+               goto unreg_dev;
        }
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
@@ -2473,7 +2515,7 @@ static int bcm2835_codec_create(struct platform_device *pdev,
        }
 
        v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
-                 dev->decode ? "decode" : "encode");
+                 roles[role]);
        return 0;
 
 err_m2m:
@@ -2509,11 +2551,15 @@ static int bcm2835_codec_probe(struct platform_device *pdev)
        if (!drv)
                return -ENOMEM;
 
-       ret = bcm2835_codec_create(pdev, &drv->encode, false);
+       ret = bcm2835_codec_create(pdev, &drv->decode, DECODE);
        if (ret)
                goto out;
 
-       ret = bcm2835_codec_create(pdev, &drv->decode, true);
+       ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE);
+       if (ret)
+               goto out;
+
+       ret = bcm2835_codec_create(pdev, &drv->isp, ISP);
        if (ret)
                goto out;
 
@@ -2526,6 +2572,10 @@ out:
                bcm2835_codec_destroy(drv->encode);
                drv->encode = NULL;
        }
+       if (drv->decode) {
+               bcm2835_codec_destroy(drv->decode);
+               drv->decode = NULL;
+       }
        return ret;
 }
 
@@ -2533,6 +2583,8 @@ static int bcm2835_codec_remove(struct platform_device *pdev)
 {
        struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
 
+       bcm2835_codec_destroy(drv->isp);
+
        bcm2835_codec_destroy(drv->encode);
 
        bcm2835_codec_destroy(drv->decode);