staging: bcm2835_codec: Query supported formats from the component
authorDave Stevenson <dave.stevenson@raspberrypi.org>
Wed, 13 Feb 2019 13:44:00 +0000 (13:44 +0000)
committerpopcornmix <popcornmix@gmail.com>
Mon, 13 May 2019 23:08:21 +0000 (00:08 +0100)
The driver was previously working with hard coded tables of
which video formats were supported by each component.
The components advertise this information via a MMAL parameter,
so retrieve the information from there during probe, and store
in the state structure for that device.

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

index c26760f..7b8de26 100644 (file)
@@ -88,17 +88,12 @@ struct bcm2835_codec_fmt {
        int     bytesperline_align;
        u32     flags;
        u32     mmal_fmt;
-       bool    decode_only;
-       bool    encode_only;
        int     size_multiplier_x2;
 };
 
-/* Supported raw pixel formats. Those supported for both encode and decode
- * must come first, with those only supported for decode coming after (there
- * are no formats supported for encode only).
- */
-static struct bcm2835_codec_fmt raw_formats[] = {
+static const struct bcm2835_codec_fmt supported_formats[] = {
        {
+               /* YUV formats */
                .fourcc                 = V4L2_PIX_FMT_YUV420,
                .depth                  = 8,
                .bytesperline_align     = 32,
@@ -139,7 +134,6 @@ static struct bcm2835_codec_fmt raw_formats[] = {
                .bytesperline_align     = 32,
                .flags                  = 0,
                .mmal_fmt               = MMAL_ENCODING_YUYV,
-               .encode_only            = true,
                .size_multiplier_x2     = 2,
        }, {
                .fourcc                 = V4L2_PIX_FMT_UYVY,
@@ -147,7 +141,6 @@ static struct bcm2835_codec_fmt raw_formats[] = {
                .bytesperline_align     = 32,
                .flags                  = 0,
                .mmal_fmt               = MMAL_ENCODING_UYVY,
-               .encode_only            = true,
                .size_multiplier_x2     = 2,
        }, {
                .fourcc                 = V4L2_PIX_FMT_YVYU,
@@ -155,7 +148,6 @@ static struct bcm2835_codec_fmt raw_formats[] = {
                .bytesperline_align     = 32,
                .flags                  = 0,
                .mmal_fmt               = MMAL_ENCODING_YVYU,
-               .encode_only            = true,
                .size_multiplier_x2     = 2,
        }, {
                .fourcc                 = V4L2_PIX_FMT_VYUY,
@@ -163,15 +155,14 @@ static struct bcm2835_codec_fmt raw_formats[] = {
                .bytesperline_align     = 32,
                .flags                  = 0,
                .mmal_fmt               = MMAL_ENCODING_VYUY,
-               .encode_only            = true,
                .size_multiplier_x2     = 2,
        }, {
+               /* RGB formats */
                .fourcc                 = V4L2_PIX_FMT_RGB24,
                .depth                  = 24,
                .bytesperline_align     = 32,
                .flags                  = 0,
                .mmal_fmt               = MMAL_ENCODING_RGB24,
-               .encode_only            = true,
                .size_multiplier_x2     = 2,
        }, {
                .fourcc                 = V4L2_PIX_FMT_BGR24,
@@ -179,7 +170,6 @@ static struct bcm2835_codec_fmt raw_formats[] = {
                .bytesperline_align     = 32,
                .flags                  = 0,
                .mmal_fmt               = MMAL_ENCODING_BGR24,
-               .encode_only            = true,
                .size_multiplier_x2     = 2,
        }, {
                .fourcc                 = V4L2_PIX_FMT_BGR32,
@@ -187,17 +177,126 @@ static struct bcm2835_codec_fmt raw_formats[] = {
                .bytesperline_align     = 32,
                .flags                  = 0,
                .mmal_fmt               = MMAL_ENCODING_BGRA,
-               .encode_only            = true,
                .size_multiplier_x2     = 2,
-       },
-};
-
-/* Supported encoded formats. Those supported for both encode and decode
- * must come first, with those only supported for decode coming after (there
- * are no formats supported for encode only).
- */
-static struct bcm2835_codec_fmt encoded_formats[] = {
-       {
+       }, {
+               /* Bayer formats */
+               /* 8 bit */
+               .fourcc                 = V4L2_PIX_FMT_SRGGB8,
+               .depth                  = 8,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SRGGB8,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SBGGR8,
+               .depth                  = 8,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SBGGR8,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SGRBG8,
+               .depth                  = 8,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SGRBG8,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SGBRG8,
+               .depth                  = 8,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SGBRG8,
+               .size_multiplier_x2     = 2,
+       }, {
+               /* 10 bit */
+               .fourcc                 = V4L2_PIX_FMT_SRGGB10P,
+               .depth                  = 10,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SRGGB10P,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SBGGR10P,
+               .depth                  = 10,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SBGGR10P,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SGRBG10P,
+               .depth                  = 10,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SGRBG10P,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SGBRG10P,
+               .depth                  = 10,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SGBRG10P,
+               .size_multiplier_x2     = 2,
+       }, {
+               /* 12 bit */
+               .fourcc                 = V4L2_PIX_FMT_SRGGB12P,
+               .depth                  = 12,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SRGGB12P,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SBGGR12P,
+               .depth                  = 12,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SBGGR12P,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SGRBG12P,
+               .depth                  = 12,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SGRBG12P,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SGBRG12P,
+               .depth                  = 12,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SGBRG12P,
+               .size_multiplier_x2     = 2,
+       }, {
+               /* 16 bit */
+               .fourcc                 = V4L2_PIX_FMT_SRGGB16,
+               .depth                  = 16,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SRGGB16,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SBGGR16,
+               .depth                  = 16,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SBGGR16,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SGRBG16,
+               .depth                  = 16,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SGRBG16,
+               .size_multiplier_x2     = 2,
+       }, {
+               .fourcc                 = V4L2_PIX_FMT_SGBRG16,
+               .depth                  = 16,
+               .bytesperline_align     = 32,
+               .flags                  = 0,
+               .mmal_fmt               = MMAL_ENCODING_BAYER_SGBRG16,
+               .size_multiplier_x2     = 2,
+       }, {
+               /* Compressed formats */
                .fourcc                 = V4L2_PIX_FMT_H264,
                .depth                  = 0,
                .flags                  = V4L2_FMT_FLAG_COMPRESSED,
@@ -212,30 +311,22 @@ static struct bcm2835_codec_fmt encoded_formats[] = {
                .depth                  = 0,
                .flags                  = V4L2_FMT_FLAG_COMPRESSED,
                .mmal_fmt               = MMAL_ENCODING_MP4V,
-               .decode_only            = true,
        }, {
                .fourcc                 = V4L2_PIX_FMT_H263,
                .depth                  = 0,
                .flags                  = V4L2_FMT_FLAG_COMPRESSED,
                .mmal_fmt               = MMAL_ENCODING_H263,
-               .decode_only            = true,
        }, {
                .fourcc                 = V4L2_PIX_FMT_MPEG2,
                .depth                  = 0,
                .flags                  = V4L2_FMT_FLAG_COMPRESSED,
                .mmal_fmt               = MMAL_ENCODING_MP2V,
-               .decode_only            = true,
        }, {
                .fourcc                 = V4L2_PIX_FMT_VP8,
                .depth                  = 0,
                .flags                  = V4L2_FMT_FLAG_COMPRESSED,
                .mmal_fmt               = MMAL_ENCODING_VP8,
-               .decode_only            = true,
        },
-       /*
-        * This list couold include VP6 and Theorafor decode, but V4L2 doesn't
-        * support them.
-        */
 };
 
 struct bcm2835_codec_fmt_list {
@@ -243,19 +334,6 @@ struct bcm2835_codec_fmt_list {
        unsigned int num_entries;
 };
 
-#define RAW_LIST       0
-#define ENCODED_LIST   1
-
-struct bcm2835_codec_fmt_list formats[] = {
-       {
-               .list = raw_formats,
-               .num_entries = ARRAY_SIZE(raw_formats),
-       }, {
-               .list = encoded_formats,
-               .num_entries = ARRAY_SIZE(encoded_formats),
-       },
-};
-
 struct m2m_mmal_buffer {
        struct v4l2_m2m_buffer  m2m;
        struct mmal_buffer      mmal;
@@ -284,52 +362,6 @@ struct bcm2835_codec_q_data {
        bool                    eos_buffer_in_use;      /* debug only */
 };
 
-enum {
-       V4L2_M2M_SRC = 0,
-       V4L2_M2M_DST = 1,
-};
-
-static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode,
-                                                            bool capture)
-{
-       return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST];
-}
-
-static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture)
-{
-       return &get_format_list(decode, capture)->list[0];
-}
-
-static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode,
-                                            bool capture)
-{
-       struct bcm2835_codec_fmt *fmt;
-       unsigned int k;
-       struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
-
-       for (k = 0; k < fmts->num_entries; k++) {
-               fmt = &fmts->list[k];
-               if (fmt->fourcc == f->fmt.pix.pixelformat)
-                       break;
-       }
-
-       /*
-        * Some compressed formats are only supported for decoding, not
-        * encoding.
-        */
-       if (!decode && fmts->list[k].decode_only)
-               return NULL;
-
-       /* Some pixel formats are only supported for encoding, not decoding. */
-       if (decode && fmts->list[k].encode_only)
-               return NULL;
-
-       if (k == fmts->num_entries)
-               return NULL;
-
-       return &fmts->list[k];
-}
-
 struct bcm2835_codec_dev {
        struct platform_device *pdev;
 
@@ -342,6 +374,9 @@ struct bcm2835_codec_dev {
 
        /* allocated mmal instance and components */
        bool                    decode;  /* Is this instance a decoder? */
+       /* The list of formats supported on input and output queues. */
+       struct bcm2835_codec_fmt_list   supported_fmts[2];
+
        struct vchiq_mmal_instance      *instance;
 
        struct v4l2_m2m_dev     *m2m_dev;
@@ -374,8 +409,59 @@ struct bcm2835_codec_ctx {
 struct bcm2835_codec_driver {
        struct bcm2835_codec_dev *encode;
        struct bcm2835_codec_dev *decode;
+       struct bcm2835_codec_dev *isp;
+};
+
+enum {
+       V4L2_M2M_SRC = 0,
+       V4L2_M2M_DST = 1,
 };
 
+static const struct bcm2835_codec_fmt *get_fmt(u32 mmal_fmt)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
+               if (supported_formats[i].mmal_fmt == mmal_fmt)
+                       return &supported_formats[i];
+       }
+       return NULL;
+}
+
+static inline
+struct bcm2835_codec_fmt_list *get_format_list(struct bcm2835_codec_dev *dev,
+                                              bool capture)
+{
+       return &dev->supported_fmts[capture ? 1 : 0];
+}
+
+static
+struct bcm2835_codec_fmt *get_default_format(struct bcm2835_codec_dev *dev,
+                                            bool capture)
+{
+       return &dev->supported_fmts[capture ? 1 : 0].list[0];
+}
+
+static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
+                                            struct bcm2835_codec_dev *dev,
+                                            bool capture)
+{
+       struct bcm2835_codec_fmt *fmt;
+       unsigned int k;
+       struct bcm2835_codec_fmt_list *fmts =
+                                       &dev->supported_fmts[capture ? 1 : 0];
+
+       for (k = 0; k < fmts->num_entries; k++) {
+               fmt = &fmts->list[k];
+               if (fmt->fourcc == f->fmt.pix.pixelformat)
+                       break;
+       }
+       if (k == fmts->num_entries)
+               return NULL;
+
+       return &fmts->list[k];
+}
+
 static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
 {
        return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
@@ -456,7 +542,6 @@ static inline unsigned int get_bytesperline(int width,
 }
 
 static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx,
-                                  bool decode,
                                   struct bcm2835_codec_q_data *q_data,
                                   struct vchiq_mmal_port *port)
 {
@@ -473,7 +558,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 (decode) {
+               if (ctx->dev->decode) {
                        port->es.video.width = 0;
                        port->es.video.height = 0;
                        port->es.video.crop.width = 0;
@@ -802,22 +887,15 @@ static int vidioc_querycap(struct file *file, void *priv,
        return 0;
 }
 
-static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture)
+static int enum_fmt(struct v4l2_fmtdesc *f, struct bcm2835_codec_ctx *ctx,
+                   bool capture)
 {
        struct bcm2835_codec_fmt *fmt;
-       struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
+       struct bcm2835_codec_fmt_list *fmts =
+                                       get_format_list(ctx->dev, capture);
 
        if (f->index < fmts->num_entries) {
                /* Format found */
-               /* Check format isn't a decode only format when encoding */
-               if (!decode &&
-                   fmts->list[f->index].decode_only)
-                       return -EINVAL;
-               /* Check format isn't a decode only format when encoding */
-               if (decode &&
-                   fmts->list[f->index].encode_only)
-                       return -EINVAL;
-
                fmt = &fmts->list[f->index];
                f->pixelformat = fmt->fourcc;
                f->flags = fmt->flags;
@@ -833,7 +911,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 {
        struct bcm2835_codec_ctx *ctx = file2ctx(file);
 
-       return enum_fmt(f, ctx->dev->decode, true);
+       return enum_fmt(f, ctx, true);
 }
 
 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
@@ -841,7 +919,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
 {
        struct bcm2835_codec_ctx *ctx = file2ctx(file);
 
-       return enum_fmt(f, ctx->dev->decode, false);
+       return enum_fmt(f, ctx, false);
 }
 
 static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f)
@@ -933,11 +1011,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        struct bcm2835_codec_fmt *fmt;
        struct bcm2835_codec_ctx *ctx = file2ctx(file);
 
-       fmt = find_format(f, ctx->dev->decode, true);
+       fmt = find_format(f, ctx->dev, true);
        if (!fmt) {
-               f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
+               f->fmt.pix.pixelformat = get_default_format(ctx->dev,
                                                            true)->fourcc;
-               fmt = find_format(f, ctx->dev->decode, true);
+               fmt = find_format(f, ctx->dev, true);
        }
 
        return vidioc_try_fmt(f, fmt);
@@ -949,11 +1027,11 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
        struct bcm2835_codec_fmt *fmt;
        struct bcm2835_codec_ctx *ctx = file2ctx(file);
 
-       fmt = find_format(f, ctx->dev->decode, false);
+       fmt = find_format(f, ctx->dev, false);
        if (!fmt) {
-               f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
+               f->fmt.pix.pixelformat = get_default_format(ctx->dev,
                                                            false)->fourcc;
-               fmt = find_format(f, ctx->dev->decode, false);
+               fmt = find_format(f, ctx->dev, false);
        }
 
        if (!f->fmt.pix.colorspace)
@@ -988,7 +1066,7 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
                return -EBUSY;
        }
 
-       q_data->fmt = find_format(f, ctx->dev->decode,
+       q_data->fmt = find_format(f, ctx->dev,
                                  f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
        q_data->crop_width = f->fmt.pix.width;
        q_data->height = f->fmt.pix.height;
@@ -1041,7 +1119,7 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
        if (!port)
                return 0;
 
-       setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port);
+       setup_mmal_port_format(ctx, q_data, port);
        ret = vchiq_mmal_port_set_format(ctx->dev->instance, port);
        if (ret) {
                v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n",
@@ -1064,8 +1142,7 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
                struct bcm2835_codec_q_data *q_data_dst =
                                                &ctx->q_data[V4L2_M2M_DST];
 
-               setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst,
-                                      port_dst);
+               setup_mmal_port_format(ctx, q_data_dst, port_dst);
                ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst);
                if (ret) {
                        v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n",
@@ -1636,10 +1713,10 @@ static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx)
                                      MMAL_PARAMETER_ZERO_COPY, &enable,
                                      sizeof(enable));
 
-       setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC],
+       setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_SRC],
                               &ctx->component->input[0]);
 
-       setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST],
+       setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_DST],
                               &ctx->component->output[0]);
 
        ret = vchiq_mmal_port_set_format(dev->instance,
@@ -2025,8 +2102,8 @@ static int bcm2835_codec_open(struct file *file)
                goto open_unlock;
        }
 
-       ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false);
-       ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true);
+       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) {
                /*
                 * Input width and height are irrelevant as they will be defined
@@ -2209,13 +2286,130 @@ static const struct v4l2_m2m_ops m2m_ops = {
        .job_abort      = job_abort,
 };
 
+/* Size of the array to provide to the VPU when asking for the list of supported
+ * formats.
+ * The ISP component currently advertises 33 input formats, so add a small
+ * overhead on that.
+ */
+#define MAX_SUPPORTED_ENCODINGS 40
+
+/* Populate dev->supported_fmts with the formats supported by those ports. */
+static int bcm2835_codec_get_supported_fmts(struct bcm2835_codec_dev *dev)
+{
+       struct bcm2835_codec_fmt *list;
+       struct vchiq_mmal_component *component;
+       u32 fourccs[MAX_SUPPORTED_ENCODINGS];
+       u32 param_size = sizeof(fourccs);
+       unsigned int i, j, num_encodings;
+       int ret;
+
+       ret = vchiq_mmal_component_init(dev->instance,
+                                       dev->decode ?
+                                               "ril.video_decode" :
+                                               "ril.video_encode",
+                                       &component);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n",
+                        __func__);
+               return -ENOMEM;
+       }
+
+       ret = vchiq_mmal_port_parameter_get(dev->instance,
+                                           &component->input[0],
+                                           MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+                                           &fourccs,
+                                           &param_size);
+
+       if (ret) {
+               if (ret == MMAL_MSG_STATUS_ENOSPC) {
+                       v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n",
+                                __func__);
+                       num_encodings = MAX_SUPPORTED_ENCODINGS;
+               } else {
+                       v4l2_err(&dev->v4l2_dev, "%s: get_param ret %u.\n",
+                                __func__, ret);
+                       ret = -EINVAL;
+                       goto destroy_component;
+               }
+       } else {
+               num_encodings = param_size / sizeof(u32);
+       }
+
+       /* Assume at this stage that all encodings will be supported in V4L2.
+        * Any that aren't supported will waste a very small amount of memory.
+        */
+       list = devm_kzalloc(&dev->pdev->dev,
+                           sizeof(struct bcm2835_codec_fmt) * num_encodings,
+                           GFP_KERNEL);
+       if (!list) {
+               ret = -ENOMEM;
+               goto destroy_component;
+       }
+       dev->supported_fmts[0].list = list;
+
+       for (i = 0, j = 0; i < num_encodings; i++) {
+               const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]);
+
+               if (fmt) {
+                       list[j] = *fmt;
+                       j++;
+               }
+       }
+       dev->supported_fmts[0].num_entries = j;
+
+       param_size = sizeof(fourccs);
+       ret = vchiq_mmal_port_parameter_get(dev->instance,
+                                           &component->output[0],
+                                           MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+                                           &fourccs,
+                                           &param_size);
+
+       if (ret) {
+               if (ret == MMAL_MSG_STATUS_ENOSPC) {
+                       v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n",
+                                __func__);
+                       num_encodings = MAX_SUPPORTED_ENCODINGS;
+               } else {
+                       ret = -EINVAL;
+                       goto destroy_component;
+               }
+       } else {
+               num_encodings = param_size / sizeof(u32);
+       }
+       /* Assume at this stage that all encodings will be supported in V4L2. */
+       list = devm_kzalloc(&dev->pdev->dev,
+                           sizeof(struct bcm2835_codec_fmt) * num_encodings,
+                           GFP_KERNEL);
+       if (!list) {
+               ret = -ENOMEM;
+               goto destroy_component;
+       }
+       dev->supported_fmts[1].list = list;
+
+       for (i = 0, j = 0; i < num_encodings; i++) {
+               const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]);
+
+               if (fmt) {
+                       list[j] = *fmt;
+                       j++;
+               }
+       }
+       dev->supported_fmts[1].num_entries = j;
+
+       ret = 0;
+
+destroy_component:
+       vchiq_mmal_component_finalise(dev->instance, component);
+
+       return ret;
+}
+
 static int bcm2835_codec_create(struct platform_device *pdev,
                                struct bcm2835_codec_dev **new_dev,
                                bool decode)
 {
        struct bcm2835_codec_dev *dev;
        struct video_device *vfd;
-       struct vchiq_mmal_instance *instance = NULL;
        int video_nr;
        int ret;
 
@@ -2227,10 +2421,18 @@ static int bcm2835_codec_create(struct platform_device *pdev,
 
        dev->decode = decode;
 
-       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       ret = vchiq_mmal_init(&dev->instance);
        if (ret)
                return ret;
 
+       ret = bcm2835_codec_get_supported_fmts(dev);
+       if (ret)
+               goto vchiq_finalise;
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret)
+               goto vchiq_finalise;
+
        atomic_set(&dev->num_inst, 0);
        mutex_init(&dev->dev_mutex);
 
@@ -2270,12 +2472,7 @@ static int bcm2835_codec_create(struct platform_device *pdev,
                goto err_m2m;
        }
 
-       ret = vchiq_mmal_init(&instance);
-       if (ret < 0)
-               goto err_m2m;
-       dev->instance = instance;
-
-       v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n",
+       v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
                  dev->decode ? "decode" : "encode");
        return 0;
 
@@ -2284,7 +2481,8 @@ err_m2m:
        video_unregister_device(&dev->vfd);
 unreg_dev:
        v4l2_device_unregister(&dev->v4l2_dev);
-
+vchiq_finalise:
+       vchiq_mmal_finalise(dev->instance);
        return ret;
 }
 
@@ -2297,6 +2495,7 @@ static int bcm2835_codec_destroy(struct bcm2835_codec_dev *dev)
        v4l2_m2m_release(dev->m2m_dev);
        video_unregister_device(&dev->vfd);
        v4l2_device_unregister(&dev->v4l2_dev);
+       vchiq_mmal_finalise(dev->instance);
 
        return 0;
 }