media: allegro: move driver out of staging
authorMichael Tretter <m.tretter@pengutronix.de>
Wed, 2 Dec 2020 13:30:37 +0000 (14:30 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Mon, 4 Jan 2021 12:19:40 +0000 (13:19 +0100)
The stateful encoder API was finalized. Nothing is blocking the driver
from being moved out of staging.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
19 files changed:
MAINTAINERS
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/allegro-dvt/Makefile [new file with mode: 0644]
drivers/media/platform/allegro-dvt/allegro-core.c [new file with mode: 0644]
drivers/media/platform/allegro-dvt/allegro-mail.c [new file with mode: 0644]
drivers/media/platform/allegro-dvt/allegro-mail.h [new file with mode: 0644]
drivers/media/platform/allegro-dvt/nal-h264.c [new file with mode: 0644]
drivers/media/platform/allegro-dvt/nal-h264.h [new file with mode: 0644]
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/allegro-dvt/Kconfig [deleted file]
drivers/staging/media/allegro-dvt/Makefile [deleted file]
drivers/staging/media/allegro-dvt/TODO [deleted file]
drivers/staging/media/allegro-dvt/allegro-core.c [deleted file]
drivers/staging/media/allegro-dvt/allegro-mail.c [deleted file]
drivers/staging/media/allegro-dvt/allegro-mail.h [deleted file]
drivers/staging/media/allegro-dvt/nal-h264.c [deleted file]
drivers/staging/media/allegro-dvt/nal-h264.h [deleted file]

index 546aa66428c9f872b59186f491df397be7353769..a40345e0477c953edd462e363f2186c94e14f5fa 100644 (file)
@@ -699,7 +699,7 @@ M:  Michael Tretter <m.tretter@pengutronix.de>
 R:     Pengutronix Kernel Team <kernel@pengutronix.de>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/staging/media/allegro-dvt/
+F:     drivers/media/platform/allegro-dvt/
 
 ALLWINNER A10 CSI DRIVER
 M:     Maxime Ripard <mripard@kernel.org>
index 35a18d388f3f8649c2ae60c8bad031c60a4f4ece..e419b18613c662cd2b7227e2f618e39e78b9ec96 100644 (file)
@@ -199,6 +199,21 @@ menuconfig V4L_MEM2MEM_DRIVERS
 
 if V4L_MEM2MEM_DRIVERS
 
+config VIDEO_ALLEGRO_DVT
+       tristate "Allegro DVT Video IP Core"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on ARCH_ZYNQMP || COMPILE_TEST
+       select V4L2_MEM2MEM_DEV
+       select VIDEOBUF2_DMA_CONTIG
+       select REGMAP_MMIO
+       help
+         Support for the encoder video IP core by Allegro DVT. This core is
+         found for example on the Xilinx ZynqMP SoC in the EV family and is
+         called VCU in the reference manual.
+
+         To compile this driver as a module, choose M here: the module
+         will be called allegro.
+
 config VIDEO_CODA
        tristate "Chips&Media Coda multi-standard codec IP"
        depends on VIDEO_DEV && VIDEO_V4L2 && OF && (ARCH_MXC || COMPILE_TEST)
index 1d63aa956bcd25c96643fc3ecd7c42d40bf6bece..9d4d6370908dcf936c012a4114ffd52a190d6f5e 100644 (file)
@@ -3,6 +3,7 @@
 # Makefile for the video capture/playback device drivers.
 #
 
+obj-$(CONFIG_VIDEO_ALLEGRO_DVT)                += allegro-dvt/
 obj-$(CONFIG_VIDEO_ASPEED)             += aspeed-video.o
 obj-$(CONFIG_VIDEO_CADENCE)            += cadence/
 obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
diff --git a/drivers/media/platform/allegro-dvt/Makefile b/drivers/media/platform/allegro-dvt/Makefile
new file mode 100644 (file)
index 0000000..8e306dc
--- /dev/null
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+allegro-objs := allegro-core.o nal-h264.o allegro-mail.o
+
+obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c
new file mode 100644 (file)
index 0000000..6404511
--- /dev/null
@@ -0,0 +1,3226 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Allegro DVT video encoder driver
+ */
+
+#include <linux/bits.h>
+#include <linux/firmware.h>
+#include <linux/gcd.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "allegro-mail.h"
+#include "nal-h264.h"
+
+/*
+ * Support up to 4k video streams. The hardware actually supports higher
+ * resolutions, which are specified in PG252 June 6, 2018 (H.264/H.265 Video
+ * Codec Unit v1.1) Chapter 3.
+ */
+#define ALLEGRO_WIDTH_MIN 128
+#define ALLEGRO_WIDTH_DEFAULT 1920
+#define ALLEGRO_WIDTH_MAX 3840
+#define ALLEGRO_HEIGHT_MIN 64
+#define ALLEGRO_HEIGHT_DEFAULT 1080
+#define ALLEGRO_HEIGHT_MAX 2160
+
+#define ALLEGRO_FRAMERATE_DEFAULT ((struct v4l2_fract) { 30, 1 })
+
+#define ALLEGRO_GOP_SIZE_DEFAULT 25
+#define ALLEGRO_GOP_SIZE_MAX 1000
+
+/*
+ * MCU Control Registers
+ *
+ * The Zynq UltraScale+ Devices Register Reference documents the registers
+ * with an offset of 0x9000, which equals the size of the SRAM and one page
+ * gap. The driver handles SRAM and registers separately and, therefore, is
+ * oblivious of the offset.
+ */
+#define AL5_MCU_RESET                   0x0000
+#define AL5_MCU_RESET_SOFT              BIT(0)
+#define AL5_MCU_RESET_REGS              BIT(1)
+#define AL5_MCU_RESET_MODE              0x0004
+#define AL5_MCU_RESET_MODE_SLEEP        BIT(0)
+#define AL5_MCU_RESET_MODE_HALT         BIT(1)
+#define AL5_MCU_STA                     0x0008
+#define AL5_MCU_STA_SLEEP               BIT(0)
+#define AL5_MCU_WAKEUP                  0x000c
+
+#define AL5_ICACHE_ADDR_OFFSET_MSB      0x0010
+#define AL5_ICACHE_ADDR_OFFSET_LSB      0x0014
+#define AL5_DCACHE_ADDR_OFFSET_MSB      0x0018
+#define AL5_DCACHE_ADDR_OFFSET_LSB      0x001c
+
+#define AL5_MCU_INTERRUPT               0x0100
+#define AL5_ITC_CPU_IRQ_MSK             0x0104
+#define AL5_ITC_CPU_IRQ_CLR             0x0108
+#define AL5_ITC_CPU_IRQ_STA             0x010C
+#define AL5_ITC_CPU_IRQ_STA_TRIGGERED   BIT(0)
+
+#define AXI_ADDR_OFFSET_IP              0x0208
+
+/*
+ * The MCU accesses the system memory with a 2G offset compared to CPU
+ * physical addresses.
+ */
+#define MCU_CACHE_OFFSET SZ_2G
+
+/*
+ * The driver needs to reserve some space at the beginning of capture buffers,
+ * because it needs to write SPS/PPS NAL units. The encoder writes the actual
+ * frame data after the offset.
+ */
+#define ENCODER_STREAM_OFFSET SZ_64
+
+#define SIZE_MACROBLOCK 16
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+struct allegro_buffer {
+       void *vaddr;
+       dma_addr_t paddr;
+       size_t size;
+       struct list_head head;
+};
+
+struct allegro_dev;
+struct allegro_channel;
+
+struct allegro_mbox {
+       struct allegro_dev *dev;
+       unsigned int head;
+       unsigned int tail;
+       unsigned int data;
+       size_t size;
+       /* protect mailbox from simultaneous accesses */
+       struct mutex lock;
+};
+
+struct allegro_dev {
+       struct v4l2_device v4l2_dev;
+       struct video_device video_dev;
+       struct v4l2_m2m_dev *m2m_dev;
+       struct platform_device *plat_dev;
+
+       /* mutex protecting vb2_queue structure */
+       struct mutex lock;
+
+       struct regmap *regmap;
+       struct regmap *sram;
+
+       const struct fw_info *fw_info;
+       struct allegro_buffer firmware;
+       struct allegro_buffer suballocator;
+
+       struct completion init_complete;
+
+       /* The mailbox interface */
+       struct allegro_mbox *mbox_command;
+       struct allegro_mbox *mbox_status;
+
+       /*
+        * The downstream driver limits the users to 64 users, thus I can use
+        * a bitfield for the user_ids that are in use. See also user_id in
+        * struct allegro_channel.
+        */
+       unsigned long channel_user_ids;
+       struct list_head channels;
+};
+
+static struct regmap_config allegro_regmap_config = {
+       .name = "regmap",
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = 0xfff,
+       .cache_type = REGCACHE_NONE,
+};
+
+static struct regmap_config allegro_sram_config = {
+       .name = "sram",
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = 0x7fff,
+       .cache_type = REGCACHE_NONE,
+};
+
+enum allegro_state {
+       ALLEGRO_STATE_ENCODING,
+       ALLEGRO_STATE_DRAIN,
+       ALLEGRO_STATE_WAIT_FOR_BUFFER,
+       ALLEGRO_STATE_STOPPED,
+};
+
+#define fh_to_channel(__fh) container_of(__fh, struct allegro_channel, fh)
+
+struct allegro_channel {
+       struct allegro_dev *dev;
+       struct v4l2_fh fh;
+       struct v4l2_ctrl_handler ctrl_handler;
+
+       unsigned int width;
+       unsigned int height;
+       unsigned int stride;
+       struct v4l2_fract framerate;
+
+       enum v4l2_colorspace colorspace;
+       enum v4l2_ycbcr_encoding ycbcr_enc;
+       enum v4l2_quantization quantization;
+       enum v4l2_xfer_func xfer_func;
+
+       u32 pixelformat;
+       unsigned int sizeimage_raw;
+       unsigned int osequence;
+
+       u32 codec;
+       enum v4l2_mpeg_video_h264_profile profile;
+       enum v4l2_mpeg_video_h264_level level;
+       unsigned int sizeimage_encoded;
+       unsigned int csequence;
+
+       bool frame_rc_enable;
+       unsigned int bitrate;
+       unsigned int bitrate_peak;
+       unsigned int cpb_size;
+       unsigned int gop_size;
+
+       struct allegro_buffer config_blob;
+
+       unsigned int num_ref_idx_l0;
+       unsigned int num_ref_idx_l1;
+
+       struct v4l2_ctrl *mpeg_video_h264_profile;
+       struct v4l2_ctrl *mpeg_video_h264_level;
+       struct v4l2_ctrl *mpeg_video_h264_i_frame_qp;
+       struct v4l2_ctrl *mpeg_video_h264_max_qp;
+       struct v4l2_ctrl *mpeg_video_h264_min_qp;
+       struct v4l2_ctrl *mpeg_video_h264_p_frame_qp;
+       struct v4l2_ctrl *mpeg_video_h264_b_frame_qp;
+       struct v4l2_ctrl *mpeg_video_frame_rc_enable;
+       struct { /* video bitrate mode control cluster */
+               struct v4l2_ctrl *mpeg_video_bitrate_mode;
+               struct v4l2_ctrl *mpeg_video_bitrate;
+               struct v4l2_ctrl *mpeg_video_bitrate_peak;
+       };
+       struct v4l2_ctrl *mpeg_video_cpb_size;
+       struct v4l2_ctrl *mpeg_video_gop_size;
+
+       /* user_id is used to identify the channel during CREATE_CHANNEL */
+       /* not sure, what to set here and if this is actually required */
+       int user_id;
+       /* channel_id is set by the mcu and used by all later commands */
+       int mcu_channel_id;
+
+       struct list_head buffers_reference;
+       struct list_head buffers_intermediate;
+
+       struct list_head source_shadow_list;
+       struct list_head stream_shadow_list;
+       /* protect shadow lists of buffers passed to firmware */
+       struct mutex shadow_list_lock;
+
+       struct list_head list;
+       struct completion completion;
+
+       unsigned int error;
+       enum allegro_state state;
+};
+
+static inline int
+allegro_set_state(struct allegro_channel *channel, enum allegro_state state)
+{
+       channel->state = state;
+
+       return 0;
+}
+
+static inline enum allegro_state
+allegro_get_state(struct allegro_channel *channel)
+{
+       return channel->state;
+}
+
+struct allegro_m2m_buffer {
+       struct v4l2_m2m_buffer buf;
+       struct list_head head;
+};
+
+#define to_allegro_m2m_buffer(__buf) \
+       container_of(__buf, struct allegro_m2m_buffer, buf)
+
+struct fw_info {
+       unsigned int id;
+       unsigned int id_codec;
+       char *version;
+       unsigned int mailbox_cmd;
+       unsigned int mailbox_status;
+       size_t mailbox_size;
+       enum mcu_msg_version mailbox_version;
+       size_t suballocator_size;
+};
+
+static const struct fw_info supported_firmware[] = {
+       {
+               .id = 18296,
+               .id_codec = 96272,
+               .version = "v2018.2",
+               .mailbox_cmd = 0x7800,
+               .mailbox_status = 0x7c00,
+               .mailbox_size = 0x400 - 0x8,
+               .mailbox_version = MCU_MSG_VERSION_2018_2,
+               .suballocator_size = SZ_16M,
+       }, {
+               .id = 14680,
+               .id_codec = 126572,
+               .version = "v2019.2",
+               .mailbox_cmd = 0x7000,
+               .mailbox_status = 0x7800,
+               .mailbox_size = 0x800 - 0x8,
+               .mailbox_version = MCU_MSG_VERSION_2019_2,
+               .suballocator_size = SZ_32M,
+       },
+};
+
+static inline u32 to_mcu_addr(struct allegro_dev *dev, dma_addr_t phys)
+{
+       if (upper_32_bits(phys) || (lower_32_bits(phys) & MCU_CACHE_OFFSET))
+               v4l2_warn(&dev->v4l2_dev,
+                         "address %pad is outside mcu window\n", &phys);
+
+       return lower_32_bits(phys) | MCU_CACHE_OFFSET;
+}
+
+static inline u32 to_mcu_size(struct allegro_dev *dev, size_t size)
+{
+       return lower_32_bits(size);
+}
+
+static inline u32 to_codec_addr(struct allegro_dev *dev, dma_addr_t phys)
+{
+       if (upper_32_bits(phys))
+               v4l2_warn(&dev->v4l2_dev,
+                         "address %pad cannot be used by codec\n", &phys);
+
+       return lower_32_bits(phys);
+}
+
+static inline u64 ptr_to_u64(const void *ptr)
+{
+       return (uintptr_t)ptr;
+}
+
+/* Helper functions for channel and user operations */
+
+static unsigned long allegro_next_user_id(struct allegro_dev *dev)
+{
+       if (dev->channel_user_ids == ~0UL)
+               return -EBUSY;
+
+       return ffz(dev->channel_user_ids);
+}
+
+static struct allegro_channel *
+allegro_find_channel_by_user_id(struct allegro_dev *dev,
+                               unsigned int user_id)
+{
+       struct allegro_channel *channel;
+
+       list_for_each_entry(channel, &dev->channels, list) {
+               if (channel->user_id == user_id)
+                       return channel;
+       }
+
+       return ERR_PTR(-EINVAL);
+}
+
+static struct allegro_channel *
+allegro_find_channel_by_channel_id(struct allegro_dev *dev,
+                                  unsigned int channel_id)
+{
+       struct allegro_channel *channel;
+
+       list_for_each_entry(channel, &dev->channels, list) {
+               if (channel->mcu_channel_id == channel_id)
+                       return channel;
+       }
+
+       return ERR_PTR(-EINVAL);
+}
+
+static inline bool channel_exists(struct allegro_channel *channel)
+{
+       return channel->mcu_channel_id != -1;
+}
+
+#define AL_ERROR                       0x80
+#define AL_ERR_INIT_FAILED             0x81
+#define AL_ERR_NO_FRAME_DECODED                0x82
+#define AL_ERR_RESOLUTION_CHANGE       0x85
+#define AL_ERR_NO_MEMORY               0x87
+#define AL_ERR_STREAM_OVERFLOW         0x88
+#define AL_ERR_TOO_MANY_SLICES         0x89
+#define AL_ERR_BUF_NOT_READY           0x8c
+#define AL_ERR_NO_CHANNEL_AVAILABLE    0x8d
+#define AL_ERR_RESOURCE_UNAVAILABLE    0x8e
+#define AL_ERR_NOT_ENOUGH_CORES                0x8f
+#define AL_ERR_REQUEST_MALFORMED       0x90
+#define AL_ERR_CMD_NOT_ALLOWED         0x91
+#define AL_ERR_INVALID_CMD_VALUE       0x92
+
+static inline const char *allegro_err_to_string(unsigned int err)
+{
+       switch (err) {
+       case AL_ERR_INIT_FAILED:
+               return "initialization failed";
+       case AL_ERR_NO_FRAME_DECODED:
+               return "no frame decoded";
+       case AL_ERR_RESOLUTION_CHANGE:
+               return "resolution change";
+       case AL_ERR_NO_MEMORY:
+               return "out of memory";
+       case AL_ERR_STREAM_OVERFLOW:
+               return "stream buffer overflow";
+       case AL_ERR_TOO_MANY_SLICES:
+               return "too many slices";
+       case AL_ERR_BUF_NOT_READY:
+               return "buffer not ready";
+       case AL_ERR_NO_CHANNEL_AVAILABLE:
+               return "no channel available";
+       case AL_ERR_RESOURCE_UNAVAILABLE:
+               return "resource unavailable";
+       case AL_ERR_NOT_ENOUGH_CORES:
+               return "not enough cores";
+       case AL_ERR_REQUEST_MALFORMED:
+               return "request malformed";
+       case AL_ERR_CMD_NOT_ALLOWED:
+               return "command not allowed";
+       case AL_ERR_INVALID_CMD_VALUE:
+               return "invalid command value";
+       case AL_ERROR:
+       default:
+               return "unknown error";
+       }
+}
+
+static unsigned int estimate_stream_size(unsigned int width,
+                                        unsigned int height)
+{
+       unsigned int offset = ENCODER_STREAM_OFFSET;
+       unsigned int num_blocks = DIV_ROUND_UP(width, SIZE_MACROBLOCK) *
+                                       DIV_ROUND_UP(height, SIZE_MACROBLOCK);
+       unsigned int pcm_size = SZ_256;
+       unsigned int partition_table = SZ_256;
+
+       return round_up(offset + num_blocks * pcm_size + partition_table, 32);
+}
+
+static enum v4l2_mpeg_video_h264_level
+select_minimum_h264_level(unsigned int width, unsigned int height)
+{
+       unsigned int pic_width_in_mb = DIV_ROUND_UP(width, SIZE_MACROBLOCK);
+       unsigned int frame_height_in_mb = DIV_ROUND_UP(height, SIZE_MACROBLOCK);
+       unsigned int frame_size_in_mb = pic_width_in_mb * frame_height_in_mb;
+       enum v4l2_mpeg_video_h264_level level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+
+       /*
+        * The level limits are specified in Rec. ITU-T H.264 Annex A.3.1 and
+        * also specify limits regarding bit rate and CBP size. Only approximate
+        * the levels using the frame size.
+        *
+        * Level 5.1 allows up to 4k video resolution.
+        */
+       if (frame_size_in_mb <= 99)
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
+       else if (frame_size_in_mb <= 396)
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
+       else if (frame_size_in_mb <= 792)
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
+       else if (frame_size_in_mb <= 1620)
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
+       else if (frame_size_in_mb <= 3600)
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
+       else if (frame_size_in_mb <= 5120)
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
+       else if (frame_size_in_mb <= 8192)
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+       else if (frame_size_in_mb <= 8704)
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
+       else if (frame_size_in_mb <= 22080)
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
+       else
+               level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+
+       return level;
+}
+
+static unsigned int maximum_bitrate(enum v4l2_mpeg_video_h264_level level)
+{
+       switch (level) {
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+               return 64000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+               return 128000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+               return 192000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+               return 384000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+               return 768000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+               return 2000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+               return 4000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+               return 4000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+               return 10000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+               return 14000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+               return 20000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+               return 20000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+               return 50000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+               return 50000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+               return 135000000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+       default:
+               return 240000000;
+       }
+}
+
+static unsigned int maximum_cpb_size(enum v4l2_mpeg_video_h264_level level)
+{
+       switch (level) {
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+               return 175;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+               return 350;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+               return 500;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+               return 1000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+               return 2000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+               return 2000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+               return 4000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+               return 4000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+               return 10000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+               return 14000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+               return 20000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+               return 25000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+               return 62500;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+               return 62500;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+               return 135000;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+       default:
+               return 240000;
+       }
+}
+
+static const struct fw_info *
+allegro_get_firmware_info(struct allegro_dev *dev,
+                         const struct firmware *fw,
+                         const struct firmware *fw_codec)
+{
+       int i;
+       unsigned int id = fw->size;
+       unsigned int id_codec = fw_codec->size;
+
+       for (i = 0; i < ARRAY_SIZE(supported_firmware); i++)
+               if (supported_firmware[i].id == id &&
+                   supported_firmware[i].id_codec == id_codec)
+                       return &supported_firmware[i];
+
+       return NULL;
+}
+
+/*
+ * Buffers that are used internally by the MCU.
+ */
+
+static int allegro_alloc_buffer(struct allegro_dev *dev,
+                               struct allegro_buffer *buffer, size_t size)
+{
+       buffer->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size,
+                                          &buffer->paddr, GFP_KERNEL);
+       if (!buffer->vaddr)
+               return -ENOMEM;
+       buffer->size = size;
+
+       return 0;
+}
+
+static void allegro_free_buffer(struct allegro_dev *dev,
+                               struct allegro_buffer *buffer)
+{
+       if (buffer->vaddr) {
+               dma_free_coherent(&dev->plat_dev->dev, buffer->size,
+                                 buffer->vaddr, buffer->paddr);
+               buffer->vaddr = NULL;
+               buffer->size = 0;
+       }
+}
+
+/*
+ * Mailbox interface to send messages to the MCU.
+ */
+
+static void allegro_mcu_interrupt(struct allegro_dev *dev);
+static void allegro_handle_message(struct allegro_dev *dev,
+                                  union mcu_msg_response *msg);
+
+static struct allegro_mbox *allegro_mbox_init(struct allegro_dev *dev,
+                                             unsigned int base, size_t size)
+{
+       struct allegro_mbox *mbox;
+
+       mbox = devm_kmalloc(&dev->plat_dev->dev, sizeof(*mbox), GFP_KERNEL);
+       if (!mbox)
+               return ERR_PTR(-ENOMEM);
+
+       mbox->dev = dev;
+
+       mbox->head = base;
+       mbox->tail = base + 0x4;
+       mbox->data = base + 0x8;
+       mbox->size = size;
+       mutex_init(&mbox->lock);
+
+       regmap_write(dev->sram, mbox->head, 0);
+       regmap_write(dev->sram, mbox->tail, 0);
+
+       return mbox;
+}
+
+static int allegro_mbox_write(struct allegro_mbox *mbox,
+                             const u32 *src, size_t size)
+{
+       struct regmap *sram = mbox->dev->sram;
+       unsigned int tail;
+       size_t size_no_wrap;
+       int err = 0;
+       int stride = regmap_get_reg_stride(sram);
+
+       if (!src)
+               return -EINVAL;
+
+       if (size > mbox->size)
+               return -EINVAL;
+
+       mutex_lock(&mbox->lock);
+       regmap_read(sram, mbox->tail, &tail);
+       if (tail > mbox->size) {
+               err = -EIO;
+               goto out;
+       }
+       size_no_wrap = min(size, mbox->size - (size_t)tail);
+       regmap_bulk_write(sram, mbox->data + tail,
+                         src, size_no_wrap / stride);
+       regmap_bulk_write(sram, mbox->data,
+                         src + (size_no_wrap / sizeof(*src)),
+                         (size - size_no_wrap) / stride);
+       regmap_write(sram, mbox->tail, (tail + size) % mbox->size);
+
+out:
+       mutex_unlock(&mbox->lock);
+
+       return err;
+}
+
+static ssize_t allegro_mbox_read(struct allegro_mbox *mbox,
+                                u32 *dst, size_t nbyte)
+{
+       struct {
+               u16 length;
+               u16 type;
+       } __attribute__ ((__packed__)) *header;
+       struct regmap *sram = mbox->dev->sram;
+       unsigned int head;
+       ssize_t size;
+       size_t body_no_wrap;
+       int stride = regmap_get_reg_stride(sram);
+
+       regmap_read(sram, mbox->head, &head);
+       if (head > mbox->size)
+               return -EIO;
+
+       /* Assume that the header does not wrap. */
+       regmap_bulk_read(sram, mbox->data + head,
+                        dst, sizeof(*header) / stride);
+       header = (void *)dst;
+       size = header->length + sizeof(*header);
+       if (size > mbox->size || size & 0x3)
+               return -EIO;
+       if (size > nbyte)
+               return -EINVAL;
+
+       /*
+        * The message might wrap within the mailbox. If the message does not
+        * wrap, the first read will read the entire message, otherwise the
+        * first read will read message until the end of the mailbox and the
+        * second read will read the remaining bytes from the beginning of the
+        * mailbox.
+        *
+        * Skip the header, as was already read to get the size of the body.
+        */
+       body_no_wrap = min((size_t)header->length,
+                          (size_t)(mbox->size - (head + sizeof(*header))));
+       regmap_bulk_read(sram, mbox->data + head + sizeof(*header),
+                        dst + (sizeof(*header) / sizeof(*dst)),
+                        body_no_wrap / stride);
+       regmap_bulk_read(sram, mbox->data,
+                        dst + (sizeof(*header) + body_no_wrap) / sizeof(*dst),
+                        (header->length - body_no_wrap) / stride);
+
+       regmap_write(sram, mbox->head, (head + size) % mbox->size);
+
+       return size;
+}
+
+/**
+ * allegro_mbox_send() - Send a message via the mailbox
+ * @mbox: the mailbox which is used to send the message
+ * @msg: the message to send
+ */
+static int allegro_mbox_send(struct allegro_mbox *mbox, void *msg)
+{
+       struct allegro_dev *dev = mbox->dev;
+       ssize_t size;
+       int err;
+       u32 *tmp;
+
+       tmp = kzalloc(mbox->size, GFP_KERNEL);
+       if (!tmp) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       size = allegro_encode_mail(tmp, msg);
+
+       err = allegro_mbox_write(mbox, tmp, size);
+       kfree(tmp);
+       if (err)
+               goto out;
+
+       allegro_mcu_interrupt(dev);
+
+out:
+       return err;
+}
+
+/**
+ * allegro_mbox_notify() - Notify the mailbox about a new message
+ * @mbox: The allegro_mbox to notify
+ */
+static void allegro_mbox_notify(struct allegro_mbox *mbox)
+{
+       struct allegro_dev *dev = mbox->dev;
+       union mcu_msg_response *msg;
+       ssize_t size;
+       u32 *tmp;
+       int err;
+
+       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+       if (!msg)
+               return;
+
+       msg->header.version = dev->fw_info->mailbox_version;
+
+       tmp = kmalloc(mbox->size, GFP_KERNEL);
+       if (!tmp)
+               goto out;
+
+       size = allegro_mbox_read(mbox, tmp, mbox->size);
+       if (size < 0)
+               goto out;
+
+       err = allegro_decode_mail(msg, tmp);
+       if (err)
+               goto out;
+
+       allegro_handle_message(dev, msg);
+
+out:
+       kfree(tmp);
+       kfree(msg);
+}
+
+static void allegro_mcu_send_init(struct allegro_dev *dev,
+                                 dma_addr_t suballoc_dma, size_t suballoc_size)
+{
+       struct mcu_msg_init_request msg;
+
+       memset(&msg, 0, sizeof(msg));
+
+       msg.header.type = MCU_MSG_TYPE_INIT;
+       msg.header.version = dev->fw_info->mailbox_version;
+
+       msg.suballoc_dma = to_mcu_addr(dev, suballoc_dma);
+       msg.suballoc_size = to_mcu_size(dev, suballoc_size);
+
+       /* disable L2 cache */
+       msg.l2_cache[0] = -1;
+       msg.l2_cache[1] = -1;
+       msg.l2_cache[2] = -1;
+
+       allegro_mbox_send(dev->mbox_command, &msg);
+}
+
+static u32 v4l2_pixelformat_to_mcu_format(u32 pixelformat)
+{
+       switch (pixelformat) {
+       case V4L2_PIX_FMT_NV12:
+               /* AL_420_8BITS: 0x100 -> NV12, 0x88 -> 8 bit */
+               return 0x100 | 0x88;
+       default:
+               return -EINVAL;
+       }
+}
+
+static u32 v4l2_colorspace_to_mcu_colorspace(enum v4l2_colorspace colorspace)
+{
+       switch (colorspace) {
+       case V4L2_COLORSPACE_REC709:
+               return 2;
+       case V4L2_COLORSPACE_SMPTE170M:
+               return 3;
+       case V4L2_COLORSPACE_SMPTE240M:
+               return 4;
+       case V4L2_COLORSPACE_SRGB:
+               return 7;
+       default:
+               /* UNKNOWN */
+               return 0;
+       }
+}
+
+static u8 v4l2_profile_to_mcu_profile(enum v4l2_mpeg_video_h264_profile profile)
+{
+       switch (profile) {
+       case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+       default:
+               return 66;
+       }
+}
+
+static u16 v4l2_level_to_mcu_level(enum v4l2_mpeg_video_h264_level level)
+{
+       switch (level) {
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+               return 10;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+               return 11;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+               return 12;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+               return 13;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+               return 20;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+               return 21;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+               return 22;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+               return 30;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+               return 31;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+               return 32;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+               return 40;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+               return 41;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+               return 42;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+               return 50;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+       default:
+               return 51;
+       }
+}
+
+static u32
+v4l2_bitrate_mode_to_mcu_mode(enum v4l2_mpeg_video_bitrate_mode mode)
+{
+       switch (mode) {
+       case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+               return 2;
+       case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+       default:
+               return 1;
+       }
+}
+
+static u32 v4l2_cpb_size_to_mcu(unsigned int cpb_size, unsigned int bitrate)
+{
+       unsigned int cpb_size_kbit;
+       unsigned int bitrate_kbps;
+
+       /*
+        * The mcu expects the CPB size in units of a 90 kHz clock, but the
+        * channel follows the V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE and stores
+        * the CPB size in kilobytes.
+        */
+       cpb_size_kbit = cpb_size * BITS_PER_BYTE;
+       bitrate_kbps = bitrate / 1000;
+
+       return (cpb_size_kbit * 90000) / bitrate_kbps;
+}
+
+static s16 get_qp_delta(int minuend, int subtrahend)
+{
+       if (minuend == subtrahend)
+               return -1;
+       else
+               return minuend - subtrahend;
+}
+
+static int fill_create_channel_param(struct allegro_channel *channel,
+                                    struct create_channel_param *param)
+{
+       int i_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_i_frame_qp);
+       int p_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_p_frame_qp);
+       int b_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_b_frame_qp);
+       int bitrate_mode = v4l2_ctrl_g_ctrl(channel->mpeg_video_bitrate_mode);
+
+       param->width = channel->width;
+       param->height = channel->height;
+       param->format = v4l2_pixelformat_to_mcu_format(channel->pixelformat);
+       param->colorspace =
+               v4l2_colorspace_to_mcu_colorspace(channel->colorspace);
+       param->src_mode = 0x0;
+       param->profile = v4l2_profile_to_mcu_profile(channel->profile);
+       param->constraint_set_flags = BIT(1);
+       param->codec = channel->codec;
+       param->level = v4l2_level_to_mcu_level(channel->level);
+       param->tier = 0;
+
+       param->log2_max_poc = 10;
+       param->log2_max_frame_num = 4;
+       param->temporal_mvp_enable = 1;
+
+       param->dbf_ovr_en = 1;
+       param->rdo_cost_mode = 1;
+       param->custom_lda = 1;
+       param->lf = 1;
+       param->lf_x_tile = 1;
+       param->lf_x_slice = 1;
+
+       param->src_bit_depth = 8;
+
+       param->beta_offset = -1;
+       param->tc_offset = -1;
+       param->num_slices = 1;
+       param->me_range[0] = 8;
+       param->me_range[1] = 8;
+       param->me_range[2] = 16;
+       param->me_range[3] = 16;
+       param->max_cu_size = ilog2(SIZE_MACROBLOCK);
+       param->min_cu_size = ilog2(8);
+       param->max_tu_size = 2;
+       param->min_tu_size = 2;
+       param->max_transfo_depth_intra = 1;
+       param->max_transfo_depth_inter = 1;
+
+       param->prefetch_auto = 0;
+       param->prefetch_mem_offset = 0;
+       param->prefetch_mem_size = 0;
+
+       param->rate_control_mode = channel->frame_rc_enable ?
+               v4l2_bitrate_mode_to_mcu_mode(bitrate_mode) : 0;
+
+       param->cpb_size = v4l2_cpb_size_to_mcu(channel->cpb_size,
+                                              channel->bitrate_peak);
+       /* Shall be ]0;cpb_size in 90 kHz units]. Use maximum value. */
+       param->initial_rem_delay = param->cpb_size;
+       param->framerate = DIV_ROUND_UP(channel->framerate.numerator,
+                                       channel->framerate.denominator);
+       param->clk_ratio = channel->framerate.denominator == 1001 ? 1001 : 1000;
+       param->target_bitrate = channel->bitrate;
+       param->max_bitrate = channel->bitrate_peak;
+       param->initial_qp = i_frame_qp;
+       param->min_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_min_qp);
+       param->max_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_max_qp);
+       param->ip_delta = get_qp_delta(i_frame_qp, p_frame_qp);
+       param->pb_delta = get_qp_delta(p_frame_qp, b_frame_qp);
+       param->golden_ref = 0;
+       param->golden_delta = 2;
+       param->golden_ref_frequency = 10;
+       param->rate_control_option = 0x00000000;
+
+       param->num_pixel = channel->width + channel->height;
+       param->max_psnr = 4200;
+       param->max_pixel_value = 255;
+
+       param->gop_ctrl_mode = 0x00000002;
+       param->freq_idr = channel->gop_size;
+       param->freq_lt = 0;
+       param->gdr_mode = 0x00000000;
+       param->gop_length = channel->gop_size;
+       param->subframe_latency = 0x00000000;
+
+       param->lda_factors[0] = 51;
+       param->lda_factors[1] = 90;
+       param->lda_factors[2] = 151;
+       param->lda_factors[3] = 151;
+       param->lda_factors[4] = 151;
+       param->lda_factors[5] = 151;
+
+       param->max_num_merge_cand = 5;
+
+       return 0;
+}
+
+static int allegro_mcu_send_create_channel(struct allegro_dev *dev,
+                                          struct allegro_channel *channel)
+{
+       struct mcu_msg_create_channel msg;
+       struct allegro_buffer *blob = &channel->config_blob;
+       struct create_channel_param param;
+       size_t size;
+
+       memset(&param, 0, sizeof(param));
+       fill_create_channel_param(channel, &param);
+       allegro_alloc_buffer(dev, blob, sizeof(struct create_channel_param));
+       param.version = dev->fw_info->mailbox_version;
+       size = allegro_encode_config_blob(blob->vaddr, &param);
+
+       memset(&msg, 0, sizeof(msg));
+
+       msg.header.type = MCU_MSG_TYPE_CREATE_CHANNEL;
+       msg.header.version = dev->fw_info->mailbox_version;
+
+       msg.user_id = channel->user_id;
+
+       msg.blob = blob->vaddr;
+       msg.blob_size = size;
+       msg.blob_mcu_addr = to_mcu_addr(dev, blob->paddr);
+
+       allegro_mbox_send(dev->mbox_command, &msg);
+
+       return 0;
+}
+
+static int allegro_mcu_send_destroy_channel(struct allegro_dev *dev,
+                                           struct allegro_channel *channel)
+{
+       struct mcu_msg_destroy_channel msg;
+
+       memset(&msg, 0, sizeof(msg));
+
+       msg.header.type = MCU_MSG_TYPE_DESTROY_CHANNEL;
+       msg.header.version = dev->fw_info->mailbox_version;
+
+       msg.channel_id = channel->mcu_channel_id;
+
+       allegro_mbox_send(dev->mbox_command, &msg);
+
+       return 0;
+}
+
+static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev,
+                                             struct allegro_channel *channel,
+                                             dma_addr_t paddr,
+                                             unsigned long size,
+                                             u64 stream_id)
+{
+       struct mcu_msg_put_stream_buffer msg;
+
+       memset(&msg, 0, sizeof(msg));
+
+       msg.header.type = MCU_MSG_TYPE_PUT_STREAM_BUFFER;
+       msg.header.version = dev->fw_info->mailbox_version;
+
+       msg.channel_id = channel->mcu_channel_id;
+       msg.dma_addr = to_codec_addr(dev, paddr);
+       msg.mcu_addr = to_mcu_addr(dev, paddr);
+       msg.size = size;
+       msg.offset = ENCODER_STREAM_OFFSET;
+       /* copied to mcu_msg_encode_frame_response */
+       msg.stream_id = stream_id;
+
+       allegro_mbox_send(dev->mbox_command, &msg);
+
+       return 0;
+}
+
+static int allegro_mcu_send_encode_frame(struct allegro_dev *dev,
+                                        struct allegro_channel *channel,
+                                        dma_addr_t src_y, dma_addr_t src_uv,
+                                        u64 src_handle)
+{
+       struct mcu_msg_encode_frame msg;
+
+       memset(&msg, 0, sizeof(msg));
+
+       msg.header.type = MCU_MSG_TYPE_ENCODE_FRAME;
+       msg.header.version = dev->fw_info->mailbox_version;
+
+       msg.channel_id = channel->mcu_channel_id;
+       msg.encoding_options = AL_OPT_FORCE_LOAD;
+       msg.pps_qp = 26; /* qp are relative to 26 */
+       msg.user_param = 0; /* copied to mcu_msg_encode_frame_response */
+       /* src_handle is copied to mcu_msg_encode_frame_response */
+       msg.src_handle = src_handle;
+       msg.src_y = to_codec_addr(dev, src_y);
+       msg.src_uv = to_codec_addr(dev, src_uv);
+       msg.stride = channel->stride;
+       msg.ep2 = 0x0;
+       msg.ep2_v = to_mcu_addr(dev, msg.ep2);
+
+       allegro_mbox_send(dev->mbox_command, &msg);
+
+       return 0;
+}
+
+static int allegro_mcu_wait_for_init_timeout(struct allegro_dev *dev,
+                                            unsigned long timeout_ms)
+{
+       unsigned long tmo;
+
+       tmo = wait_for_completion_timeout(&dev->init_complete,
+                                         msecs_to_jiffies(timeout_ms));
+       if (tmo == 0)
+               return -ETIMEDOUT;
+
+       reinit_completion(&dev->init_complete);
+       return 0;
+}
+
+static int allegro_mcu_push_buffer_internal(struct allegro_channel *channel,
+                                           enum mcu_msg_type type)
+{
+       struct allegro_dev *dev = channel->dev;
+       struct mcu_msg_push_buffers_internal *msg;
+       struct mcu_msg_push_buffers_internal_buffer *buffer;
+       unsigned int num_buffers = 0;
+       size_t size;
+       struct allegro_buffer *al_buffer;
+       struct list_head *list;
+       int err;
+
+       switch (type) {
+       case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
+               list = &channel->buffers_reference;
+               break;
+       case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
+               list = &channel->buffers_intermediate;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       list_for_each_entry(al_buffer, list, head)
+               num_buffers++;
+       size = struct_size(msg, buffer, num_buffers);
+
+       msg = kmalloc(size, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       msg->header.type = type;
+       msg->header.version = dev->fw_info->mailbox_version;
+
+       msg->channel_id = channel->mcu_channel_id;
+       msg->num_buffers = num_buffers;
+
+       buffer = msg->buffer;
+       list_for_each_entry(al_buffer, list, head) {
+               buffer->dma_addr = to_codec_addr(dev, al_buffer->paddr);
+               buffer->mcu_addr = to_mcu_addr(dev, al_buffer->paddr);
+               buffer->size = to_mcu_size(dev, al_buffer->size);
+               buffer++;
+       }
+
+       err = allegro_mbox_send(dev->mbox_command, msg);
+
+       kfree(msg);
+       return err;
+}
+
+static int allegro_mcu_push_buffer_intermediate(struct allegro_channel *channel)
+{
+       enum mcu_msg_type type = MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE;
+
+       return allegro_mcu_push_buffer_internal(channel, type);
+}
+
+static int allegro_mcu_push_buffer_reference(struct allegro_channel *channel)
+{
+       enum mcu_msg_type type = MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE;
+
+       return allegro_mcu_push_buffer_internal(channel, type);
+}
+
+static int allocate_buffers_internal(struct allegro_channel *channel,
+                                    struct list_head *list,
+                                    size_t n, size_t size)
+{
+       struct allegro_dev *dev = channel->dev;
+       unsigned int i;
+       int err;
+       struct allegro_buffer *buffer, *tmp;
+
+       for (i = 0; i < n; i++) {
+               buffer = kmalloc(sizeof(*buffer), GFP_KERNEL);
+               if (!buffer) {
+                       err = -ENOMEM;
+                       goto err;
+               }
+               INIT_LIST_HEAD(&buffer->head);
+
+               err = allegro_alloc_buffer(dev, buffer, size);
+               if (err)
+                       goto err;
+               list_add(&buffer->head, list);
+       }
+
+       return 0;
+
+err:
+       list_for_each_entry_safe(buffer, tmp, list, head) {
+               list_del(&buffer->head);
+               allegro_free_buffer(dev, buffer);
+               kfree(buffer);
+       }
+       return err;
+}
+
+static void destroy_buffers_internal(struct allegro_channel *channel,
+                                    struct list_head *list)
+{
+       struct allegro_dev *dev = channel->dev;
+       struct allegro_buffer *buffer, *tmp;
+
+       list_for_each_entry_safe(buffer, tmp, list, head) {
+               list_del(&buffer->head);
+               allegro_free_buffer(dev, buffer);
+               kfree(buffer);
+       }
+}
+
+static void destroy_reference_buffers(struct allegro_channel *channel)
+{
+       return destroy_buffers_internal(channel, &channel->buffers_reference);
+}
+
+static void destroy_intermediate_buffers(struct allegro_channel *channel)
+{
+       return destroy_buffers_internal(channel,
+                                       &channel->buffers_intermediate);
+}
+
+static int allocate_intermediate_buffers(struct allegro_channel *channel,
+                                        size_t n, size_t size)
+{
+       return allocate_buffers_internal(channel,
+                                        &channel->buffers_intermediate,
+                                        n, size);
+}
+
+static int allocate_reference_buffers(struct allegro_channel *channel,
+                                     size_t n, size_t size)
+{
+       return allocate_buffers_internal(channel,
+                                        &channel->buffers_reference,
+                                        n, PAGE_ALIGN(size));
+}
+
+static ssize_t allegro_h264_write_sps(struct allegro_channel *channel,
+                                     void *dest, size_t n)
+{
+       struct allegro_dev *dev = channel->dev;
+       struct nal_h264_sps *sps;
+       ssize_t size;
+       unsigned int size_mb = SIZE_MACROBLOCK;
+       /* Calculation of crop units in Rec. ITU-T H.264 (04/2017) p. 76 */
+       unsigned int crop_unit_x = 2;
+       unsigned int crop_unit_y = 2;
+
+       sps = kzalloc(sizeof(*sps), GFP_KERNEL);
+       if (!sps)
+               return -ENOMEM;
+
+       sps->profile_idc = nal_h264_profile_from_v4l2(channel->profile);
+       sps->constraint_set0_flag = 0;
+       sps->constraint_set1_flag = 1;
+       sps->constraint_set2_flag = 0;
+       sps->constraint_set3_flag = 0;
+       sps->constraint_set4_flag = 0;
+       sps->constraint_set5_flag = 0;
+       sps->level_idc = nal_h264_level_from_v4l2(channel->level);
+       sps->seq_parameter_set_id = 0;
+       sps->log2_max_frame_num_minus4 = 0;
+       sps->pic_order_cnt_type = 0;
+       sps->log2_max_pic_order_cnt_lsb_minus4 = 6;
+       sps->max_num_ref_frames = 3;
+       sps->gaps_in_frame_num_value_allowed_flag = 0;
+       sps->pic_width_in_mbs_minus1 =
+               DIV_ROUND_UP(channel->width, size_mb) - 1;
+       sps->pic_height_in_map_units_minus1 =
+               DIV_ROUND_UP(channel->height, size_mb) - 1;
+       sps->frame_mbs_only_flag = 1;
+       sps->mb_adaptive_frame_field_flag = 0;
+       sps->direct_8x8_inference_flag = 1;
+       sps->frame_cropping_flag =
+               (channel->width % size_mb) || (channel->height % size_mb);
+       if (sps->frame_cropping_flag) {
+               sps->crop_left = 0;
+               sps->crop_right = (round_up(channel->width, size_mb) - channel->width) / crop_unit_x;
+               sps->crop_top = 0;
+               sps->crop_bottom = (round_up(channel->height, size_mb) - channel->height) / crop_unit_y;
+       }
+       sps->vui_parameters_present_flag = 1;
+       sps->vui.aspect_ratio_info_present_flag = 0;
+       sps->vui.overscan_info_present_flag = 0;
+       sps->vui.video_signal_type_present_flag = 1;
+       sps->vui.video_format = 1;
+       sps->vui.video_full_range_flag = 0;
+       sps->vui.colour_description_present_flag = 1;
+       sps->vui.colour_primaries = 5;
+       sps->vui.transfer_characteristics = 5;
+       sps->vui.matrix_coefficients = 5;
+       sps->vui.chroma_loc_info_present_flag = 1;
+       sps->vui.chroma_sample_loc_type_top_field = 0;
+       sps->vui.chroma_sample_loc_type_bottom_field = 0;
+
+       sps->vui.timing_info_present_flag = 1;
+       sps->vui.num_units_in_tick = channel->framerate.denominator;
+       sps->vui.time_scale = 2 * channel->framerate.numerator;
+
+       sps->vui.fixed_frame_rate_flag = 1;
+       sps->vui.nal_hrd_parameters_present_flag = 0;
+       sps->vui.vcl_hrd_parameters_present_flag = 1;
+       sps->vui.vcl_hrd_parameters.cpb_cnt_minus1 = 0;
+       sps->vui.vcl_hrd_parameters.bit_rate_scale = 0;
+       sps->vui.vcl_hrd_parameters.cpb_size_scale = 1;
+       /* See Rec. ITU-T H.264 (04/2017) p. 410 E-53 */
+       sps->vui.vcl_hrd_parameters.bit_rate_value_minus1[0] =
+               channel->bitrate_peak / (1 << (6 + sps->vui.vcl_hrd_parameters.bit_rate_scale)) - 1;
+       /* See Rec. ITU-T H.264 (04/2017) p. 410 E-54 */
+       sps->vui.vcl_hrd_parameters.cpb_size_value_minus1[0] =
+               (channel->cpb_size * 1000) / (1 << (4 + sps->vui.vcl_hrd_parameters.cpb_size_scale)) - 1;
+       sps->vui.vcl_hrd_parameters.cbr_flag[0] =
+               !v4l2_ctrl_g_ctrl(channel->mpeg_video_frame_rc_enable);
+       sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 = 31;
+       sps->vui.vcl_hrd_parameters.cpb_removal_delay_length_minus1 = 31;
+       sps->vui.vcl_hrd_parameters.dpb_output_delay_length_minus1 = 31;
+       sps->vui.vcl_hrd_parameters.time_offset_length = 0;
+       sps->vui.low_delay_hrd_flag = 0;
+       sps->vui.pic_struct_present_flag = 1;
+       sps->vui.bitstream_restriction_flag = 0;
+
+       size = nal_h264_write_sps(&dev->plat_dev->dev, dest, n, sps);
+
+       kfree(sps);
+
+       return size;
+}
+
+static ssize_t allegro_h264_write_pps(struct allegro_channel *channel,
+                                     void *dest, size_t n)
+{
+       struct allegro_dev *dev = channel->dev;
+       struct nal_h264_pps *pps;
+       ssize_t size;
+
+       pps = kzalloc(sizeof(*pps), GFP_KERNEL);
+       if (!pps)
+               return -ENOMEM;
+
+       pps->pic_parameter_set_id = 0;
+       pps->seq_parameter_set_id = 0;
+       pps->entropy_coding_mode_flag = 0;
+       pps->bottom_field_pic_order_in_frame_present_flag = 0;
+       pps->num_slice_groups_minus1 = 0;
+       pps->num_ref_idx_l0_default_active_minus1 = channel->num_ref_idx_l0 - 1;
+       pps->num_ref_idx_l1_default_active_minus1 = channel->num_ref_idx_l1 - 1;
+       pps->weighted_pred_flag = 0;
+       pps->weighted_bipred_idc = 0;
+       pps->pic_init_qp_minus26 = 0;
+       pps->pic_init_qs_minus26 = 0;
+       pps->chroma_qp_index_offset = 0;
+       pps->deblocking_filter_control_present_flag = 1;
+       pps->constrained_intra_pred_flag = 0;
+       pps->redundant_pic_cnt_present_flag = 0;
+       pps->transform_8x8_mode_flag = 0;
+       pps->pic_scaling_matrix_present_flag = 0;
+       pps->second_chroma_qp_index_offset = 0;
+
+       size = nal_h264_write_pps(&dev->plat_dev->dev, dest, n, pps);
+
+       kfree(pps);
+
+       return size;
+}
+
+static bool allegro_channel_is_at_eos(struct allegro_channel *channel)
+{
+       bool is_at_eos = false;
+
+       switch (allegro_get_state(channel)) {
+       case ALLEGRO_STATE_STOPPED:
+               is_at_eos = true;
+               break;
+       case ALLEGRO_STATE_DRAIN:
+       case ALLEGRO_STATE_WAIT_FOR_BUFFER:
+               mutex_lock(&channel->shadow_list_lock);
+               if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) == 0 &&
+                   list_empty(&channel->source_shadow_list))
+                       is_at_eos = true;
+               mutex_unlock(&channel->shadow_list_lock);
+               break;
+       default:
+               break;
+       }
+
+       return is_at_eos;
+}
+
+static void allegro_channel_buf_done(struct allegro_channel *channel,
+                                    struct vb2_v4l2_buffer *buf,
+                                    enum vb2_buffer_state state)
+{
+       const struct v4l2_event eos_event = {
+               .type = V4L2_EVENT_EOS
+       };
+
+       if (allegro_channel_is_at_eos(channel)) {
+               buf->flags |= V4L2_BUF_FLAG_LAST;
+               v4l2_event_queue_fh(&channel->fh, &eos_event);
+
+               allegro_set_state(channel, ALLEGRO_STATE_STOPPED);
+       }
+
+       v4l2_m2m_buf_done(buf, state);
+}
+
+static u64 allegro_put_buffer(struct allegro_channel *channel,
+                             struct list_head *list,
+                             struct vb2_v4l2_buffer *buffer)
+{
+       struct v4l2_m2m_buffer *b = container_of(buffer,
+                                                struct v4l2_m2m_buffer, vb);
+       struct allegro_m2m_buffer *shadow = to_allegro_m2m_buffer(b);
+
+       mutex_lock(&channel->shadow_list_lock);
+       list_add_tail(&shadow->head, list);
+       mutex_unlock(&channel->shadow_list_lock);
+
+       return ptr_to_u64(buffer);
+}
+
+static struct vb2_v4l2_buffer *
+allegro_get_buffer(struct allegro_channel *channel,
+                  struct list_head *list, u64 handle)
+{
+       struct allegro_m2m_buffer *shadow, *tmp;
+       struct vb2_v4l2_buffer *buffer = NULL;
+
+       mutex_lock(&channel->shadow_list_lock);
+       list_for_each_entry_safe(shadow, tmp, list, head) {
+               if (handle == ptr_to_u64(&shadow->buf.vb)) {
+                       buffer = &shadow->buf.vb;
+                       list_del_init(&shadow->head);
+                       break;
+               }
+       }
+       mutex_unlock(&channel->shadow_list_lock);
+
+       return buffer;
+}
+
+static void allegro_channel_finish_frame(struct allegro_channel *channel,
+               struct mcu_msg_encode_frame_response *msg)
+{
+       struct allegro_dev *dev = channel->dev;
+       struct vb2_v4l2_buffer *src_buf;
+       struct vb2_v4l2_buffer *dst_buf;
+       struct {
+               u32 offset;
+               u32 size;
+       } *partition;
+       enum vb2_buffer_state state = VB2_BUF_STATE_ERROR;
+       char *curr;
+       ssize_t len;
+       ssize_t free;
+
+       src_buf = allegro_get_buffer(channel, &channel->source_shadow_list,
+                                    msg->src_handle);
+       if (!src_buf)
+               v4l2_warn(&dev->v4l2_dev,
+                         "channel %d: invalid source buffer\n",
+                         channel->mcu_channel_id);
+
+       dst_buf = allegro_get_buffer(channel, &channel->stream_shadow_list,
+                                    msg->stream_id);
+       if (!dst_buf)
+               v4l2_warn(&dev->v4l2_dev,
+                         "channel %d: invalid stream buffer\n",
+                         channel->mcu_channel_id);
+
+       if (!src_buf || !dst_buf)
+               goto err;
+
+       dst_buf->sequence = channel->csequence++;
+
+       if (msg->error_code & AL_ERROR) {
+               v4l2_err(&dev->v4l2_dev,
+                        "channel %d: failed to encode frame: %s (%x)\n",
+                        channel->mcu_channel_id,
+                        allegro_err_to_string(msg->error_code),
+                        msg->error_code);
+               goto err;
+       }
+
+       if (msg->partition_table_size != 1) {
+               v4l2_warn(&dev->v4l2_dev,
+                         "channel %d: only handling first partition table entry (%d entries)\n",
+                         channel->mcu_channel_id, msg->partition_table_size);
+       }
+
+       if (msg->partition_table_offset +
+           msg->partition_table_size * sizeof(*partition) >
+           vb2_plane_size(&dst_buf->vb2_buf, 0)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "channel %d: partition table outside of dst_buf\n",
+                        channel->mcu_channel_id);
+               goto err;
+       }
+
+       partition =
+           vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + msg->partition_table_offset;
+       if (partition->offset + partition->size >
+           vb2_plane_size(&dst_buf->vb2_buf, 0)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "channel %d: encoded frame is outside of dst_buf (offset 0x%x, size 0x%x)\n",
+                        channel->mcu_channel_id, partition->offset,
+                        partition->size);
+               goto err;
+       }
+
+       v4l2_dbg(2, debug, &dev->v4l2_dev,
+                "channel %d: encoded frame of size %d is at offset 0x%x\n",
+                channel->mcu_channel_id, partition->size, partition->offset);
+
+       /*
+        * The payload must include the data before the partition offset,
+        * because we will put the sps and pps data there.
+        */
+       vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
+                             partition->offset + partition->size);
+
+       curr = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
+       free = partition->offset;
+       if (msg->is_idr) {
+               len = allegro_h264_write_sps(channel, curr, free);
+               if (len < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "not enough space for sequence parameter set: %zd left\n",
+                                free);
+                       goto err;
+               }
+               curr += len;
+               free -= len;
+               v4l2_dbg(1, debug, &dev->v4l2_dev,
+                        "channel %d: wrote %zd byte SPS nal unit\n",
+                        channel->mcu_channel_id, len);
+       }
+
+       if (msg->slice_type == AL_ENC_SLICE_TYPE_I) {
+               len = allegro_h264_write_pps(channel, curr, free);
+               if (len < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "not enough space for picture parameter set: %zd left\n",
+                                free);
+                       goto err;
+               }
+               curr += len;
+               free -= len;
+               v4l2_dbg(1, debug, &dev->v4l2_dev,
+                        "channel %d: wrote %zd byte PPS nal unit\n",
+                        channel->mcu_channel_id, len);
+       }
+
+       if (msg->slice_type != AL_ENC_SLICE_TYPE_I && !msg->is_idr) {
+               dst_buf->vb2_buf.planes[0].data_offset = free;
+               free = 0;
+       } else {
+               len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free);
+               if (len < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "failed to write %zd filler data\n", free);
+                       goto err;
+               }
+               curr += len;
+               free -= len;
+               v4l2_dbg(2, debug, &dev->v4l2_dev,
+                        "channel %d: wrote %zd bytes filler nal unit\n",
+                        channel->mcu_channel_id, len);
+       }
+
+       if (free != 0) {
+               v4l2_err(&dev->v4l2_dev,
+                        "non-VCL NAL units do not fill space until VCL NAL unit: %zd bytes left\n",
+                        free);
+               goto err;
+       }
+
+       state = VB2_BUF_STATE_DONE;
+
+       v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
+       if (msg->is_idr)
+               dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+       else
+               dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "channel %d: encoded frame #%03d (%s%s, QP %d, %d bytes)\n",
+                channel->mcu_channel_id,
+                dst_buf->sequence,
+                msg->is_idr ? "IDR, " : "",
+                msg->slice_type == AL_ENC_SLICE_TYPE_I ? "I slice" :
+                msg->slice_type == AL_ENC_SLICE_TYPE_P ? "P slice" : "unknown",
+                msg->qp, partition->size);
+
+err:
+       if (src_buf)
+               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+
+       if (dst_buf)
+               allegro_channel_buf_done(channel, dst_buf, state);
+}
+
+static int allegro_handle_init(struct allegro_dev *dev,
+                              struct mcu_msg_init_response *msg)
+{
+       complete(&dev->init_complete);
+
+       return 0;
+}
+
+static int
+allegro_handle_create_channel(struct allegro_dev *dev,
+                             struct mcu_msg_create_channel_response *msg)
+{
+       struct allegro_channel *channel;
+       int err = 0;
+       struct create_channel_param param;
+
+       channel = allegro_find_channel_by_user_id(dev, msg->user_id);
+       if (IS_ERR(channel)) {
+               v4l2_warn(&dev->v4l2_dev,
+                         "received %s for unknown user %d\n",
+                         msg_type_name(msg->header.type),
+                         msg->user_id);
+               return -EINVAL;
+       }
+
+       if (msg->error_code) {
+               v4l2_err(&dev->v4l2_dev,
+                        "user %d: mcu failed to create channel: %s (%x)\n",
+                        channel->user_id,
+                        allegro_err_to_string(msg->error_code),
+                        msg->error_code);
+               err = -EIO;
+               goto out;
+       }
+
+       channel->mcu_channel_id = msg->channel_id;
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "user %d: channel has channel id %d\n",
+                channel->user_id, channel->mcu_channel_id);
+
+       err = allegro_decode_config_blob(&param, msg, channel->config_blob.vaddr);
+       allegro_free_buffer(channel->dev, &channel->config_blob);
+       if (err)
+               goto out;
+
+       channel->num_ref_idx_l0 = param.num_ref_idx_l0;
+       channel->num_ref_idx_l1 = param.num_ref_idx_l1;
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "channel %d: intermediate buffers: %d x %d bytes\n",
+                channel->mcu_channel_id,
+                msg->int_buffers_count, msg->int_buffers_size);
+       err = allocate_intermediate_buffers(channel, msg->int_buffers_count,
+                                           msg->int_buffers_size);
+       if (err) {
+               v4l2_err(&dev->v4l2_dev,
+                        "channel %d: failed to allocate intermediate buffers\n",
+                        channel->mcu_channel_id);
+               goto out;
+       }
+       err = allegro_mcu_push_buffer_intermediate(channel);
+       if (err)
+               goto out;
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "channel %d: reference buffers: %d x %d bytes\n",
+                channel->mcu_channel_id,
+                msg->rec_buffers_count, msg->rec_buffers_size);
+       err = allocate_reference_buffers(channel, msg->rec_buffers_count,
+                                        msg->rec_buffers_size);
+       if (err) {
+               v4l2_err(&dev->v4l2_dev,
+                        "channel %d: failed to allocate reference buffers\n",
+                        channel->mcu_channel_id);
+               goto out;
+       }
+       err = allegro_mcu_push_buffer_reference(channel);
+       if (err)
+               goto out;
+
+out:
+       channel->error = err;
+       complete(&channel->completion);
+
+       /* Handled successfully, error is passed via channel->error */
+       return 0;
+}
+
+static int
+allegro_handle_destroy_channel(struct allegro_dev *dev,
+                              struct mcu_msg_destroy_channel_response *msg)
+{
+       struct allegro_channel *channel;
+
+       channel = allegro_find_channel_by_channel_id(dev, msg->channel_id);
+       if (IS_ERR(channel)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "received %s for unknown channel %d\n",
+                        msg_type_name(msg->header.type),
+                        msg->channel_id);
+               return -EINVAL;
+       }
+
+       v4l2_dbg(2, debug, &dev->v4l2_dev,
+                "user %d: vcu destroyed channel %d\n",
+                channel->user_id, channel->mcu_channel_id);
+       complete(&channel->completion);
+
+       return 0;
+}
+
+static int
+allegro_handle_encode_frame(struct allegro_dev *dev,
+                           struct mcu_msg_encode_frame_response *msg)
+{
+       struct allegro_channel *channel;
+
+       channel = allegro_find_channel_by_channel_id(dev, msg->channel_id);
+       if (IS_ERR(channel)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "received %s for unknown channel %d\n",
+                        msg_type_name(msg->header.type),
+                        msg->channel_id);
+               return -EINVAL;
+       }
+
+       allegro_channel_finish_frame(channel, msg);
+
+       return 0;
+}
+
+static void allegro_handle_message(struct allegro_dev *dev,
+                                  union mcu_msg_response *msg)
+{
+       switch (msg->header.type) {
+       case MCU_MSG_TYPE_INIT:
+               allegro_handle_init(dev, &msg->init);
+               break;
+       case MCU_MSG_TYPE_CREATE_CHANNEL:
+               allegro_handle_create_channel(dev, &msg->create_channel);
+               break;
+       case MCU_MSG_TYPE_DESTROY_CHANNEL:
+               allegro_handle_destroy_channel(dev, &msg->destroy_channel);
+               break;
+       case MCU_MSG_TYPE_ENCODE_FRAME:
+               allegro_handle_encode_frame(dev, &msg->encode_frame);
+               break;
+       default:
+               v4l2_warn(&dev->v4l2_dev,
+                         "%s: unknown message %s\n",
+                         __func__, msg_type_name(msg->header.type));
+               break;
+       }
+}
+
+static irqreturn_t allegro_hardirq(int irq, void *data)
+{
+       struct allegro_dev *dev = data;
+       unsigned int status;
+
+       regmap_read(dev->regmap, AL5_ITC_CPU_IRQ_STA, &status);
+       if (!(status & AL5_ITC_CPU_IRQ_STA_TRIGGERED))
+               return IRQ_NONE;
+
+       regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_CLR, status);
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t allegro_irq_thread(int irq, void *data)
+{
+       struct allegro_dev *dev = data;
+
+       allegro_mbox_notify(dev->mbox_status);
+
+       return IRQ_HANDLED;
+}
+
+static void allegro_copy_firmware(struct allegro_dev *dev,
+                                 const u8 * const buf, size_t size)
+{
+       int err = 0;
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "copy mcu firmware (%zu B) to SRAM\n", size);
+       err = regmap_bulk_write(dev->sram, 0x0, buf, size / 4);
+       if (err)
+               v4l2_err(&dev->v4l2_dev,
+                        "failed to copy firmware: %d\n", err);
+}
+
+static void allegro_copy_fw_codec(struct allegro_dev *dev,
+                                 const u8 * const buf, size_t size)
+{
+       int err;
+       dma_addr_t icache_offset, dcache_offset;
+
+       /*
+        * The downstream allocates 600 KB for the codec firmware to have some
+        * extra space for "possible extensions." My tests were fine with
+        * allocating just enough memory for the actual firmware, but I am not
+        * sure that the firmware really does not use the remaining space.
+        */
+       err = allegro_alloc_buffer(dev, &dev->firmware, size);
+       if (err) {
+               v4l2_err(&dev->v4l2_dev,
+                        "failed to allocate %zu bytes for firmware\n", size);
+               return;
+       }
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "copy codec firmware (%zd B) to phys %pad\n",
+                size, &dev->firmware.paddr);
+       memcpy(dev->firmware.vaddr, buf, size);
+
+       regmap_write(dev->regmap, AXI_ADDR_OFFSET_IP,
+                    upper_32_bits(dev->firmware.paddr));
+
+       icache_offset = dev->firmware.paddr - MCU_CACHE_OFFSET;
+       v4l2_dbg(2, debug, &dev->v4l2_dev,
+                "icache_offset: msb = 0x%x, lsb = 0x%x\n",
+                upper_32_bits(icache_offset), lower_32_bits(icache_offset));
+       regmap_write(dev->regmap, AL5_ICACHE_ADDR_OFFSET_MSB,
+                    upper_32_bits(icache_offset));
+       regmap_write(dev->regmap, AL5_ICACHE_ADDR_OFFSET_LSB,
+                    lower_32_bits(icache_offset));
+
+       dcache_offset =
+           (dev->firmware.paddr & 0xffffffff00000000ULL) - MCU_CACHE_OFFSET;
+       v4l2_dbg(2, debug, &dev->v4l2_dev,
+                "dcache_offset: msb = 0x%x, lsb = 0x%x\n",
+                upper_32_bits(dcache_offset), lower_32_bits(dcache_offset));
+       regmap_write(dev->regmap, AL5_DCACHE_ADDR_OFFSET_MSB,
+                    upper_32_bits(dcache_offset));
+       regmap_write(dev->regmap, AL5_DCACHE_ADDR_OFFSET_LSB,
+                    lower_32_bits(dcache_offset));
+}
+
+static void allegro_free_fw_codec(struct allegro_dev *dev)
+{
+       allegro_free_buffer(dev, &dev->firmware);
+}
+
+/*
+ * Control functions for the MCU
+ */
+
+static int allegro_mcu_enable_interrupts(struct allegro_dev *dev)
+{
+       return regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_MSK, BIT(0));
+}
+
+static int allegro_mcu_disable_interrupts(struct allegro_dev *dev)
+{
+       return regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_MSK, 0);
+}
+
+static int allegro_mcu_wait_for_sleep(struct allegro_dev *dev)
+{
+       unsigned long timeout;
+       unsigned int status;
+
+       timeout = jiffies + msecs_to_jiffies(100);
+       while (regmap_read(dev->regmap, AL5_MCU_STA, &status) == 0 &&
+              status != AL5_MCU_STA_SLEEP) {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+               cpu_relax();
+       }
+
+       return 0;
+}
+
+static int allegro_mcu_start(struct allegro_dev *dev)
+{
+       unsigned long timeout;
+       unsigned int status;
+       int err;
+
+       err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, BIT(0));
+       if (err)
+               return err;
+
+       timeout = jiffies + msecs_to_jiffies(100);
+       while (regmap_read(dev->regmap, AL5_MCU_STA, &status) == 0 &&
+              status == AL5_MCU_STA_SLEEP) {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+               cpu_relax();
+       }
+
+       err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, 0);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int allegro_mcu_reset(struct allegro_dev *dev)
+{
+       int err;
+
+       /*
+        * Ensure that the AL5_MCU_WAKEUP bit is set to 0 otherwise the mcu
+        * does not go to sleep after the reset.
+        */
+       err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, 0);
+       if (err)
+               return err;
+
+       err = regmap_write(dev->regmap,
+                          AL5_MCU_RESET_MODE, AL5_MCU_RESET_MODE_SLEEP);
+       if (err < 0)
+               return err;
+
+       err = regmap_write(dev->regmap, AL5_MCU_RESET, AL5_MCU_RESET_SOFT);
+       if (err < 0)
+               return err;
+
+       return allegro_mcu_wait_for_sleep(dev);
+}
+
+static void allegro_mcu_interrupt(struct allegro_dev *dev)
+{
+       regmap_write(dev->regmap, AL5_MCU_INTERRUPT, BIT(0));
+}
+
+static void allegro_destroy_channel(struct allegro_channel *channel)
+{
+       struct allegro_dev *dev = channel->dev;
+       unsigned long timeout;
+
+       if (channel_exists(channel)) {
+               reinit_completion(&channel->completion);
+               allegro_mcu_send_destroy_channel(dev, channel);
+               timeout = wait_for_completion_timeout(&channel->completion,
+                                                     msecs_to_jiffies(5000));
+               if (timeout == 0)
+                       v4l2_warn(&dev->v4l2_dev,
+                                 "channel %d: timeout while destroying\n",
+                                 channel->mcu_channel_id);
+
+               channel->mcu_channel_id = -1;
+       }
+
+       destroy_intermediate_buffers(channel);
+       destroy_reference_buffers(channel);
+
+       v4l2_ctrl_grab(channel->mpeg_video_h264_profile, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_level, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_i_frame_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_max_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, false);
+       v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, false);
+       v4l2_ctrl_grab(channel->mpeg_video_bitrate, false);
+       v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, false);
+       v4l2_ctrl_grab(channel->mpeg_video_cpb_size, false);
+       v4l2_ctrl_grab(channel->mpeg_video_gop_size, false);
+
+       if (channel->user_id != -1) {
+               clear_bit(channel->user_id, &dev->channel_user_ids);
+               channel->user_id = -1;
+       }
+}
+
+/*
+ * Create the MCU channel
+ *
+ * After the channel has been created, the picture size, format, colorspace
+ * and framerate are fixed. Also the codec, profile, bitrate, etc. cannot be
+ * changed anymore.
+ *
+ * The channel can be created only once. The MCU will accept source buffers
+ * and stream buffers only after a channel has been created.
+ */
+static int allegro_create_channel(struct allegro_channel *channel)
+{
+       struct allegro_dev *dev = channel->dev;
+       unsigned long timeout;
+       enum v4l2_mpeg_video_h264_level min_level;
+
+       if (channel_exists(channel)) {
+               v4l2_warn(&dev->v4l2_dev,
+                         "channel already exists\n");
+               return 0;
+       }
+
+       channel->user_id = allegro_next_user_id(dev);
+       if (channel->user_id < 0) {
+               v4l2_err(&dev->v4l2_dev,
+                        "no free channels available\n");
+               return -EBUSY;
+       }
+       set_bit(channel->user_id, &dev->channel_user_ids);
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "user %d: creating channel (%4.4s, %dx%d@%d)\n",
+                channel->user_id,
+                (char *)&channel->codec, channel->width, channel->height,
+                DIV_ROUND_UP(channel->framerate.numerator,
+                             channel->framerate.denominator));
+
+       min_level = select_minimum_h264_level(channel->width, channel->height);
+       if (channel->level < min_level) {
+               v4l2_warn(&dev->v4l2_dev,
+                         "user %d: selected Level %s too low: increasing to Level %s\n",
+                         channel->user_id,
+                         v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL)[channel->level],
+                         v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL)[min_level]);
+               channel->level = min_level;
+       }
+
+       v4l2_ctrl_grab(channel->mpeg_video_h264_profile, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_level, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_i_frame_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_max_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, true);
+       v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, true);
+       v4l2_ctrl_grab(channel->mpeg_video_bitrate, true);
+       v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, true);
+       v4l2_ctrl_grab(channel->mpeg_video_cpb_size, true);
+       v4l2_ctrl_grab(channel->mpeg_video_gop_size, true);
+
+       reinit_completion(&channel->completion);
+       allegro_mcu_send_create_channel(dev, channel);
+       timeout = wait_for_completion_timeout(&channel->completion,
+                                             msecs_to_jiffies(5000));
+       if (timeout == 0)
+               channel->error = -ETIMEDOUT;
+       if (channel->error)
+               goto err;
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "channel %d: accepting buffers\n",
+                channel->mcu_channel_id);
+
+       return 0;
+
+err:
+       allegro_destroy_channel(channel);
+
+       return channel->error;
+}
+
+static void allegro_set_default_params(struct allegro_channel *channel)
+{
+       channel->width = ALLEGRO_WIDTH_DEFAULT;
+       channel->height = ALLEGRO_HEIGHT_DEFAULT;
+       channel->stride = round_up(channel->width, 32);
+       channel->framerate = ALLEGRO_FRAMERATE_DEFAULT;
+
+       channel->colorspace = V4L2_COLORSPACE_REC709;
+       channel->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       channel->quantization = V4L2_QUANTIZATION_DEFAULT;
+       channel->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+       channel->pixelformat = V4L2_PIX_FMT_NV12;
+       channel->sizeimage_raw = channel->stride * channel->height * 3 / 2;
+
+       channel->codec = V4L2_PIX_FMT_H264;
+       channel->profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+       channel->level =
+               select_minimum_h264_level(channel->width, channel->height);
+       channel->sizeimage_encoded =
+               estimate_stream_size(channel->width, channel->height);
+
+       channel->bitrate = maximum_bitrate(channel->level);
+       channel->bitrate_peak = maximum_bitrate(channel->level);
+       channel->cpb_size = maximum_cpb_size(channel->level);
+       channel->gop_size = ALLEGRO_GOP_SIZE_DEFAULT;
+}
+
+static int allegro_queue_setup(struct vb2_queue *vq,
+                              unsigned int *nbuffers, unsigned int *nplanes,
+                              unsigned int sizes[],
+                              struct device *alloc_devs[])
+{
+       struct allegro_channel *channel = vb2_get_drv_priv(vq);
+       struct allegro_dev *dev = channel->dev;
+
+       v4l2_dbg(2, debug, &dev->v4l2_dev,
+                "%s: queue setup[%s]: nplanes = %d\n",
+                V4L2_TYPE_IS_OUTPUT(vq->type) ? "output" : "capture",
+                *nplanes == 0 ? "REQBUFS" : "CREATE_BUFS", *nplanes);
+
+       if (*nplanes != 0) {
+               if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+                       if (sizes[0] < channel->sizeimage_raw)
+                               return -EINVAL;
+               } else {
+                       if (sizes[0] < channel->sizeimage_encoded)
+                               return -EINVAL;
+               }
+       } else {
+               *nplanes = 1;
+               if (V4L2_TYPE_IS_OUTPUT(vq->type))
+                       sizes[0] = channel->sizeimage_raw;
+               else
+                       sizes[0] = channel->sizeimage_encoded;
+       }
+
+       return 0;
+}
+
+static int allegro_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct allegro_channel *channel = vb2_get_drv_priv(vb->vb2_queue);
+       struct allegro_dev *dev = channel->dev;
+
+       if (allegro_get_state(channel) == ALLEGRO_STATE_DRAIN &&
+           V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
+               return -EBUSY;
+
+       if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+               if (vbuf->field == V4L2_FIELD_ANY)
+                       vbuf->field = V4L2_FIELD_NONE;
+               if (vbuf->field != V4L2_FIELD_NONE) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "channel %d: unsupported field\n",
+                                channel->mcu_channel_id);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void allegro_buf_queue(struct vb2_buffer *vb)
+{
+       struct allegro_channel *channel = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+       if (allegro_get_state(channel) == ALLEGRO_STATE_WAIT_FOR_BUFFER &&
+           vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               allegro_channel_buf_done(channel, vbuf, VB2_BUF_STATE_DONE);
+               return;
+       }
+
+       v4l2_m2m_buf_queue(channel->fh.m2m_ctx, vbuf);
+}
+
+static int allegro_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct allegro_channel *channel = vb2_get_drv_priv(q);
+       struct allegro_dev *dev = channel->dev;
+
+       v4l2_dbg(2, debug, &dev->v4l2_dev,
+                "%s: start streaming\n",
+                V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture");
+
+       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+               channel->osequence = 0;
+               allegro_set_state(channel, ALLEGRO_STATE_ENCODING);
+       } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               channel->csequence = 0;
+       }
+
+       return 0;
+}
+
+static void allegro_stop_streaming(struct vb2_queue *q)
+{
+       struct allegro_channel *channel = vb2_get_drv_priv(q);
+       struct allegro_dev *dev = channel->dev;
+       struct vb2_v4l2_buffer *buffer;
+       struct allegro_m2m_buffer *shadow, *tmp;
+
+       v4l2_dbg(2, debug, &dev->v4l2_dev,
+                "%s: stop streaming\n",
+                V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture");
+
+       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+               mutex_lock(&channel->shadow_list_lock);
+               list_for_each_entry_safe(shadow, tmp,
+                                        &channel->source_shadow_list, head) {
+                       list_del(&shadow->head);
+                       v4l2_m2m_buf_done(&shadow->buf.vb, VB2_BUF_STATE_ERROR);
+               }
+               mutex_unlock(&channel->shadow_list_lock);
+
+               allegro_set_state(channel, ALLEGRO_STATE_STOPPED);
+               while ((buffer = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR);
+       } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               mutex_lock(&channel->shadow_list_lock);
+               list_for_each_entry_safe(shadow, tmp,
+                                        &channel->stream_shadow_list, head) {
+                       list_del(&shadow->head);
+                       v4l2_m2m_buf_done(&shadow->buf.vb, VB2_BUF_STATE_ERROR);
+               }
+               mutex_unlock(&channel->shadow_list_lock);
+
+               allegro_destroy_channel(channel);
+               while ((buffer = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR);
+       }
+}
+
+static const struct vb2_ops allegro_queue_ops = {
+       .queue_setup = allegro_queue_setup,
+       .buf_prepare = allegro_buf_prepare,
+       .buf_queue = allegro_buf_queue,
+       .start_streaming = allegro_start_streaming,
+       .stop_streaming = allegro_stop_streaming,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+};
+
+static int allegro_queue_init(void *priv,
+                             struct vb2_queue *src_vq,
+                             struct vb2_queue *dst_vq)
+{
+       int err;
+       struct allegro_channel *channel = priv;
+
+       src_vq->dev = &channel->dev->plat_dev->dev;
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+       src_vq->drv_priv = channel;
+       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->ops = &allegro_queue_ops;
+       src_vq->buf_struct_size = sizeof(struct allegro_m2m_buffer);
+       src_vq->lock = &channel->dev->lock;
+       err = vb2_queue_init(src_vq);
+       if (err)
+               return err;
+
+       dst_vq->dev = &channel->dev->plat_dev->dev;
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+       dst_vq->drv_priv = channel;
+       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->ops = &allegro_queue_ops;
+       dst_vq->buf_struct_size = sizeof(struct allegro_m2m_buffer);
+       dst_vq->lock = &channel->dev->lock;
+       err = vb2_queue_init(dst_vq);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int allegro_clamp_qp(struct allegro_channel *channel,
+                           struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_ctrl *next_ctrl;
+
+       if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP)
+               next_ctrl = channel->mpeg_video_h264_p_frame_qp;
+       else if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP)
+               next_ctrl = channel->mpeg_video_h264_b_frame_qp;
+       else
+               return 0;
+
+       /* Modify range automatically updates the value */
+       __v4l2_ctrl_modify_range(next_ctrl, ctrl->val, 51, 1, ctrl->val);
+
+       return allegro_clamp_qp(channel, next_ctrl);
+}
+
+static int allegro_clamp_bitrate(struct allegro_channel *channel,
+                                struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_ctrl *ctrl_bitrate = channel->mpeg_video_bitrate;
+       struct v4l2_ctrl *ctrl_bitrate_peak = channel->mpeg_video_bitrate_peak;
+
+       if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+           ctrl_bitrate_peak->val < ctrl_bitrate->val)
+               ctrl_bitrate_peak->val = ctrl_bitrate->val;
+
+       return 0;
+}
+
+static int allegro_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct allegro_channel *channel = container_of(ctrl->handler,
+                                                      struct allegro_channel,
+                                                      ctrl_handler);
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               allegro_clamp_bitrate(channel, ctrl);
+               break;
+       }
+
+       return 0;
+}
+
+static int allegro_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct allegro_channel *channel = container_of(ctrl->handler,
+                                                      struct allegro_channel,
+                                                      ctrl_handler);
+       struct allegro_dev *dev = channel->dev;
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "s_ctrl: %s = %d\n", v4l2_ctrl_get_name(ctrl->id), ctrl->val);
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+               channel->level = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+               channel->frame_rc_enable = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               channel->bitrate = channel->mpeg_video_bitrate->val;
+               channel->bitrate_peak = channel->mpeg_video_bitrate_peak->val;
+               v4l2_ctrl_activate(channel->mpeg_video_bitrate_peak,
+                                  ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
+               channel->cpb_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               channel->gop_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+               allegro_clamp_qp(channel, ctrl);
+               break;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops allegro_ctrl_ops = {
+       .try_ctrl = allegro_try_ctrl,
+       .s_ctrl = allegro_s_ctrl,
+};
+
+static int allegro_open(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct allegro_dev *dev = video_get_drvdata(vdev);
+       struct allegro_channel *channel = NULL;
+       struct v4l2_ctrl_handler *handler;
+       u64 mask;
+       int ret;
+
+       channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+       if (!channel)
+               return -ENOMEM;
+
+       v4l2_fh_init(&channel->fh, vdev);
+
+       init_completion(&channel->completion);
+       INIT_LIST_HEAD(&channel->source_shadow_list);
+       INIT_LIST_HEAD(&channel->stream_shadow_list);
+       mutex_init(&channel->shadow_list_lock);
+
+       channel->dev = dev;
+
+       allegro_set_default_params(channel);
+
+       handler = &channel->ctrl_handler;
+       v4l2_ctrl_handler_init(handler, 0);
+       channel->mpeg_video_h264_profile = v4l2_ctrl_new_std_menu(handler,
+                       &allegro_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+                       V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0,
+                       V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
+       mask = 1 << V4L2_MPEG_VIDEO_H264_LEVEL_1B;
+       channel->mpeg_video_h264_level = v4l2_ctrl_new_std_menu(handler,
+                       &allegro_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+                       V4L2_MPEG_VIDEO_H264_LEVEL_5_1, mask,
+                       V4L2_MPEG_VIDEO_H264_LEVEL_5_1);
+       channel->mpeg_video_h264_i_frame_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+                                 0, 51, 1, 30);
+       channel->mpeg_video_h264_max_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+                                 0, 51, 1, 51);
+       channel->mpeg_video_h264_min_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+                                 0, 51, 1, 0);
+       channel->mpeg_video_h264_p_frame_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+                                 0, 51, 1, 30);
+       channel->mpeg_video_h264_b_frame_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+                                 0, 51, 1, 30);
+       channel->mpeg_video_frame_rc_enable =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+                                 false, 0x1,
+                                 true, false);
+       channel->mpeg_video_bitrate_mode = v4l2_ctrl_new_std_menu(handler,
+                       &allegro_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+       channel->mpeg_video_bitrate = v4l2_ctrl_new_std(handler,
+                       &allegro_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_BITRATE,
+                       0, maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1),
+                       1, channel->bitrate);
+       channel->mpeg_video_bitrate_peak = v4l2_ctrl_new_std(handler,
+                       &allegro_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+                       0, maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1),
+                       1, channel->bitrate_peak);
+       channel->mpeg_video_cpb_size = v4l2_ctrl_new_std(handler,
+                       &allegro_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
+                       0, maximum_cpb_size(V4L2_MPEG_VIDEO_H264_LEVEL_5_1),
+                       1, channel->cpb_size);
+       channel->mpeg_video_gop_size = v4l2_ctrl_new_std(handler,
+                       &allegro_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+                       0, ALLEGRO_GOP_SIZE_MAX,
+                       1, channel->gop_size);
+       v4l2_ctrl_new_std(handler,
+                         &allegro_ctrl_ops,
+                         V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+                         1, 32,
+                         1, 1);
+       if (handler->error != 0) {
+               ret = handler->error;
+               goto error;
+       }
+
+       channel->fh.ctrl_handler = handler;
+
+       v4l2_ctrl_cluster(3, &channel->mpeg_video_bitrate_mode);
+
+       channel->mcu_channel_id = -1;
+       channel->user_id = -1;
+
+       INIT_LIST_HEAD(&channel->buffers_reference);
+       INIT_LIST_HEAD(&channel->buffers_intermediate);
+
+       channel->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, channel,
+                                               allegro_queue_init);
+
+       if (IS_ERR(channel->fh.m2m_ctx)) {
+               ret = PTR_ERR(channel->fh.m2m_ctx);
+               goto error;
+       }
+
+       list_add(&channel->list, &dev->channels);
+       file->private_data = &channel->fh;
+       v4l2_fh_add(&channel->fh);
+
+       return 0;
+
+error:
+       v4l2_ctrl_handler_free(handler);
+       kfree(channel);
+       return ret;
+}
+
+static int allegro_release(struct file *file)
+{
+       struct allegro_channel *channel = fh_to_channel(file->private_data);
+
+       v4l2_m2m_ctx_release(channel->fh.m2m_ctx);
+
+       list_del(&channel->list);
+
+       v4l2_ctrl_handler_free(&channel->ctrl_handler);
+
+       v4l2_fh_del(&channel->fh);
+       v4l2_fh_exit(&channel->fh);
+
+       kfree(channel);
+
+       return 0;
+}
+
+static int allegro_querycap(struct file *file, void *fh,
+                           struct v4l2_capability *cap)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct allegro_dev *dev = video_get_drvdata(vdev);
+
+       strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+       strscpy(cap->card, "Allegro DVT Video Encoder", sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+                dev_name(&dev->plat_dev->dev));
+
+       return 0;
+}
+
+static int allegro_enum_fmt_vid(struct file *file, void *fh,
+                               struct v4l2_fmtdesc *f)
+{
+       if (f->index)
+               return -EINVAL;
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               f->pixelformat = V4L2_PIX_FMT_NV12;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               f->pixelformat = V4L2_PIX_FMT_H264;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int allegro_g_fmt_vid_cap(struct file *file, void *fh,
+                                struct v4l2_format *f)
+{
+       struct allegro_channel *channel = fh_to_channel(fh);
+
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+       f->fmt.pix.width = channel->width;
+       f->fmt.pix.height = channel->height;
+
+       f->fmt.pix.colorspace = channel->colorspace;
+       f->fmt.pix.ycbcr_enc = channel->ycbcr_enc;
+       f->fmt.pix.quantization = channel->quantization;
+       f->fmt.pix.xfer_func = channel->xfer_func;
+
+       f->fmt.pix.pixelformat = channel->codec;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage = channel->sizeimage_encoded;
+
+       return 0;
+}
+
+static int allegro_try_fmt_vid_cap(struct file *file, void *fh,
+                                  struct v4l2_format *f)
+{
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+
+       f->fmt.pix.width = clamp_t(__u32, f->fmt.pix.width,
+                                  ALLEGRO_WIDTH_MIN, ALLEGRO_WIDTH_MAX);
+       f->fmt.pix.height = clamp_t(__u32, f->fmt.pix.height,
+                                   ALLEGRO_HEIGHT_MIN, ALLEGRO_HEIGHT_MAX);
+
+       f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage =
+               estimate_stream_size(f->fmt.pix.width, f->fmt.pix.height);
+
+       return 0;
+}
+
+static int allegro_g_fmt_vid_out(struct file *file, void *fh,
+                                struct v4l2_format *f)
+{
+       struct allegro_channel *channel = fh_to_channel(fh);
+
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+
+       f->fmt.pix.width = channel->width;
+       f->fmt.pix.height = channel->height;
+
+       f->fmt.pix.colorspace = channel->colorspace;
+       f->fmt.pix.ycbcr_enc = channel->ycbcr_enc;
+       f->fmt.pix.quantization = channel->quantization;
+       f->fmt.pix.xfer_func = channel->xfer_func;
+
+       f->fmt.pix.pixelformat = channel->pixelformat;
+       f->fmt.pix.bytesperline = channel->stride;
+       f->fmt.pix.sizeimage = channel->sizeimage_raw;
+
+       return 0;
+}
+
+static int allegro_try_fmt_vid_out(struct file *file, void *fh,
+                                  struct v4l2_format *f)
+{
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+
+       /*
+        * The firmware of the Allegro codec handles the padding internally
+        * and expects the visual frame size when configuring a channel.
+        * Therefore, unlike other encoder drivers, this driver does not round
+        * up the width and height to macroblock alignment and does not
+        * implement the selection api.
+        */
+       f->fmt.pix.width = clamp_t(__u32, f->fmt.pix.width,
+                                  ALLEGRO_WIDTH_MIN, ALLEGRO_WIDTH_MAX);
+       f->fmt.pix.height = clamp_t(__u32, f->fmt.pix.height,
+                                   ALLEGRO_HEIGHT_MIN, ALLEGRO_HEIGHT_MAX);
+
+       f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
+       f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 32);
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.bytesperline * f->fmt.pix.height * 3 / 2;
+
+       return 0;
+}
+
+static int allegro_s_fmt_vid_out(struct file *file, void *fh,
+                                struct v4l2_format *f)
+{
+       struct allegro_channel *channel = fh_to_channel(fh);
+       int err;
+
+       err = allegro_try_fmt_vid_out(file, fh, f);
+       if (err)
+               return err;
+
+       channel->width = f->fmt.pix.width;
+       channel->height = f->fmt.pix.height;
+       channel->stride = f->fmt.pix.bytesperline;
+       channel->sizeimage_raw = f->fmt.pix.sizeimage;
+
+       channel->colorspace = f->fmt.pix.colorspace;
+       channel->ycbcr_enc = f->fmt.pix.ycbcr_enc;
+       channel->quantization = f->fmt.pix.quantization;
+       channel->xfer_func = f->fmt.pix.xfer_func;
+
+       channel->level =
+               select_minimum_h264_level(channel->width, channel->height);
+       channel->sizeimage_encoded =
+               estimate_stream_size(channel->width, channel->height);
+
+       return 0;
+}
+
+static int allegro_channel_cmd_stop(struct allegro_channel *channel)
+{
+       struct allegro_dev *dev = channel->dev;
+       struct vb2_v4l2_buffer *dst_buf;
+
+       switch (allegro_get_state(channel)) {
+       case ALLEGRO_STATE_DRAIN:
+       case ALLEGRO_STATE_WAIT_FOR_BUFFER:
+               return -EBUSY;
+       case ALLEGRO_STATE_ENCODING:
+               allegro_set_state(channel, ALLEGRO_STATE_DRAIN);
+               break;
+       default:
+               return 0;
+       }
+
+       /* If there are output buffers, they must be encoded */
+       if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) != 0) {
+               v4l2_dbg(1, debug,  &dev->v4l2_dev,
+                        "channel %d: CMD_STOP: continue encoding src buffers\n",
+                        channel->mcu_channel_id);
+               return 0;
+       }
+
+       /* If there are capture buffers, use it to signal EOS */
+       dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx);
+       if (dst_buf) {
+               v4l2_dbg(1, debug,  &dev->v4l2_dev,
+                        "channel %d: CMD_STOP: signaling EOS\n",
+                        channel->mcu_channel_id);
+               allegro_channel_buf_done(channel, dst_buf, VB2_BUF_STATE_DONE);
+               return 0;
+       }
+
+       /*
+        * If there are no capture buffers, we need to wait for the next
+        * buffer to signal EOS.
+        */
+       v4l2_dbg(1, debug,  &dev->v4l2_dev,
+                "channel %d: CMD_STOP: wait for CAPTURE buffer to signal EOS\n",
+                channel->mcu_channel_id);
+       allegro_set_state(channel, ALLEGRO_STATE_WAIT_FOR_BUFFER);
+
+       return 0;
+}
+
+static int allegro_channel_cmd_start(struct allegro_channel *channel)
+{
+       switch (allegro_get_state(channel)) {
+       case ALLEGRO_STATE_DRAIN:
+       case ALLEGRO_STATE_WAIT_FOR_BUFFER:
+               return -EBUSY;
+       case ALLEGRO_STATE_STOPPED:
+               allegro_set_state(channel, ALLEGRO_STATE_ENCODING);
+               break;
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int allegro_encoder_cmd(struct file *file, void *fh,
+                              struct v4l2_encoder_cmd *cmd)
+{
+       struct allegro_channel *channel = fh_to_channel(fh);
+       int err;
+
+       err = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd);
+       if (err)
+               return err;
+
+       switch (cmd->cmd) {
+       case V4L2_ENC_CMD_STOP:
+               err = allegro_channel_cmd_stop(channel);
+               break;
+       case V4L2_ENC_CMD_START:
+               err = allegro_channel_cmd_start(channel);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+
+       return err;
+}
+
+static int allegro_enum_framesizes(struct file *file, void *fh,
+                                  struct v4l2_frmsizeenum *fsize)
+{
+       switch (fsize->pixel_format) {
+       case V4L2_PIX_FMT_H264:
+       case V4L2_PIX_FMT_NV12:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (fsize->index)
+               return -EINVAL;
+
+       fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+       fsize->stepwise.min_width = ALLEGRO_WIDTH_MIN;
+       fsize->stepwise.max_width = ALLEGRO_WIDTH_MAX;
+       fsize->stepwise.step_width = 1;
+       fsize->stepwise.min_height = ALLEGRO_HEIGHT_MIN;
+       fsize->stepwise.max_height = ALLEGRO_HEIGHT_MAX;
+       fsize->stepwise.step_height = 1;
+
+       return 0;
+}
+
+static int allegro_ioctl_streamon(struct file *file, void *priv,
+                                 enum v4l2_buf_type type)
+{
+       struct v4l2_fh *fh = file->private_data;
+       struct allegro_channel *channel = fh_to_channel(fh);
+       int err;
+
+       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               err = allegro_create_channel(channel);
+               if (err)
+                       return err;
+       }
+
+       return v4l2_m2m_streamon(file, fh->m2m_ctx, type);
+}
+
+static int allegro_g_parm(struct file *file, void *fh,
+                         struct v4l2_streamparm *a)
+{
+       struct allegro_channel *channel = fh_to_channel(fh);
+       struct v4l2_fract *timeperframe;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+       timeperframe = &a->parm.output.timeperframe;
+       timeperframe->numerator = channel->framerate.denominator;
+       timeperframe->denominator = channel->framerate.numerator;
+
+       return 0;
+}
+
+static int allegro_s_parm(struct file *file, void *fh,
+                         struct v4l2_streamparm *a)
+{
+       struct allegro_channel *channel = fh_to_channel(fh);
+       struct v4l2_fract *timeperframe;
+       int div;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+       timeperframe = &a->parm.output.timeperframe;
+
+       if (timeperframe->numerator == 0 || timeperframe->denominator == 0)
+               return allegro_g_parm(file, fh, a);
+
+       div = gcd(timeperframe->denominator, timeperframe->numerator);
+       channel->framerate.numerator = timeperframe->denominator / div;
+       channel->framerate.denominator = timeperframe->numerator / div;
+
+       return 0;
+}
+
+static int allegro_subscribe_event(struct v4l2_fh *fh,
+                                  const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_EOS:
+               return v4l2_event_subscribe(fh, sub, 0, NULL);
+       default:
+               return v4l2_ctrl_subscribe_event(fh, sub);
+       }
+}
+
+static const struct v4l2_ioctl_ops allegro_ioctl_ops = {
+       .vidioc_querycap = allegro_querycap,
+       .vidioc_enum_fmt_vid_cap = allegro_enum_fmt_vid,
+       .vidioc_enum_fmt_vid_out = allegro_enum_fmt_vid,
+       .vidioc_g_fmt_vid_cap = allegro_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = allegro_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap = allegro_try_fmt_vid_cap,
+       .vidioc_g_fmt_vid_out = allegro_g_fmt_vid_out,
+       .vidioc_try_fmt_vid_out = allegro_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out = allegro_s_fmt_vid_out,
+
+       .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+       .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+
+       .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+       .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+       .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+       .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+       .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+
+       .vidioc_streamon = allegro_ioctl_streamon,
+       .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+       .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
+       .vidioc_encoder_cmd = allegro_encoder_cmd,
+       .vidioc_enum_framesizes = allegro_enum_framesizes,
+
+       .vidioc_g_parm          = allegro_g_parm,
+       .vidioc_s_parm          = allegro_s_parm,
+
+       .vidioc_subscribe_event = allegro_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_file_operations allegro_fops = {
+       .owner = THIS_MODULE,
+       .open = allegro_open,
+       .release = allegro_release,
+       .poll = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = v4l2_m2m_fop_mmap,
+};
+
+static int allegro_register_device(struct allegro_dev *dev)
+{
+       struct video_device *video_dev = &dev->video_dev;
+
+       strscpy(video_dev->name, "allegro", sizeof(video_dev->name));
+       video_dev->fops = &allegro_fops;
+       video_dev->ioctl_ops = &allegro_ioctl_ops;
+       video_dev->release = video_device_release_empty;
+       video_dev->lock = &dev->lock;
+       video_dev->v4l2_dev = &dev->v4l2_dev;
+       video_dev->vfl_dir = VFL_DIR_M2M;
+       video_dev->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+       video_set_drvdata(video_dev, dev);
+
+       return video_register_device(video_dev, VFL_TYPE_VIDEO, 0);
+}
+
+static void allegro_device_run(void *priv)
+{
+       struct allegro_channel *channel = priv;
+       struct allegro_dev *dev = channel->dev;
+       struct vb2_v4l2_buffer *src_buf;
+       struct vb2_v4l2_buffer *dst_buf;
+       dma_addr_t src_y;
+       dma_addr_t src_uv;
+       dma_addr_t dst_addr;
+       unsigned long dst_size;
+       u64 src_handle;
+       u64 dst_handle;
+
+       dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx);
+       dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+       dst_size = vb2_plane_size(&dst_buf->vb2_buf, 0);
+       dst_handle = allegro_put_buffer(channel, &channel->stream_shadow_list,
+                                       dst_buf);
+       allegro_mcu_send_put_stream_buffer(dev, channel, dst_addr, dst_size,
+                                          dst_handle);
+
+       src_buf = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx);
+       src_buf->sequence = channel->osequence++;
+       src_y = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+       src_uv = src_y + (channel->stride * channel->height);
+       src_handle = allegro_put_buffer(channel, &channel->source_shadow_list,
+                                       src_buf);
+       allegro_mcu_send_encode_frame(dev, channel, src_y, src_uv, src_handle);
+
+       v4l2_m2m_job_finish(dev->m2m_dev, channel->fh.m2m_ctx);
+}
+
+static const struct v4l2_m2m_ops allegro_m2m_ops = {
+       .device_run = allegro_device_run,
+};
+
+static int allegro_mcu_hw_init(struct allegro_dev *dev,
+                              const struct fw_info *info)
+{
+       int err;
+
+       dev->mbox_command = allegro_mbox_init(dev, info->mailbox_cmd,
+                                             info->mailbox_size);
+       dev->mbox_status = allegro_mbox_init(dev, info->mailbox_status,
+                                            info->mailbox_size);
+       if (IS_ERR(dev->mbox_command) || IS_ERR(dev->mbox_status)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "failed to initialize mailboxes\n");
+               return -EIO;
+       }
+
+       allegro_mcu_enable_interrupts(dev);
+
+       /* The mcu sends INIT after reset. */
+       allegro_mcu_start(dev);
+       err = allegro_mcu_wait_for_init_timeout(dev, 5000);
+       if (err < 0) {
+               v4l2_err(&dev->v4l2_dev,
+                        "mcu did not send INIT after reset\n");
+               err = -EIO;
+               goto err_disable_interrupts;
+       }
+
+       err = allegro_alloc_buffer(dev, &dev->suballocator,
+                                  info->suballocator_size);
+       if (err) {
+               v4l2_err(&dev->v4l2_dev,
+                        "failed to allocate %zu bytes for suballocator\n",
+                        info->suballocator_size);
+               goto err_reset_mcu;
+       }
+
+       allegro_mcu_send_init(dev, dev->suballocator.paddr,
+                             dev->suballocator.size);
+       err = allegro_mcu_wait_for_init_timeout(dev, 5000);
+       if (err < 0) {
+               v4l2_err(&dev->v4l2_dev,
+                        "mcu failed to configure sub-allocator\n");
+               err = -EIO;
+               goto err_free_suballocator;
+       }
+
+       return 0;
+
+err_free_suballocator:
+       allegro_free_buffer(dev, &dev->suballocator);
+err_reset_mcu:
+       allegro_mcu_reset(dev);
+err_disable_interrupts:
+       allegro_mcu_disable_interrupts(dev);
+
+       return err;
+}
+
+static int allegro_mcu_hw_deinit(struct allegro_dev *dev)
+{
+       int err;
+
+       err = allegro_mcu_reset(dev);
+       if (err)
+               v4l2_warn(&dev->v4l2_dev,
+                         "mcu failed to enter sleep state\n");
+
+       err = allegro_mcu_disable_interrupts(dev);
+       if (err)
+               v4l2_warn(&dev->v4l2_dev,
+                         "failed to disable interrupts\n");
+
+       allegro_free_buffer(dev, &dev->suballocator);
+
+       return 0;
+}
+
+static void allegro_fw_callback(const struct firmware *fw, void *context)
+{
+       struct allegro_dev *dev = context;
+       const char *fw_codec_name = "al5e.fw";
+       const struct firmware *fw_codec;
+       int err;
+
+       if (!fw)
+               return;
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "requesting codec firmware '%s'\n", fw_codec_name);
+       err = request_firmware(&fw_codec, fw_codec_name, &dev->plat_dev->dev);
+       if (err)
+               goto err_release_firmware;
+
+       dev->fw_info = allegro_get_firmware_info(dev, fw, fw_codec);
+       if (!dev->fw_info) {
+               v4l2_err(&dev->v4l2_dev, "firmware is not supported\n");
+               goto err_release_firmware_codec;
+       }
+
+       v4l2_info(&dev->v4l2_dev,
+                 "using mcu firmware version '%s'\n", dev->fw_info->version);
+
+       /* Ensure that the mcu is sleeping at the reset vector */
+       err = allegro_mcu_reset(dev);
+       if (err) {
+               v4l2_err(&dev->v4l2_dev, "failed to reset mcu\n");
+               goto err_release_firmware_codec;
+       }
+
+       allegro_copy_firmware(dev, fw->data, fw->size);
+       allegro_copy_fw_codec(dev, fw_codec->data, fw_codec->size);
+
+       err = allegro_mcu_hw_init(dev, dev->fw_info);
+       if (err) {
+               v4l2_err(&dev->v4l2_dev, "failed to initialize mcu\n");
+               goto err_free_fw_codec;
+       }
+
+       dev->m2m_dev = v4l2_m2m_init(&allegro_m2m_ops);
+       if (IS_ERR(dev->m2m_dev)) {
+               v4l2_err(&dev->v4l2_dev, "failed to init mem2mem device\n");
+               goto err_mcu_hw_deinit;
+       }
+
+       err = allegro_register_device(dev);
+       if (err) {
+               v4l2_err(&dev->v4l2_dev, "failed to register video device\n");
+               goto err_m2m_release;
+       }
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "allegro codec registered as /dev/video%d\n",
+                dev->video_dev.num);
+
+       release_firmware(fw_codec);
+       release_firmware(fw);
+
+       return;
+
+err_m2m_release:
+       v4l2_m2m_release(dev->m2m_dev);
+       dev->m2m_dev = NULL;
+err_mcu_hw_deinit:
+       allegro_mcu_hw_deinit(dev);
+err_free_fw_codec:
+       allegro_free_fw_codec(dev);
+err_release_firmware_codec:
+       release_firmware(fw_codec);
+err_release_firmware:
+       release_firmware(fw);
+}
+
+static int allegro_firmware_request_nowait(struct allegro_dev *dev)
+{
+       const char *fw = "al5e_b.fw";
+
+       v4l2_dbg(1, debug, &dev->v4l2_dev,
+                "requesting firmware '%s'\n", fw);
+       return request_firmware_nowait(THIS_MODULE, true, fw,
+                                      &dev->plat_dev->dev, GFP_KERNEL, dev,
+                                      allegro_fw_callback);
+}
+
+static int allegro_probe(struct platform_device *pdev)
+{
+       struct allegro_dev *dev;
+       struct resource *res, *sram_res;
+       int ret;
+       int irq;
+       void __iomem *regs, *sram_regs;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       dev->plat_dev = pdev;
+       init_completion(&dev->init_complete);
+       INIT_LIST_HEAD(&dev->channels);
+
+       mutex_init(&dev->lock);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "regs resource missing from device tree\n");
+               return -EINVAL;
+       }
+       regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!regs) {
+               dev_err(&pdev->dev, "failed to map registers\n");
+               return -ENOMEM;
+       }
+       dev->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+                                           &allegro_regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               dev_err(&pdev->dev, "failed to init regmap\n");
+               return PTR_ERR(dev->regmap);
+       }
+
+       sram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
+       if (!sram_res) {
+               dev_err(&pdev->dev,
+                       "sram resource missing from device tree\n");
+               return -EINVAL;
+       }
+       sram_regs = devm_ioremap(&pdev->dev,
+                                sram_res->start,
+                                resource_size(sram_res));
+       if (!sram_regs) {
+               dev_err(&pdev->dev, "failed to map sram\n");
+               return -ENOMEM;
+       }
+       dev->sram = devm_regmap_init_mmio(&pdev->dev, sram_regs,
+                                         &allegro_sram_config);
+       if (IS_ERR(dev->sram)) {
+               dev_err(&pdev->dev, "failed to init sram\n");
+               return PTR_ERR(dev->sram);
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+       ret = devm_request_threaded_irq(&pdev->dev, irq,
+                                       allegro_hardirq,
+                                       allegro_irq_thread,
+                                       IRQF_SHARED, dev_name(&pdev->dev), dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+               return ret;
+       }
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(pdev, dev);
+
+       ret = allegro_firmware_request_nowait(dev);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev,
+                        "failed to request firmware: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int allegro_remove(struct platform_device *pdev)
+{
+       struct allegro_dev *dev = platform_get_drvdata(pdev);
+
+       video_unregister_device(&dev->video_dev);
+       if (dev->m2m_dev)
+               v4l2_m2m_release(dev->m2m_dev);
+       allegro_mcu_hw_deinit(dev);
+       allegro_free_fw_codec(dev);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+
+       return 0;
+}
+
+static const struct of_device_id allegro_dt_ids[] = {
+       { .compatible = "allegro,al5e-1.1" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, allegro_dt_ids);
+
+static struct platform_driver allegro_driver = {
+       .probe = allegro_probe,
+       .remove = allegro_remove,
+       .driver = {
+               .name = "allegro",
+               .of_match_table = of_match_ptr(allegro_dt_ids),
+       },
+};
+
+module_platform_driver(allegro_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Tretter <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("Allegro DVT encoder driver");
diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.c b/drivers/media/platform/allegro-dvt/allegro-mail.c
new file mode 100644 (file)
index 0000000..9286d21
--- /dev/null
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Helper functions for handling messages that are send via mailbox to the
+ * Allegro VCU firmware.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "allegro-mail.h"
+
+const char *msg_type_name(enum mcu_msg_type type)
+{
+       static char buf[9];
+
+       switch (type) {
+       case MCU_MSG_TYPE_INIT:
+               return "INIT";
+       case MCU_MSG_TYPE_CREATE_CHANNEL:
+               return "CREATE_CHANNEL";
+       case MCU_MSG_TYPE_DESTROY_CHANNEL:
+               return "DESTROY_CHANNEL";
+       case MCU_MSG_TYPE_ENCODE_FRAME:
+               return "ENCODE_FRAME";
+       case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
+               return "PUT_STREAM_BUFFER";
+       case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
+               return "PUSH_BUFFER_INTERMEDIATE";
+       case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
+               return "PUSH_BUFFER_REFERENCE";
+       default:
+               snprintf(buf, sizeof(buf), "(0x%04x)", type);
+               return buf;
+       }
+}
+EXPORT_SYMBOL(msg_type_name);
+
+static ssize_t
+allegro_enc_init(u32 *dst, struct mcu_msg_init_request *msg)
+{
+       unsigned int i = 0;
+       enum mcu_msg_version version = msg->header.version;
+
+       dst[i++] = msg->reserved0;
+       dst[i++] = msg->suballoc_dma;
+       dst[i++] = msg->suballoc_size;
+       dst[i++] = msg->l2_cache[0];
+       dst[i++] = msg->l2_cache[1];
+       dst[i++] = msg->l2_cache[2];
+       if (version >= MCU_MSG_VERSION_2019_2) {
+               dst[i++] = -1;
+               dst[i++] = 0;
+       }
+
+       return i * sizeof(*dst);
+}
+
+static inline u32 settings_get_mcu_codec(struct create_channel_param *param)
+{
+       enum mcu_msg_version version = param->version;
+       u32 pixelformat = param->codec;
+
+       if (version < MCU_MSG_VERSION_2019_2) {
+               switch (pixelformat) {
+               case V4L2_PIX_FMT_H264:
+               default:
+                       return 1;
+               }
+       } else {
+               switch (pixelformat) {
+               case V4L2_PIX_FMT_H264:
+               default:
+                       return 0;
+               }
+       }
+}
+
+ssize_t
+allegro_encode_config_blob(u32 *dst, struct create_channel_param *param)
+{
+       enum mcu_msg_version version = param->version;
+       unsigned int i = 0;
+       unsigned int j = 0;
+       u32 val;
+       unsigned int codec = settings_get_mcu_codec(param);
+
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->layer_id;
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->height) |
+                  FIELD_PREP(GENMASK(15, 0), param->width);
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->videomode;
+       dst[i++] = param->format;
+       if (version < MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->colorspace;
+       dst[i++] = param->src_mode;
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->src_bit_depth;
+       dst[i++] = FIELD_PREP(GENMASK(31, 24), codec) |
+                  FIELD_PREP(GENMASK(23, 8), param->constraint_set_flags) |
+                  FIELD_PREP(GENMASK(7, 0), param->profile);
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->tier) |
+                  FIELD_PREP(GENMASK(15, 0), param->level);
+
+       val = 0;
+       val |= param->temporal_mvp_enable ? BIT(20) : 0;
+       val |= FIELD_PREP(GENMASK(7, 4), param->log2_max_frame_num) |
+              FIELD_PREP(GENMASK(3, 0), param->log2_max_poc);
+       dst[i++] = val;
+
+       val = 0;
+       val |= param->dbf_ovr_en ? BIT(2) : 0;
+       dst[i++] = val;
+
+       if (version >= MCU_MSG_VERSION_2019_2) {
+               val = 0;
+               val |= param->custom_lda ? BIT(2) : 0;
+               val |= param->rdo_cost_mode ? BIT(20) : 0;
+               dst[i++] = val;
+
+               val = 0;
+               val |= param->lf ? BIT(2) : 0;
+               val |= param->lf_x_tile ? BIT(3) : 0;
+               val |= param->lf_x_slice ? BIT(4) : 0;
+               dst[i++] = val;
+       } else {
+               val = 0;
+               dst[i++] = val;
+       }
+
+       dst[i++] = FIELD_PREP(GENMASK(15, 8), param->beta_offset) |
+                  FIELD_PREP(GENMASK(7, 0), param->tc_offset);
+       dst[i++] = param->unknown11;
+       dst[i++] = param->unknown12;
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->num_slices;
+       else
+               dst[i++] = FIELD_PREP(GENMASK(31, 16), param->prefetch_auto) |
+                          FIELD_PREP(GENMASK(15, 0), param->num_slices);
+       dst[i++] = param->prefetch_mem_offset;
+       dst[i++] = param->prefetch_mem_size;
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clip_vrt_range) |
+                  FIELD_PREP(GENMASK(15, 0), param->clip_hrz_range);
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[1]) |
+                  FIELD_PREP(GENMASK(15, 0), param->me_range[0]);
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[3]) |
+                  FIELD_PREP(GENMASK(15, 0), param->me_range[2]);
+       dst[i++] = FIELD_PREP(GENMASK(31, 24), param->min_tu_size) |
+                  FIELD_PREP(GENMASK(23, 16), param->max_tu_size) |
+                  FIELD_PREP(GENMASK(15, 8), param->min_cu_size) |
+                  FIELD_PREP(GENMASK(8, 0), param->max_cu_size);
+       dst[i++] = FIELD_PREP(GENMASK(15, 8), param->max_transfo_depth_intra) |
+                  FIELD_PREP(GENMASK(7, 0), param->max_transfo_depth_inter);
+       dst[i++] = param->entropy_mode;
+       dst[i++] = param->wp_mode;
+
+       dst[i++] = param->rate_control_mode;
+       dst[i++] = param->initial_rem_delay;
+       dst[i++] = param->cpb_size;
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clk_ratio) |
+                  FIELD_PREP(GENMASK(15, 0), param->framerate);
+       dst[i++] = param->target_bitrate;
+       dst[i++] = param->max_bitrate;
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->min_qp) |
+                  FIELD_PREP(GENMASK(15, 0), param->initial_qp);
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->ip_delta) |
+                  FIELD_PREP(GENMASK(15, 0), param->max_qp);
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref) |
+                  FIELD_PREP(GENMASK(15, 0), param->pb_delta);
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref_frequency) |
+                  FIELD_PREP(GENMASK(15, 0), param->golden_delta);
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->rate_control_option;
+       else
+               dst[i++] = 0;
+
+       if (version >= MCU_MSG_VERSION_2019_2) {
+               dst[i++] = param->num_pixel;
+               dst[i++] = FIELD_PREP(GENMASK(31, 16), param->max_pixel_value) |
+                       FIELD_PREP(GENMASK(15, 0), param->max_psnr);
+               for (j = 0; j < 3; j++)
+                       dst[i++] = param->maxpicturesize[j];
+       }
+
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->gop_ctrl_mode;
+       else
+               dst[i++] = 0;
+
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |
+                          FIELD_PREP(GENMASK(23, 16), param->num_b) |
+                          FIELD_PREP(GENMASK(15, 0), param->gop_length);
+       dst[i++] = param->freq_idr;
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->enable_lt;
+       dst[i++] = param->freq_lt;
+       dst[i++] = param->gdr_mode;
+       if (version < MCU_MSG_VERSION_2019_2)
+               dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |
+                          FIELD_PREP(GENMASK(23, 16), param->num_b) |
+                          FIELD_PREP(GENMASK(15, 0), param->gop_length);
+
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->tmpdqp;
+
+       dst[i++] = param->subframe_latency;
+       dst[i++] = param->lda_control_mode;
+       if (version < MCU_MSG_VERSION_2019_2)
+               dst[i++] = param->unknown41;
+
+       if (version >= MCU_MSG_VERSION_2019_2) {
+               for (j = 0; j < 6; j++)
+                       dst[i++] = param->lda_factors[j];
+               dst[i++] = param->max_num_merge_cand;
+       }
+
+       return i * sizeof(*dst);
+}
+
+static ssize_t
+allegro_enc_create_channel(u32 *dst, struct mcu_msg_create_channel *msg)
+{
+       enum mcu_msg_version version = msg->header.version;
+       unsigned int i = 0;
+
+       dst[i++] = msg->user_id;
+
+       if (version >= MCU_MSG_VERSION_2019_2) {
+               dst[i++] = msg->blob_mcu_addr;
+       } else {
+               memcpy(&dst[i], msg->blob, msg->blob_size);
+               i += msg->blob_size / sizeof(*dst);
+       }
+
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = msg->ep1_addr;
+
+       return i * sizeof(*dst);
+}
+
+ssize_t allegro_decode_config_blob(struct create_channel_param *param,
+                                  struct mcu_msg_create_channel_response *msg,
+                                  u32 *src)
+{
+       enum mcu_msg_version version = msg->header.version;
+
+       if (version >= MCU_MSG_VERSION_2019_2) {
+               param->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[9]);
+               param->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[9]);
+       } else {
+               param->num_ref_idx_l0 = msg->num_ref_idx_l0;
+               param->num_ref_idx_l1 = msg->num_ref_idx_l1;
+       }
+
+       return 0;
+}
+
+static ssize_t
+allegro_enc_destroy_channel(u32 *dst, struct mcu_msg_destroy_channel *msg)
+{
+       unsigned int i = 0;
+
+       dst[i++] = msg->channel_id;
+
+       return i * sizeof(*dst);
+}
+
+static ssize_t
+allegro_enc_push_buffers(u32 *dst, struct mcu_msg_push_buffers_internal *msg)
+{
+       unsigned int i = 0;
+       struct mcu_msg_push_buffers_internal_buffer *buffer;
+       unsigned int num_buffers = msg->num_buffers;
+       unsigned int j;
+
+       dst[i++] = msg->channel_id;
+
+       for (j = 0; j < num_buffers; j++) {
+               buffer = &msg->buffer[j];
+               dst[i++] = buffer->dma_addr;
+               dst[i++] = buffer->mcu_addr;
+               dst[i++] = buffer->size;
+       }
+
+       return i * sizeof(*dst);
+}
+
+static ssize_t
+allegro_enc_put_stream_buffer(u32 *dst,
+                             struct mcu_msg_put_stream_buffer *msg)
+{
+       unsigned int i = 0;
+
+       dst[i++] = msg->channel_id;
+       dst[i++] = msg->dma_addr;
+       dst[i++] = msg->mcu_addr;
+       dst[i++] = msg->size;
+       dst[i++] = msg->offset;
+       dst[i++] = lower_32_bits(msg->stream_id);
+       dst[i++] = upper_32_bits(msg->stream_id);
+
+       return i * sizeof(*dst);
+}
+
+static ssize_t
+allegro_enc_encode_frame(u32 *dst, struct mcu_msg_encode_frame *msg)
+{
+       enum mcu_msg_version version = msg->header.version;
+       unsigned int i = 0;
+
+       dst[i++] = msg->channel_id;
+
+       dst[i++] = msg->reserved;
+       dst[i++] = msg->encoding_options;
+       dst[i++] = FIELD_PREP(GENMASK(31, 16), msg->padding) |
+                  FIELD_PREP(GENMASK(15, 0), msg->pps_qp);
+
+       if (version >= MCU_MSG_VERSION_2019_2) {
+               dst[i++] = 0;
+               dst[i++] = 0;
+               dst[i++] = 0;
+               dst[i++] = 0;
+       }
+
+       dst[i++] = lower_32_bits(msg->user_param);
+       dst[i++] = upper_32_bits(msg->user_param);
+       dst[i++] = lower_32_bits(msg->src_handle);
+       dst[i++] = upper_32_bits(msg->src_handle);
+       dst[i++] = msg->request_options;
+       dst[i++] = msg->src_y;
+       dst[i++] = msg->src_uv;
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = msg->is_10_bit;
+       dst[i++] = msg->stride;
+       if (version >= MCU_MSG_VERSION_2019_2)
+               dst[i++] = msg->format;
+       dst[i++] = msg->ep2;
+       dst[i++] = lower_32_bits(msg->ep2_v);
+       dst[i++] = upper_32_bits(msg->ep2_v);
+
+       return i * sizeof(*dst);
+}
+
+static ssize_t
+allegro_dec_init(struct mcu_msg_init_response *msg, u32 *src)
+{
+       unsigned int i = 0;
+
+       msg->reserved0 = src[i++];
+
+       return i * sizeof(*src);
+}
+
+static ssize_t
+allegro_dec_create_channel(struct mcu_msg_create_channel_response *msg,
+                          u32 *src)
+{
+       enum mcu_msg_version version = msg->header.version;
+       unsigned int i = 0;
+
+       msg->channel_id = src[i++];
+       msg->user_id = src[i++];
+       /*
+        * Version >= MCU_MSG_VERSION_2019_2 is handled in
+        * allegro_decode_config_blob().
+        */
+       if (version < MCU_MSG_VERSION_2019_2) {
+               msg->options = src[i++];
+               msg->num_core = src[i++];
+               msg->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[i]);
+               msg->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[i++]);
+       }
+       msg->int_buffers_count = src[i++];
+       msg->int_buffers_size = src[i++];
+       msg->rec_buffers_count = src[i++];
+       msg->rec_buffers_size = src[i++];
+       msg->reserved = src[i++];
+       msg->error_code = src[i++];
+
+       return i * sizeof(*src);
+}
+
+static ssize_t
+allegro_dec_destroy_channel(struct mcu_msg_destroy_channel_response *msg,
+                           u32 *src)
+{
+       unsigned int i = 0;
+
+       msg->channel_id = src[i++];
+
+       return i * sizeof(*src);
+}
+
+static ssize_t
+allegro_dec_encode_frame(struct mcu_msg_encode_frame_response *msg, u32 *src)
+{
+       enum mcu_msg_version version = msg->header.version;
+       unsigned int i = 0;
+       unsigned int j;
+
+       msg->channel_id = src[i++];
+
+       msg->stream_id = src[i++];
+       msg->stream_id |= (((u64)src[i++]) << 32);
+       msg->user_param = src[i++];
+       msg->user_param |= (((u64)src[i++]) << 32);
+       msg->src_handle = src[i++];
+       msg->src_handle |= (((u64)src[i++]) << 32);
+       msg->skip = FIELD_GET(GENMASK(31, 16), src[i]);
+       msg->is_ref = FIELD_GET(GENMASK(15, 0), src[i++]);
+       msg->initial_removal_delay = src[i++];
+       msg->dpb_output_delay = src[i++];
+       msg->size = src[i++];
+       msg->frame_tag_size = src[i++];
+       msg->stuffing = src[i++];
+       msg->filler = src[i++];
+       msg->num_column = FIELD_GET(GENMASK(31, 16), src[i]);
+       msg->num_row = FIELD_GET(GENMASK(15, 0), src[i++]);
+       msg->num_ref_idx_l1 = FIELD_GET(GENMASK(31, 24), src[i]);
+       msg->num_ref_idx_l0 = FIELD_GET(GENMASK(23, 16), src[i]);
+       msg->qp = FIELD_GET(GENMASK(15, 0), src[i++]);
+       msg->partition_table_offset = src[i++];
+       msg->partition_table_size = src[i++];
+       msg->sum_complex = src[i++];
+       for (j = 0; j < 4; j++)
+               msg->tile_width[j] = src[i++];
+       for (j = 0; j < 22; j++)
+               msg->tile_height[j] = src[i++];
+       msg->error_code = src[i++];
+       msg->slice_type = src[i++];
+       msg->pic_struct = src[i++];
+       msg->reserved = FIELD_GET(GENMASK(31, 24), src[i]);
+       msg->is_last_slice = FIELD_GET(GENMASK(23, 16), src[i]);
+       msg->is_first_slice = FIELD_GET(GENMASK(15, 8), src[i]);
+       msg->is_idr = FIELD_GET(GENMASK(7, 0), src[i++]);
+
+       msg->reserved1 = FIELD_GET(GENMASK(31, 16), src[i]);
+       msg->pps_qp = FIELD_GET(GENMASK(15, 0), src[i++]);
+
+       msg->reserved2 = src[i++];
+       if (version >= MCU_MSG_VERSION_2019_2) {
+               msg->reserved3 = src[i++];
+               msg->reserved4 = src[i++];
+               msg->reserved5 = src[i++];
+               msg->reserved6 = src[i++];
+       }
+
+       return i * sizeof(*src);
+}
+
+/**
+ * allegro_encode_mail() - Encode allegro messages to firmware format
+ * @dst: Pointer to the memory that will be filled with data
+ * @msg: The allegro message that will be encoded
+ */
+ssize_t allegro_encode_mail(u32 *dst, void *msg)
+{
+       const struct mcu_msg_header *header = msg;
+       ssize_t size;
+
+       if (!msg || !dst)
+               return -EINVAL;
+
+       switch (header->type) {
+       case MCU_MSG_TYPE_INIT:
+               size = allegro_enc_init(&dst[1], msg);
+               break;
+       case MCU_MSG_TYPE_CREATE_CHANNEL:
+               size = allegro_enc_create_channel(&dst[1], msg);
+               break;
+       case MCU_MSG_TYPE_DESTROY_CHANNEL:
+               size = allegro_enc_destroy_channel(&dst[1], msg);
+               break;
+       case MCU_MSG_TYPE_ENCODE_FRAME:
+               size = allegro_enc_encode_frame(&dst[1], msg);
+               break;
+       case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
+               size = allegro_enc_put_stream_buffer(&dst[1], msg);
+               break;
+       case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
+       case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
+               size = allegro_enc_push_buffers(&dst[1], msg);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * The encoded messages might have different length depending on
+        * the firmware version or certain fields. Therefore, we have to
+        * set the body length after encoding the message.
+        */
+       dst[0] = FIELD_PREP(GENMASK(31, 16), header->type) |
+                FIELD_PREP(GENMASK(15, 0), size);
+
+       return size + sizeof(*dst);
+}
+
+/**
+ * allegro_decode_mail() - Parse allegro messages from the firmware.
+ * @msg: The mcu_msg_response that will be filled with parsed values.
+ * @src: Pointer to the memory that will be parsed
+ *
+ * The message format in the mailbox depends on the firmware. Parse the
+ * different formats into a uniform message format that can be used without
+ * taking care of the firmware version.
+ */
+int allegro_decode_mail(void *msg, u32 *src)
+{
+       struct mcu_msg_header *header;
+
+       if (!src || !msg)
+               return -EINVAL;
+
+       header = msg;
+       header->type = FIELD_GET(GENMASK(31, 16), src[0]);
+
+       src++;
+       switch (header->type) {
+       case MCU_MSG_TYPE_INIT:
+               allegro_dec_init(msg, src);
+               break;
+       case MCU_MSG_TYPE_CREATE_CHANNEL:
+               allegro_dec_create_channel(msg, src);
+               break;
+       case MCU_MSG_TYPE_DESTROY_CHANNEL:
+               allegro_dec_destroy_channel(msg, src);
+               break;
+       case MCU_MSG_TYPE_ENCODE_FRAME:
+               allegro_dec_encode_frame(msg, src);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.h b/drivers/media/platform/allegro-dvt/allegro-mail.h
new file mode 100644 (file)
index 0000000..486ecb1
--- /dev/null
@@ -0,0 +1,294 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Allegro VCU firmware mailbox mail definitions
+ */
+
+#ifndef ALLEGRO_MAIL_H
+#define ALLEGRO_MAIL_H
+
+#include <linux/kernel.h>
+
+enum mcu_msg_type {
+       MCU_MSG_TYPE_INIT = 0x0000,
+       MCU_MSG_TYPE_CREATE_CHANNEL = 0x0005,
+       MCU_MSG_TYPE_DESTROY_CHANNEL = 0x0006,
+       MCU_MSG_TYPE_ENCODE_FRAME = 0x0007,
+       MCU_MSG_TYPE_PUT_STREAM_BUFFER = 0x0012,
+       MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE = 0x000e,
+       MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE = 0x000f,
+};
+
+enum mcu_msg_version {
+       MCU_MSG_VERSION_2018_2,
+       MCU_MSG_VERSION_2019_2,
+};
+
+const char *msg_type_name(enum mcu_msg_type type);
+
+struct mcu_msg_header {
+       enum mcu_msg_type type;
+       enum mcu_msg_version version;
+};
+
+struct mcu_msg_init_request {
+       struct mcu_msg_header header;
+       u32 reserved0;          /* maybe a unused channel id */
+       u32 suballoc_dma;
+       u32 suballoc_size;
+       s32 l2_cache[3];
+};
+
+struct mcu_msg_init_response {
+       struct mcu_msg_header header;
+       u32 reserved0;
+};
+
+struct create_channel_param {
+       enum mcu_msg_version version;
+       u32 layer_id;
+       u16 width;
+       u16 height;
+       u32 videomode;
+       u32 format;
+       u32 colorspace;
+       u32 src_mode;
+       u32 src_bit_depth;
+       u8 profile;
+       u16 constraint_set_flags;
+       u32 codec;
+       u16 level;
+       u16 tier;
+       u32 log2_max_poc;
+       u32 log2_max_frame_num;
+       u32 temporal_mvp_enable;
+       u32 enable_reordering;
+       u32 dbf_ovr_en;
+       u32 num_ref_idx_l0;
+       u32 num_ref_idx_l1;
+       u32 custom_lda;
+       u32 rdo_cost_mode;
+       u32 lf;
+       u32 lf_x_tile;
+       u32 lf_x_slice;
+       s8 beta_offset;
+       s8 tc_offset;
+       u16 reserved10;
+       u32 unknown11;
+       u32 unknown12;
+       u16 num_slices;
+       u16 prefetch_auto;
+       u32 prefetch_mem_offset;
+       u32 prefetch_mem_size;
+       u16 clip_hrz_range;
+       u16 clip_vrt_range;
+       u16 me_range[4];
+       u8 max_cu_size;
+       u8 min_cu_size;
+       u8 max_tu_size;
+       u8 min_tu_size;
+       u8 max_transfo_depth_inter;
+       u8 max_transfo_depth_intra;
+       u16 reserved20;
+       u32 entropy_mode;
+       u32 wp_mode;
+
+       /* rate control param */
+       u32 rate_control_mode;
+       u32 initial_rem_delay;
+       u32 cpb_size;
+       u16 framerate;
+       u16 clk_ratio;
+       u32 target_bitrate;
+       u32 max_bitrate;
+       u16 initial_qp;
+       u16 min_qp;
+       u16 max_qp;
+       s16 ip_delta;
+       s16 pb_delta;
+       u16 golden_ref;
+       u16 golden_delta;
+       u16 golden_ref_frequency;
+       u32 rate_control_option;
+       u32 num_pixel;
+       u16 max_psnr;
+       u16 max_pixel_value;
+       u32 maxpicturesize[3];
+
+       /* gop param */
+       u32 gop_ctrl_mode;
+       u32 freq_idr;
+       u32 freq_lt;
+       u32 gdr_mode;
+       u16 gop_length;
+       u8 num_b;
+       u8 freq_golden_ref;
+       u32 enable_lt;
+       u32 tmpdqp;
+
+       u32 subframe_latency;
+       u32 lda_control_mode;
+       u32 unknown41;
+
+       u32 lda_factors[6];
+
+       u32 max_num_merge_cand;
+};
+
+struct mcu_msg_create_channel {
+       struct mcu_msg_header header;
+       u32 user_id;
+       u32 *blob;
+       size_t blob_size;
+       u32 blob_mcu_addr;
+       u32 ep1_addr;
+};
+
+struct mcu_msg_create_channel_response {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       u32 user_id;
+       u32 options;
+       u32 num_core;
+       u32 num_ref_idx_l0;
+       u32 num_ref_idx_l1;
+       u32 int_buffers_count;
+       u32 int_buffers_size;
+       u32 rec_buffers_count;
+       u32 rec_buffers_size;
+       u32 reserved;
+       u32 error_code;
+};
+
+struct mcu_msg_destroy_channel {
+       struct mcu_msg_header header;
+       u32 channel_id;
+};
+
+struct mcu_msg_destroy_channel_response {
+       struct mcu_msg_header header;
+       u32 channel_id;
+};
+
+struct mcu_msg_push_buffers_internal_buffer {
+       u32 dma_addr;
+       u32 mcu_addr;
+       u32 size;
+};
+
+struct mcu_msg_push_buffers_internal {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       size_t num_buffers;
+       struct mcu_msg_push_buffers_internal_buffer buffer[];
+};
+
+struct mcu_msg_put_stream_buffer {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       u32 dma_addr;
+       u32 mcu_addr;
+       u32 size;
+       u32 offset;
+       u64 stream_id;
+};
+
+struct mcu_msg_encode_frame {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       u32 reserved;
+
+       u32 encoding_options;
+#define AL_OPT_USE_QP_TABLE            BIT(0)
+#define AL_OPT_FORCE_LOAD              BIT(1)
+#define AL_OPT_USE_L2                  BIT(2)
+#define AL_OPT_DISABLE_INTRA           BIT(3)
+#define AL_OPT_DEPENDENT_SLICES                BIT(4)
+
+       s16 pps_qp;
+       u16 padding;
+       u64 user_param;
+       u64 src_handle;
+
+       u32 request_options;
+#define AL_OPT_SCENE_CHANGE            BIT(0)
+#define AL_OPT_RESTART_GOP             BIT(1)
+#define AL_OPT_USE_LONG_TERM           BIT(2)
+#define AL_OPT_UPDATE_PARAMS           BIT(3)
+
+       /* u32 scene_change_delay (optional) */
+       /* rate control param (optional) */
+       /* gop param (optional) */
+       /* dynamic resolution params (optional) */
+       u32 src_y;
+       u32 src_uv;
+       u32 is_10_bit;
+       u32 stride;
+       u32 format;
+       u32 ep2;
+       u64 ep2_v;
+};
+
+struct mcu_msg_encode_frame_response {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       u64 stream_id;          /* see mcu_msg_put_stream_buffer */
+       u64 user_param;         /* see mcu_msg_encode_frame */
+       u64 src_handle;         /* see mcu_msg_encode_frame */
+       u16 skip;
+       u16 is_ref;
+       u32 initial_removal_delay;
+       u32 dpb_output_delay;
+       u32 size;
+       u32 frame_tag_size;
+       s32 stuffing;
+       s32 filler;
+       u16 num_column;
+       u16 num_row;
+       u16 qp;
+       u8 num_ref_idx_l0;
+       u8 num_ref_idx_l1;
+       u32 partition_table_offset;
+       s32 partition_table_size;
+       u32 sum_complex;
+       s32 tile_width[4];
+       s32 tile_height[22];
+       u32 error_code;
+
+       u32 slice_type;
+#define AL_ENC_SLICE_TYPE_B             0
+#define AL_ENC_SLICE_TYPE_P             1
+#define AL_ENC_SLICE_TYPE_I             2
+
+       u32 pic_struct;
+       u8 is_idr;
+       u8 is_first_slice;
+       u8 is_last_slice;
+       u8 reserved;
+       u16 pps_qp;
+       u16 reserved1;
+       u32 reserved2;
+       u32 reserved3;
+       u32 reserved4;
+       u32 reserved5;
+       u32 reserved6;
+};
+
+union mcu_msg_response {
+       struct mcu_msg_header header;
+       struct mcu_msg_init_response init;
+       struct mcu_msg_create_channel_response create_channel;
+       struct mcu_msg_destroy_channel_response destroy_channel;
+       struct mcu_msg_encode_frame_response encode_frame;
+};
+
+ssize_t allegro_encode_config_blob(u32 *dst, struct create_channel_param *param);
+ssize_t allegro_decode_config_blob(struct create_channel_param *param,
+                                  struct mcu_msg_create_channel_response *msg,
+                                  u32 *src);
+
+int allegro_decode_mail(void *msg, u32 *src);
+ssize_t allegro_encode_mail(u32 *dst, void *msg);
+
+#endif
diff --git a/drivers/media/platform/allegro-dvt/nal-h264.c b/drivers/media/platform/allegro-dvt/nal-h264.c
new file mode 100644 (file)
index 0000000..bd48b88
--- /dev/null
@@ -0,0 +1,1001 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Convert NAL units between raw byte sequence payloads (RBSP) and C structs
+ *
+ * The conversion is defined in "ITU-T Rec. H.264 (04/2017) Advanced video
+ * coding for generic audiovisual services". Decoder drivers may use the
+ * parser to parse RBSP from encoded streams and configure the hardware, if
+ * the hardware is not able to parse RBSP itself.  Encoder drivers may use the
+ * generator to generate the RBSP for SPS/PPS nal units and add them to the
+ * encoded stream if the hardware does not generate the units.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/v4l2-controls.h>
+
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/log2.h>
+
+#include "nal-h264.h"
+
+/*
+ * See Rec. ITU-T H.264 (04/2017) Table 7-1 â€“ NAL unit type codes, syntax
+ * element categories, and NAL unit type classes
+ */
+enum nal_unit_type {
+       SEQUENCE_PARAMETER_SET = 7,
+       PICTURE_PARAMETER_SET = 8,
+       FILLER_DATA = 12,
+};
+
+struct rbsp;
+
+struct nal_h264_ops {
+       int (*rbsp_bit)(struct rbsp *rbsp, int *val);
+       int (*rbsp_bits)(struct rbsp *rbsp, int n, unsigned int *val);
+       int (*rbsp_uev)(struct rbsp *rbsp, unsigned int *val);
+       int (*rbsp_sev)(struct rbsp *rbsp, int *val);
+};
+
+/**
+ * struct rbsp - State object for handling a raw byte sequence payload
+ * @data: pointer to the data of the rbsp
+ * @size: maximum size of the data of the rbsp
+ * @pos: current bit position inside the rbsp
+ * @num_consecutive_zeros: number of zeros before @pos
+ * @ops: per datatype functions for interacting with the rbsp
+ * @error: an error occurred while handling the rbsp
+ *
+ * This struct is passed around the various parsing functions and tracks the
+ * current position within the raw byte sequence payload.
+ *
+ * The @ops field allows to separate the operation, i.e., reading/writing a
+ * value from/to that rbsp, from the structure of the NAL unit. This allows to
+ * have a single function for iterating the NAL unit, while @ops has function
+ * pointers for handling each type in the rbsp.
+ */
+struct rbsp {
+       u8 *data;
+       size_t size;
+       unsigned int pos;
+       unsigned int num_consecutive_zeros;
+       struct nal_h264_ops *ops;
+       int error;
+};
+
+static void rbsp_init(struct rbsp *rbsp, void *addr, size_t size,
+                     struct nal_h264_ops *ops)
+{
+       if (!rbsp)
+               return;
+
+       rbsp->data = addr;
+       rbsp->size = size;
+       rbsp->pos = 0;
+       rbsp->ops = ops;
+       rbsp->error = 0;
+}
+
+/**
+ * nal_h264_profile_from_v4l2() - Get profile_idc for v4l2 h264 profile
+ * @profile: the profile as &enum v4l2_mpeg_video_h264_profile
+ *
+ * Convert the &enum v4l2_mpeg_video_h264_profile to profile_idc as specified
+ * in Rec. ITU-T H.264 (04/2017) A.2.
+ *
+ * Return: the profile_idc for the passed level
+ */
+int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile)
+{
+       switch (profile) {
+       case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+               return 66;
+       case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+               return 77;
+       case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+               return 88;
+       case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+               return 100;
+       default:
+               return -EINVAL;
+       }
+}
+
+/**
+ * nal_h264_level_from_v4l2() - Get level_idc for v4l2 h264 level
+ * @level: the level as &enum v4l2_mpeg_video_h264_level
+ *
+ * Convert the &enum v4l2_mpeg_video_h264_level to level_idc as specified in
+ * Rec. ITU-T H.264 (04/2017) A.3.2.
+ *
+ * Return: the level_idc for the passed level
+ */
+int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level)
+{
+       switch (level) {
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+               return 10;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+               return 9;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+               return 11;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+               return 12;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+               return 13;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+               return 20;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+               return 21;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+               return 22;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+               return 30;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+               return 31;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+               return 32;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+               return 40;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+               return 41;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+               return 42;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+               return 50;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+               return 51;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value);
+static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value);
+
+/*
+ * When reading or writing, the emulation_prevention_three_byte is detected
+ * only when the 2 one bits need to be inserted. Therefore, we are not
+ * actually adding the 0x3 byte, but the 2 one bits and the six 0 bits of the
+ * next byte.
+ */
+#define EMULATION_PREVENTION_THREE_BYTE (0x3 << 6)
+
+static int add_emulation_prevention_three_byte(struct rbsp *rbsp)
+{
+       rbsp->num_consecutive_zeros = 0;
+       rbsp_write_bits(rbsp, 8, EMULATION_PREVENTION_THREE_BYTE);
+
+       return 0;
+}
+
+static int discard_emulation_prevention_three_byte(struct rbsp *rbsp)
+{
+       unsigned int tmp = 0;
+
+       rbsp->num_consecutive_zeros = 0;
+       rbsp_read_bits(rbsp, 8, &tmp);
+       if (tmp != EMULATION_PREVENTION_THREE_BYTE)
+               return -EINVAL;
+
+       return 0;
+}
+
+static inline int rbsp_read_bit(struct rbsp *rbsp)
+{
+       int shift;
+       int ofs;
+       int bit;
+       int err;
+
+       if (rbsp->num_consecutive_zeros == 22) {
+               err = discard_emulation_prevention_three_byte(rbsp);
+               if (err)
+                       return err;
+       }
+
+       shift = 7 - (rbsp->pos % 8);
+       ofs = rbsp->pos / 8;
+       if (ofs >= rbsp->size)
+               return -EINVAL;
+
+       bit = (rbsp->data[ofs] >> shift) & 1;
+
+       rbsp->pos++;
+
+       if (bit == 1 ||
+           (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0)))
+               rbsp->num_consecutive_zeros = 0;
+       else
+               rbsp->num_consecutive_zeros++;
+
+       return bit;
+}
+
+static inline int rbsp_write_bit(struct rbsp *rbsp, bool value)
+{
+       int shift;
+       int ofs;
+
+       if (rbsp->num_consecutive_zeros == 22)
+               add_emulation_prevention_three_byte(rbsp);
+
+       shift = 7 - (rbsp->pos % 8);
+       ofs = rbsp->pos / 8;
+       if (ofs >= rbsp->size)
+               return -EINVAL;
+
+       rbsp->data[ofs] &= ~(1 << shift);
+       rbsp->data[ofs] |= value << shift;
+
+       rbsp->pos++;
+
+       if (value ||
+           (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0))) {
+               rbsp->num_consecutive_zeros = 0;
+       } else {
+               rbsp->num_consecutive_zeros++;
+       }
+
+       return 0;
+}
+
+static inline int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value)
+{
+       int i;
+       int bit;
+       unsigned int tmp = 0;
+
+       if (n > 8 * sizeof(*value))
+               return -EINVAL;
+
+       for (i = n; i > 0; i--) {
+               bit = rbsp_read_bit(rbsp);
+               if (bit < 0)
+                       return bit;
+               tmp |= bit << (i - 1);
+       }
+
+       if (value)
+               *value = tmp;
+
+       return 0;
+}
+
+static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value)
+{
+       int ret;
+
+       if (n > 8 * sizeof(value))
+               return -EINVAL;
+
+       while (n--) {
+               ret = rbsp_write_bit(rbsp, (value >> n) & 1);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int rbsp_read_uev(struct rbsp *rbsp, unsigned int *value)
+{
+       int leading_zero_bits = 0;
+       unsigned int tmp = 0;
+       int ret;
+
+       while ((ret = rbsp_read_bit(rbsp)) == 0)
+               leading_zero_bits++;
+       if (ret < 0)
+               return ret;
+
+       if (leading_zero_bits > 0) {
+               ret = rbsp_read_bits(rbsp, leading_zero_bits, &tmp);
+               if (ret)
+                       return ret;
+       }
+
+       if (value)
+               *value = (1 << leading_zero_bits) - 1 + tmp;
+
+       return 0;
+}
+
+static int rbsp_write_uev(struct rbsp *rbsp, unsigned int *value)
+{
+       int ret;
+       int leading_zero_bits;
+
+       if (!value)
+               return -EINVAL;
+
+       leading_zero_bits = ilog2(*value + 1);
+
+       ret = rbsp_write_bits(rbsp, leading_zero_bits, 0);
+       if (ret)
+               return ret;
+
+       return rbsp_write_bits(rbsp, leading_zero_bits + 1, *value + 1);
+}
+
+static int rbsp_read_sev(struct rbsp *rbsp, int *value)
+{
+       int ret;
+       unsigned int tmp;
+
+       ret = rbsp_read_uev(rbsp, &tmp);
+       if (ret)
+               return ret;
+
+       if (value) {
+               if (tmp & 1)
+                       *value = (tmp + 1) / 2;
+               else
+                       *value = -(tmp / 2);
+       }
+
+       return 0;
+}
+
+static int rbsp_write_sev(struct rbsp *rbsp, int *value)
+{
+       unsigned int tmp;
+
+       if (!value)
+               return -EINVAL;
+
+       if (*value > 0)
+               tmp = (2 * (*value)) | 1;
+       else
+               tmp = -2 * (*value);
+
+       return rbsp_write_uev(rbsp, &tmp);
+}
+
+static int __rbsp_write_bit(struct rbsp *rbsp, int *value)
+{
+       return rbsp_write_bit(rbsp, *value);
+}
+
+static int __rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int *value)
+{
+       return rbsp_write_bits(rbsp, n, *value);
+}
+
+static struct nal_h264_ops write = {
+       .rbsp_bit = __rbsp_write_bit,
+       .rbsp_bits = __rbsp_write_bits,
+       .rbsp_uev = rbsp_write_uev,
+       .rbsp_sev = rbsp_write_sev,
+};
+
+static int __rbsp_read_bit(struct rbsp *rbsp, int *value)
+{
+       int tmp = rbsp_read_bit(rbsp);
+
+       if (tmp < 0)
+               return tmp;
+       *value = tmp;
+
+       return 0;
+}
+
+static struct nal_h264_ops read = {
+       .rbsp_bit = __rbsp_read_bit,
+       .rbsp_bits = rbsp_read_bits,
+       .rbsp_uev = rbsp_read_uev,
+       .rbsp_sev = rbsp_read_sev,
+};
+
+static inline void rbsp_bit(struct rbsp *rbsp, int *value)
+{
+       if (rbsp->error)
+               return;
+       rbsp->error = rbsp->ops->rbsp_bit(rbsp, value);
+}
+
+static inline void rbsp_bits(struct rbsp *rbsp, int n, int *value)
+{
+       if (rbsp->error)
+               return;
+       rbsp->error = rbsp->ops->rbsp_bits(rbsp, n, value);
+}
+
+static inline void rbsp_uev(struct rbsp *rbsp, unsigned int *value)
+{
+       if (rbsp->error)
+               return;
+       rbsp->error = rbsp->ops->rbsp_uev(rbsp, value);
+}
+
+static inline void rbsp_sev(struct rbsp *rbsp, int *value)
+{
+       if (rbsp->error)
+               return;
+       rbsp->error = rbsp->ops->rbsp_sev(rbsp, value);
+}
+
+static void nal_h264_rbsp_trailing_bits(struct rbsp *rbsp)
+{
+       unsigned int rbsp_stop_one_bit = 1;
+       unsigned int rbsp_alignment_zero_bit = 0;
+
+       rbsp_bit(rbsp, &rbsp_stop_one_bit);
+       rbsp_bits(rbsp, round_up(rbsp->pos, 8) - rbsp->pos,
+                 &rbsp_alignment_zero_bit);
+}
+
+static void nal_h264_write_start_code_prefix(struct rbsp *rbsp)
+{
+       u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
+       int i = 4;
+
+       if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
+               rbsp->error = -EINVAL;
+               return;
+       }
+
+       p[0] = 0x00;
+       p[1] = 0x00;
+       p[2] = 0x00;
+       p[3] = 0x01;
+
+       rbsp->pos += i * 8;
+}
+
+static void nal_h264_read_start_code_prefix(struct rbsp *rbsp)
+{
+       u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
+       int i = 4;
+
+       if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
+               rbsp->error = -EINVAL;
+               return;
+       }
+
+       if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x01) {
+               rbsp->error = -EINVAL;
+               return;
+       }
+
+       rbsp->pos += i * 8;
+}
+
+static void nal_h264_write_filler_data(struct rbsp *rbsp)
+{
+       u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
+       int i;
+
+       /* Keep 1 byte extra for terminating the NAL unit */
+       i = rbsp->size - DIV_ROUND_UP(rbsp->pos, 8) - 1;
+       memset(p, 0xff, i);
+       rbsp->pos += i * 8;
+}
+
+static void nal_h264_read_filler_data(struct rbsp *rbsp)
+{
+       u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
+
+       while (*p == 0xff) {
+               if (DIV_ROUND_UP(rbsp->pos, 8) > rbsp->size) {
+                       rbsp->error = -EINVAL;
+                       return;
+               }
+
+               p++;
+               rbsp->pos += 8;
+       }
+}
+
+static void nal_h264_rbsp_hrd_parameters(struct rbsp *rbsp,
+                                        struct nal_h264_hrd_parameters *hrd)
+{
+       unsigned int i;
+
+       if (!hrd) {
+               rbsp->error = -EINVAL;
+               return;
+       }
+
+       rbsp_uev(rbsp, &hrd->cpb_cnt_minus1);
+       rbsp_bits(rbsp, 4, &hrd->bit_rate_scale);
+       rbsp_bits(rbsp, 4, &hrd->cpb_size_scale);
+
+       for (i = 0; i <= hrd->cpb_cnt_minus1; i++) {
+               rbsp_uev(rbsp, &hrd->bit_rate_value_minus1[i]);
+               rbsp_uev(rbsp, &hrd->cpb_size_value_minus1[i]);
+               rbsp_bit(rbsp, &hrd->cbr_flag[i]);
+       }
+
+       rbsp_bits(rbsp, 5, &hrd->initial_cpb_removal_delay_length_minus1);
+       rbsp_bits(rbsp, 5, &hrd->cpb_removal_delay_length_minus1);
+       rbsp_bits(rbsp, 5, &hrd->dpb_output_delay_length_minus1);
+       rbsp_bits(rbsp, 5, &hrd->time_offset_length);
+}
+
+static void nal_h264_rbsp_vui_parameters(struct rbsp *rbsp,
+                                        struct nal_h264_vui_parameters *vui)
+{
+       if (!vui) {
+               rbsp->error = -EINVAL;
+               return;
+       }
+
+       rbsp_bit(rbsp, &vui->aspect_ratio_info_present_flag);
+       if (vui->aspect_ratio_info_present_flag) {
+               rbsp_bits(rbsp, 8, &vui->aspect_ratio_idc);
+               if (vui->aspect_ratio_idc == 255) {
+                       rbsp_bits(rbsp, 16, &vui->sar_width);
+                       rbsp_bits(rbsp, 16, &vui->sar_height);
+               }
+       }
+
+       rbsp_bit(rbsp, &vui->overscan_info_present_flag);
+       if (vui->overscan_info_present_flag)
+               rbsp_bit(rbsp, &vui->overscan_appropriate_flag);
+
+       rbsp_bit(rbsp, &vui->video_signal_type_present_flag);
+       if (vui->video_signal_type_present_flag) {
+               rbsp_bits(rbsp, 3, &vui->video_format);
+               rbsp_bit(rbsp, &vui->video_full_range_flag);
+
+               rbsp_bit(rbsp, &vui->colour_description_present_flag);
+               if (vui->colour_description_present_flag) {
+                       rbsp_bits(rbsp, 8, &vui->colour_primaries);
+                       rbsp_bits(rbsp, 8, &vui->transfer_characteristics);
+                       rbsp_bits(rbsp, 8, &vui->matrix_coefficients);
+               }
+       }
+
+       rbsp_bit(rbsp, &vui->chroma_loc_info_present_flag);
+       if (vui->chroma_loc_info_present_flag) {
+               rbsp_uev(rbsp, &vui->chroma_sample_loc_type_top_field);
+               rbsp_uev(rbsp, &vui->chroma_sample_loc_type_bottom_field);
+       }
+
+       rbsp_bit(rbsp, &vui->timing_info_present_flag);
+       if (vui->timing_info_present_flag) {
+               rbsp_bits(rbsp, 32, &vui->num_units_in_tick);
+               rbsp_bits(rbsp, 32, &vui->time_scale);
+               rbsp_bit(rbsp, &vui->fixed_frame_rate_flag);
+       }
+
+       rbsp_bit(rbsp, &vui->nal_hrd_parameters_present_flag);
+       if (vui->nal_hrd_parameters_present_flag)
+               nal_h264_rbsp_hrd_parameters(rbsp, &vui->nal_hrd_parameters);
+
+       rbsp_bit(rbsp, &vui->vcl_hrd_parameters_present_flag);
+       if (vui->vcl_hrd_parameters_present_flag)
+               nal_h264_rbsp_hrd_parameters(rbsp, &vui->vcl_hrd_parameters);
+
+       if (vui->nal_hrd_parameters_present_flag ||
+           vui->vcl_hrd_parameters_present_flag)
+               rbsp_bit(rbsp, &vui->low_delay_hrd_flag);
+
+       rbsp_bit(rbsp, &vui->pic_struct_present_flag);
+
+       rbsp_bit(rbsp, &vui->bitstream_restriction_flag);
+       if (vui->bitstream_restriction_flag) {
+               rbsp_bit(rbsp, &vui->motion_vectors_over_pic_boundaries_flag);
+               rbsp_uev(rbsp, &vui->max_bytes_per_pic_denom);
+               rbsp_uev(rbsp, &vui->max_bits_per_mb_denom);
+               rbsp_uev(rbsp, &vui->log2_max_mv_length_horizontal);
+               rbsp_uev(rbsp, &vui->log21_max_mv_length_vertical);
+               rbsp_uev(rbsp, &vui->max_num_reorder_frames);
+               rbsp_uev(rbsp, &vui->max_dec_frame_buffering);
+       }
+}
+
+static void nal_h264_rbsp_sps(struct rbsp *rbsp, struct nal_h264_sps *sps)
+{
+       unsigned int i;
+
+       if (!sps) {
+               rbsp->error = -EINVAL;
+               return;
+       }
+
+       rbsp_bits(rbsp, 8, &sps->profile_idc);
+       rbsp_bit(rbsp, &sps->constraint_set0_flag);
+       rbsp_bit(rbsp, &sps->constraint_set1_flag);
+       rbsp_bit(rbsp, &sps->constraint_set2_flag);
+       rbsp_bit(rbsp, &sps->constraint_set3_flag);
+       rbsp_bit(rbsp, &sps->constraint_set4_flag);
+       rbsp_bit(rbsp, &sps->constraint_set5_flag);
+       rbsp_bits(rbsp, 2, &sps->reserved_zero_2bits);
+       rbsp_bits(rbsp, 8, &sps->level_idc);
+
+       rbsp_uev(rbsp, &sps->seq_parameter_set_id);
+
+       if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
+           sps->profile_idc == 122 || sps->profile_idc == 244 ||
+           sps->profile_idc == 44 || sps->profile_idc == 83 ||
+           sps->profile_idc == 86 || sps->profile_idc == 118 ||
+           sps->profile_idc == 128 || sps->profile_idc == 138 ||
+           sps->profile_idc == 139 || sps->profile_idc == 134 ||
+           sps->profile_idc == 135) {
+               rbsp_uev(rbsp, &sps->chroma_format_idc);
+
+               if (sps->chroma_format_idc == 3)
+                       rbsp_bit(rbsp, &sps->separate_colour_plane_flag);
+               rbsp_uev(rbsp, &sps->bit_depth_luma_minus8);
+               rbsp_uev(rbsp, &sps->bit_depth_chroma_minus8);
+               rbsp_bit(rbsp, &sps->qpprime_y_zero_transform_bypass_flag);
+               rbsp_bit(rbsp, &sps->seq_scaling_matrix_present_flag);
+               if (sps->seq_scaling_matrix_present_flag)
+                       rbsp->error = -EINVAL;
+       }
+
+       rbsp_uev(rbsp, &sps->log2_max_frame_num_minus4);
+
+       rbsp_uev(rbsp, &sps->pic_order_cnt_type);
+       switch (sps->pic_order_cnt_type) {
+       case 0:
+               rbsp_uev(rbsp, &sps->log2_max_pic_order_cnt_lsb_minus4);
+               break;
+       case 1:
+               rbsp_bit(rbsp, &sps->delta_pic_order_always_zero_flag);
+               rbsp_sev(rbsp, &sps->offset_for_non_ref_pic);
+               rbsp_sev(rbsp, &sps->offset_for_top_to_bottom_field);
+
+               rbsp_uev(rbsp, &sps->num_ref_frames_in_pic_order_cnt_cycle);
+               for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
+                       rbsp_sev(rbsp, &sps->offset_for_ref_frame[i]);
+               break;
+       default:
+               rbsp->error = -EINVAL;
+               break;
+       }
+
+       rbsp_uev(rbsp, &sps->max_num_ref_frames);
+       rbsp_bit(rbsp, &sps->gaps_in_frame_num_value_allowed_flag);
+       rbsp_uev(rbsp, &sps->pic_width_in_mbs_minus1);
+       rbsp_uev(rbsp, &sps->pic_height_in_map_units_minus1);
+
+       rbsp_bit(rbsp, &sps->frame_mbs_only_flag);
+       if (!sps->frame_mbs_only_flag)
+               rbsp_bit(rbsp, &sps->mb_adaptive_frame_field_flag);
+
+       rbsp_bit(rbsp, &sps->direct_8x8_inference_flag);
+
+       rbsp_bit(rbsp, &sps->frame_cropping_flag);
+       if (sps->frame_cropping_flag) {
+               rbsp_uev(rbsp, &sps->crop_left);
+               rbsp_uev(rbsp, &sps->crop_right);
+               rbsp_uev(rbsp, &sps->crop_top);
+               rbsp_uev(rbsp, &sps->crop_bottom);
+       }
+
+       rbsp_bit(rbsp, &sps->vui_parameters_present_flag);
+       if (sps->vui_parameters_present_flag)
+               nal_h264_rbsp_vui_parameters(rbsp, &sps->vui);
+}
+
+static void nal_h264_rbsp_pps(struct rbsp *rbsp, struct nal_h264_pps *pps)
+{
+       int i;
+
+       rbsp_uev(rbsp, &pps->pic_parameter_set_id);
+       rbsp_uev(rbsp, &pps->seq_parameter_set_id);
+       rbsp_bit(rbsp, &pps->entropy_coding_mode_flag);
+       rbsp_bit(rbsp, &pps->bottom_field_pic_order_in_frame_present_flag);
+       rbsp_uev(rbsp, &pps->num_slice_groups_minus1);
+       if (pps->num_slice_groups_minus1 > 0) {
+               rbsp_uev(rbsp, &pps->slice_group_map_type);
+               switch (pps->slice_group_map_type) {
+               case 0:
+                       for (i = 0; i < pps->num_slice_groups_minus1; i++)
+                               rbsp_uev(rbsp, &pps->run_length_minus1[i]);
+                       break;
+               case 2:
+                       for (i = 0; i < pps->num_slice_groups_minus1; i++) {
+                               rbsp_uev(rbsp, &pps->top_left[i]);
+                               rbsp_uev(rbsp, &pps->bottom_right[i]);
+                       }
+                       break;
+               case 3: case 4: case 5:
+                       rbsp_bit(rbsp, &pps->slice_group_change_direction_flag);
+                       rbsp_uev(rbsp, &pps->slice_group_change_rate_minus1);
+                       break;
+               case 6:
+                       rbsp_uev(rbsp, &pps->pic_size_in_map_units_minus1);
+                       for (i = 0; i < pps->pic_size_in_map_units_minus1; i++)
+                               rbsp_bits(rbsp,
+                                         order_base_2(pps->num_slice_groups_minus1 + 1),
+                                         &pps->slice_group_id[i]);
+                       break;
+               default:
+                       break;
+               }
+       }
+       rbsp_uev(rbsp, &pps->num_ref_idx_l0_default_active_minus1);
+       rbsp_uev(rbsp, &pps->num_ref_idx_l1_default_active_minus1);
+       rbsp_bit(rbsp, &pps->weighted_pred_flag);
+       rbsp_bits(rbsp, 2, &pps->weighted_bipred_idc);
+       rbsp_sev(rbsp, &pps->pic_init_qp_minus26);
+       rbsp_sev(rbsp, &pps->pic_init_qs_minus26);
+       rbsp_sev(rbsp, &pps->chroma_qp_index_offset);
+       rbsp_bit(rbsp, &pps->deblocking_filter_control_present_flag);
+       rbsp_bit(rbsp, &pps->constrained_intra_pred_flag);
+       rbsp_bit(rbsp, &pps->redundant_pic_cnt_present_flag);
+       if (/* more_rbsp_data() */ false) {
+               rbsp_bit(rbsp, &pps->transform_8x8_mode_flag);
+               rbsp_bit(rbsp, &pps->pic_scaling_matrix_present_flag);
+               if (pps->pic_scaling_matrix_present_flag)
+                       rbsp->error = -EINVAL;
+               rbsp_sev(rbsp, &pps->second_chroma_qp_index_offset);
+       }
+}
+
+/**
+ * nal_h264_write_sps() - Write SPS NAL unit into RBSP format
+ * @dev: device pointer
+ * @dest: the buffer that is filled with RBSP data
+ * @n: maximum size of @dest in bytes
+ * @sps: &struct nal_h264_sps to convert to RBSP
+ *
+ * Convert @sps to RBSP data and write it into @dest.
+ *
+ * The size of the SPS NAL unit is not known in advance and this function will
+ * fail, if @dest does not hold sufficient space for the SPS NAL unit.
+ *
+ * Return: number of bytes written to @dest or negative error code
+ */
+ssize_t nal_h264_write_sps(const struct device *dev,
+                          void *dest, size_t n, struct nal_h264_sps *sps)
+{
+       struct rbsp rbsp;
+       unsigned int forbidden_zero_bit = 0;
+       unsigned int nal_ref_idc = 0;
+       unsigned int nal_unit_type = SEQUENCE_PARAMETER_SET;
+
+       if (!dest)
+               return -EINVAL;
+
+       rbsp_init(&rbsp, dest, n, &write);
+
+       nal_h264_write_start_code_prefix(&rbsp);
+
+       rbsp_bit(&rbsp, &forbidden_zero_bit);
+       rbsp_bits(&rbsp, 2, &nal_ref_idc);
+       rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+       nal_h264_rbsp_sps(&rbsp, sps);
+
+       nal_h264_rbsp_trailing_bits(&rbsp);
+
+       if (rbsp.error)
+               return rbsp.error;
+
+       return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_write_sps);
+
+/**
+ * nal_h264_read_sps() - Read SPS NAL unit from RBSP format
+ * @dev: device pointer
+ * @sps: the &struct nal_h264_sps to fill from the RBSP data
+ * @src: the buffer that contains the RBSP data
+ * @n: size of @src in bytes
+ *
+ * Read RBSP data from @src and use it to fill @sps.
+ *
+ * Return: number of bytes read from @src or negative error code
+ */
+ssize_t nal_h264_read_sps(const struct device *dev,
+                         struct nal_h264_sps *sps, void *src, size_t n)
+{
+       struct rbsp rbsp;
+       unsigned int forbidden_zero_bit;
+       unsigned int nal_ref_idc;
+       unsigned int nal_unit_type;
+
+       if (!src)
+               return -EINVAL;
+
+       rbsp_init(&rbsp, src, n, &read);
+
+       nal_h264_read_start_code_prefix(&rbsp);
+
+       rbsp_bit(&rbsp, &forbidden_zero_bit);
+       rbsp_bits(&rbsp, 2, &nal_ref_idc);
+       rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+       if (rbsp.error ||
+           forbidden_zero_bit != 0 ||
+           nal_ref_idc != 0 ||
+           nal_unit_type != SEQUENCE_PARAMETER_SET)
+               return -EINVAL;
+
+       nal_h264_rbsp_sps(&rbsp, sps);
+
+       nal_h264_rbsp_trailing_bits(&rbsp);
+
+       if (rbsp.error)
+               return rbsp.error;
+
+       return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_read_sps);
+
+/**
+ * nal_h264_write_pps() - Write PPS NAL unit into RBSP format
+ * @dev: device pointer
+ * @dest: the buffer that is filled with RBSP data
+ * @n: maximum size of @dest in bytes
+ * @pps: &struct nal_h264_pps to convert to RBSP
+ *
+ * Convert @pps to RBSP data and write it into @dest.
+ *
+ * The size of the PPS NAL unit is not known in advance and this function will
+ * fail, if @dest does not hold sufficient space for the PPS NAL unit.
+ *
+ * Return: number of bytes written to @dest or negative error code
+ */
+ssize_t nal_h264_write_pps(const struct device *dev,
+                          void *dest, size_t n, struct nal_h264_pps *pps)
+{
+       struct rbsp rbsp;
+       unsigned int forbidden_zero_bit = 0;
+       unsigned int nal_ref_idc = 0;
+       unsigned int nal_unit_type = PICTURE_PARAMETER_SET;
+
+       if (!dest)
+               return -EINVAL;
+
+       rbsp_init(&rbsp, dest, n, &write);
+
+       nal_h264_write_start_code_prefix(&rbsp);
+
+       /* NAL unit header */
+       rbsp_bit(&rbsp, &forbidden_zero_bit);
+       rbsp_bits(&rbsp, 2, &nal_ref_idc);
+       rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+       nal_h264_rbsp_pps(&rbsp, pps);
+
+       nal_h264_rbsp_trailing_bits(&rbsp);
+
+       if (rbsp.error)
+               return rbsp.error;
+
+       return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_write_pps);
+
+/**
+ * nal_h264_read_pps() - Read PPS NAL unit from RBSP format
+ * @dev: device pointer
+ * @pps: the &struct nal_h264_pps to fill from the RBSP data
+ * @src: the buffer that contains the RBSP data
+ * @n: size of @src in bytes
+ *
+ * Read RBSP data from @src and use it to fill @pps.
+ *
+ * Return: number of bytes read from @src or negative error code
+ */
+ssize_t nal_h264_read_pps(const struct device *dev,
+                         struct nal_h264_pps *pps, void *src, size_t n)
+{
+       struct rbsp rbsp;
+
+       if (!src)
+               return -EINVAL;
+
+       rbsp_init(&rbsp, src, n, &read);
+
+       nal_h264_read_start_code_prefix(&rbsp);
+
+       /* NAL unit header */
+       rbsp.pos += 8;
+
+       nal_h264_rbsp_pps(&rbsp, pps);
+
+       nal_h264_rbsp_trailing_bits(&rbsp);
+
+       if (rbsp.error)
+               return rbsp.error;
+
+       return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_read_pps);
+
+/**
+ * nal_h264_write_filler() - Write filler data RBSP
+ * @dev: device pointer
+ * @dest: buffer to fill with filler data
+ * @n: size of the buffer to fill with filler data
+ *
+ * Write a filler data RBSP to @dest with a size of @n bytes and return the
+ * number of written filler data bytes.
+ *
+ * Use this function to generate dummy data in an RBSP data stream that can be
+ * safely ignored by h264 decoders.
+ *
+ * The RBSP format of the filler data is specified in Rec. ITU-T H.264
+ * (04/2017) 7.3.2.7 Filler data RBSP syntax.
+ *
+ * Return: number of filler data bytes (including marker) or negative error
+ */
+ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n)
+{
+       struct rbsp rbsp;
+       unsigned int forbidden_zero_bit = 0;
+       unsigned int nal_ref_idc = 0;
+       unsigned int nal_unit_type = FILLER_DATA;
+
+       if (!dest)
+               return -EINVAL;
+
+       rbsp_init(&rbsp, dest, n, &write);
+
+       nal_h264_write_start_code_prefix(&rbsp);
+
+       rbsp_bit(&rbsp, &forbidden_zero_bit);
+       rbsp_bits(&rbsp, 2, &nal_ref_idc);
+       rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+       nal_h264_write_filler_data(&rbsp);
+
+       nal_h264_rbsp_trailing_bits(&rbsp);
+
+       return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_write_filler);
+
+/**
+ * nal_h264_read_filler() - Read filler data RBSP
+ * @dev: device pointer
+ * @src: buffer with RBSP data that is read
+ * @n: maximum size of src that shall be read
+ *
+ * Read a filler data RBSP from @src up to a maximum size of @n bytes and
+ * return the size of the filler data in bytes including the marker.
+ *
+ * This function is used to parse filler data and skip the respective bytes in
+ * the RBSP data.
+ *
+ * The RBSP format of the filler data is specified in Rec. ITU-T H.264
+ * (04/2017) 7.3.2.7 Filler data RBSP syntax.
+ *
+ * Return: number of filler data bytes (including marker) or negative error
+ */
+ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n)
+{
+       struct rbsp rbsp;
+       unsigned int forbidden_zero_bit;
+       unsigned int nal_ref_idc;
+       unsigned int nal_unit_type;
+
+       if (!src)
+               return -EINVAL;
+
+       rbsp_init(&rbsp, src, n, &read);
+
+       nal_h264_read_start_code_prefix(&rbsp);
+
+       rbsp_bit(&rbsp, &forbidden_zero_bit);
+       rbsp_bits(&rbsp, 2, &nal_ref_idc);
+       rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+       if (rbsp.error)
+               return rbsp.error;
+       if (forbidden_zero_bit != 0 ||
+           nal_ref_idc != 0 ||
+           nal_unit_type != FILLER_DATA)
+               return -EINVAL;
+
+       nal_h264_read_filler_data(&rbsp);
+       nal_h264_rbsp_trailing_bits(&rbsp);
+
+       if (rbsp.error)
+               return rbsp.error;
+
+       return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_read_filler);
diff --git a/drivers/media/platform/allegro-dvt/nal-h264.h b/drivers/media/platform/allegro-dvt/nal-h264.h
new file mode 100644 (file)
index 0000000..2ba7cbc
--- /dev/null
@@ -0,0 +1,208 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Convert NAL units between raw byte sequence payloads (RBSP) and C structs.
+ */
+
+#ifndef __NAL_H264_H__
+#define __NAL_H264_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+/**
+ * struct nal_h264_hdr_parameters - HDR parameters
+ *
+ * C struct representation of the sequence parameter set NAL unit as defined by
+ * Rec. ITU-T H.264 (04/2017) E.1.2 HRD parameters syntax.
+ */
+struct nal_h264_hrd_parameters {
+       unsigned int cpb_cnt_minus1;
+       unsigned int bit_rate_scale;
+       unsigned int cpb_size_scale;
+       struct {
+               int bit_rate_value_minus1[16];
+               int cpb_size_value_minus1[16];
+               unsigned int cbr_flag[16];
+       };
+       unsigned int initial_cpb_removal_delay_length_minus1;
+       unsigned int cpb_removal_delay_length_minus1;
+       unsigned int dpb_output_delay_length_minus1;
+       unsigned int time_offset_length;
+};
+
+/**
+ * struct nal_h264_vui_parameters - VUI parameters
+ *
+ * C struct representation of the VUI parameters as defined by Rec. ITU-T
+ * H.264 (04/2017) E.1.1 VUI parameters syntax.
+ */
+struct nal_h264_vui_parameters {
+       unsigned int aspect_ratio_info_present_flag;
+       struct {
+               unsigned int aspect_ratio_idc;
+               unsigned int sar_width;
+               unsigned int sar_height;
+       };
+       unsigned int overscan_info_present_flag;
+       unsigned int overscan_appropriate_flag;
+       unsigned int video_signal_type_present_flag;
+       struct {
+               unsigned int video_format;
+               unsigned int video_full_range_flag;
+               unsigned int colour_description_present_flag;
+               struct {
+                       unsigned int colour_primaries;
+                       unsigned int transfer_characteristics;
+                       unsigned int matrix_coefficients;
+               };
+       };
+       unsigned int chroma_loc_info_present_flag;
+       struct {
+               unsigned int chroma_sample_loc_type_top_field;
+               unsigned int chroma_sample_loc_type_bottom_field;
+       };
+       unsigned int timing_info_present_flag;
+       struct {
+               unsigned int num_units_in_tick;
+               unsigned int time_scale;
+               unsigned int fixed_frame_rate_flag;
+       };
+       unsigned int nal_hrd_parameters_present_flag;
+       struct nal_h264_hrd_parameters nal_hrd_parameters;
+       unsigned int vcl_hrd_parameters_present_flag;
+       struct nal_h264_hrd_parameters vcl_hrd_parameters;
+       unsigned int low_delay_hrd_flag;
+       unsigned int pic_struct_present_flag;
+       unsigned int bitstream_restriction_flag;
+       struct {
+               unsigned int motion_vectors_over_pic_boundaries_flag;
+               unsigned int max_bytes_per_pic_denom;
+               unsigned int max_bits_per_mb_denom;
+               unsigned int log2_max_mv_length_horizontal;
+               unsigned int log21_max_mv_length_vertical;
+               unsigned int max_num_reorder_frames;
+               unsigned int max_dec_frame_buffering;
+       };
+};
+
+/**
+ * struct nal_h264_sps - Sequence parameter set
+ *
+ * C struct representation of the sequence parameter set NAL unit as defined by
+ * Rec. ITU-T H.264 (04/2017) 7.3.2.1.1 Sequence parameter set data syntax.
+ */
+struct nal_h264_sps {
+       unsigned int profile_idc;
+       unsigned int constraint_set0_flag;
+       unsigned int constraint_set1_flag;
+       unsigned int constraint_set2_flag;
+       unsigned int constraint_set3_flag;
+       unsigned int constraint_set4_flag;
+       unsigned int constraint_set5_flag;
+       unsigned int reserved_zero_2bits;
+       unsigned int level_idc;
+       unsigned int seq_parameter_set_id;
+       struct {
+               unsigned int chroma_format_idc;
+               unsigned int separate_colour_plane_flag;
+               unsigned int bit_depth_luma_minus8;
+               unsigned int bit_depth_chroma_minus8;
+               unsigned int qpprime_y_zero_transform_bypass_flag;
+               unsigned int seq_scaling_matrix_present_flag;
+       };
+       unsigned int log2_max_frame_num_minus4;
+       unsigned int pic_order_cnt_type;
+       union {
+               unsigned int log2_max_pic_order_cnt_lsb_minus4;
+               struct {
+                       unsigned int delta_pic_order_always_zero_flag;
+                       int offset_for_non_ref_pic;
+                       int offset_for_top_to_bottom_field;
+                       unsigned int num_ref_frames_in_pic_order_cnt_cycle;
+                       int offset_for_ref_frame[255];
+               };
+       };
+       unsigned int max_num_ref_frames;
+       unsigned int gaps_in_frame_num_value_allowed_flag;
+       unsigned int pic_width_in_mbs_minus1;
+       unsigned int pic_height_in_map_units_minus1;
+       unsigned int frame_mbs_only_flag;
+       unsigned int mb_adaptive_frame_field_flag;
+       unsigned int direct_8x8_inference_flag;
+       unsigned int frame_cropping_flag;
+       struct {
+               unsigned int crop_left;
+               unsigned int crop_right;
+               unsigned int crop_top;
+               unsigned int crop_bottom;
+       };
+       unsigned int vui_parameters_present_flag;
+       struct nal_h264_vui_parameters vui;
+};
+
+/**
+ * struct nal_h264_pps - Picture parameter set
+ *
+ * C struct representation of the picture parameter set NAL unit as defined by
+ * Rec. ITU-T H.264 (04/2017) 7.3.2.2 Picture parameter set RBSP syntax.
+ */
+struct nal_h264_pps {
+       unsigned int pic_parameter_set_id;
+       unsigned int seq_parameter_set_id;
+       unsigned int entropy_coding_mode_flag;
+       unsigned int bottom_field_pic_order_in_frame_present_flag;
+       unsigned int num_slice_groups_minus1;
+       unsigned int slice_group_map_type;
+       union {
+               unsigned int run_length_minus1[8];
+               struct {
+                       unsigned int top_left[8];
+                       unsigned int bottom_right[8];
+               };
+               struct {
+                       unsigned int slice_group_change_direction_flag;
+                       unsigned int slice_group_change_rate_minus1;
+               };
+               struct {
+                       unsigned int pic_size_in_map_units_minus1;
+                       unsigned int slice_group_id[8];
+               };
+       };
+       unsigned int num_ref_idx_l0_default_active_minus1;
+       unsigned int num_ref_idx_l1_default_active_minus1;
+       unsigned int weighted_pred_flag;
+       unsigned int weighted_bipred_idc;
+       int pic_init_qp_minus26;
+       int pic_init_qs_minus26;
+       int chroma_qp_index_offset;
+       unsigned int deblocking_filter_control_present_flag;
+       unsigned int constrained_intra_pred_flag;
+       unsigned int redundant_pic_cnt_present_flag;
+       struct {
+               unsigned int transform_8x8_mode_flag;
+               unsigned int pic_scaling_matrix_present_flag;
+               int second_chroma_qp_index_offset;
+       };
+};
+
+int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile);
+int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level);
+
+ssize_t nal_h264_write_sps(const struct device *dev,
+                          void *dest, size_t n, struct nal_h264_sps *sps);
+ssize_t nal_h264_read_sps(const struct device *dev,
+                         struct nal_h264_sps *sps, void *src, size_t n);
+void nal_h264_print_sps(const struct device *dev, struct nal_h264_sps *sps);
+
+ssize_t nal_h264_write_pps(const struct device *dev,
+                          void *dest, size_t n, struct nal_h264_pps *pps);
+ssize_t nal_h264_read_pps(const struct device *dev,
+                         struct nal_h264_pps *pps, void *src, size_t n);
+void nal_h264_print_pps(const struct device *dev, struct nal_h264_pps *pps);
+
+ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n);
+ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n);
+
+#endif /* __NAL_H264_H__ */
index e8996b1c3b3518000f2aac39ddffdc3fedf51ff2..ca59986b20f8a898cca16ceefdd40e8401a7a770 100644 (file)
@@ -20,8 +20,6 @@ menuconfig STAGING_MEDIA
 if STAGING_MEDIA && MEDIA_SUPPORT
 
 # Please keep them in alphabetic order
-source "drivers/staging/media/allegro-dvt/Kconfig"
-
 source "drivers/staging/media/atomisp/Kconfig"
 
 source "drivers/staging/media/hantro/Kconfig"
index 24b5873ff760846db724ee2a83fd6d20690b605e..716929a1a313000fc38858de575e45734358c4eb 100644 (file)
@@ -1,5 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_VIDEO_ALLEGRO_DVT)        += allegro-dvt/
 obj-$(CONFIG_INTEL_ATOMISP)     += atomisp/
 obj-$(CONFIG_VIDEO_IMX_MEDIA)  += imx/
 obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/
diff --git a/drivers/staging/media/allegro-dvt/Kconfig b/drivers/staging/media/allegro-dvt/Kconfig
deleted file mode 100644 (file)
index 6b7107d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-config VIDEO_ALLEGRO_DVT
-       tristate "Allegro DVT Video IP Core"
-       depends on VIDEO_DEV && VIDEO_V4L2
-       depends on ARCH_ZYNQMP || COMPILE_TEST
-       select V4L2_MEM2MEM_DEV
-       select VIDEOBUF2_DMA_CONTIG
-       select REGMAP
-       select REGMAP_MMIO
-       help
-         Support for the encoder video IP core by Allegro DVT. This core is
-         found for example on the Xilinx ZynqMP SoC in the EV family and is
-         called VCU in the reference manual.
-
-         To compile this driver as a module, choose M here: the module
-         will be called allegro.
diff --git a/drivers/staging/media/allegro-dvt/Makefile b/drivers/staging/media/allegro-dvt/Makefile
deleted file mode 100644 (file)
index 8e306dc..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-allegro-objs := allegro-core.o nal-h264.o allegro-mail.o
-
-obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
diff --git a/drivers/staging/media/allegro-dvt/TODO b/drivers/staging/media/allegro-dvt/TODO
deleted file mode 100644 (file)
index 99e19be..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-TODO:
-
-- This driver is waiting for the stateful encoder spec and corresponding
-  v4l2-compliance tests to be finalized.
diff --git a/drivers/staging/media/allegro-dvt/allegro-core.c b/drivers/staging/media/allegro-dvt/allegro-core.c
deleted file mode 100644 (file)
index 6404511..0000000
+++ /dev/null
@@ -1,3226 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
- *
- * Allegro DVT video encoder driver
- */
-
-#include <linux/bits.h>
-#include <linux/firmware.h>
-#include <linux/gcd.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/log2.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-dma-contig.h>
-#include <media/videobuf2-v4l2.h>
-
-#include "allegro-mail.h"
-#include "nal-h264.h"
-
-/*
- * Support up to 4k video streams. The hardware actually supports higher
- * resolutions, which are specified in PG252 June 6, 2018 (H.264/H.265 Video
- * Codec Unit v1.1) Chapter 3.
- */
-#define ALLEGRO_WIDTH_MIN 128
-#define ALLEGRO_WIDTH_DEFAULT 1920
-#define ALLEGRO_WIDTH_MAX 3840
-#define ALLEGRO_HEIGHT_MIN 64
-#define ALLEGRO_HEIGHT_DEFAULT 1080
-#define ALLEGRO_HEIGHT_MAX 2160
-
-#define ALLEGRO_FRAMERATE_DEFAULT ((struct v4l2_fract) { 30, 1 })
-
-#define ALLEGRO_GOP_SIZE_DEFAULT 25
-#define ALLEGRO_GOP_SIZE_MAX 1000
-
-/*
- * MCU Control Registers
- *
- * The Zynq UltraScale+ Devices Register Reference documents the registers
- * with an offset of 0x9000, which equals the size of the SRAM and one page
- * gap. The driver handles SRAM and registers separately and, therefore, is
- * oblivious of the offset.
- */
-#define AL5_MCU_RESET                   0x0000
-#define AL5_MCU_RESET_SOFT              BIT(0)
-#define AL5_MCU_RESET_REGS              BIT(1)
-#define AL5_MCU_RESET_MODE              0x0004
-#define AL5_MCU_RESET_MODE_SLEEP        BIT(0)
-#define AL5_MCU_RESET_MODE_HALT         BIT(1)
-#define AL5_MCU_STA                     0x0008
-#define AL5_MCU_STA_SLEEP               BIT(0)
-#define AL5_MCU_WAKEUP                  0x000c
-
-#define AL5_ICACHE_ADDR_OFFSET_MSB      0x0010
-#define AL5_ICACHE_ADDR_OFFSET_LSB      0x0014
-#define AL5_DCACHE_ADDR_OFFSET_MSB      0x0018
-#define AL5_DCACHE_ADDR_OFFSET_LSB      0x001c
-
-#define AL5_MCU_INTERRUPT               0x0100
-#define AL5_ITC_CPU_IRQ_MSK             0x0104
-#define AL5_ITC_CPU_IRQ_CLR             0x0108
-#define AL5_ITC_CPU_IRQ_STA             0x010C
-#define AL5_ITC_CPU_IRQ_STA_TRIGGERED   BIT(0)
-
-#define AXI_ADDR_OFFSET_IP              0x0208
-
-/*
- * The MCU accesses the system memory with a 2G offset compared to CPU
- * physical addresses.
- */
-#define MCU_CACHE_OFFSET SZ_2G
-
-/*
- * The driver needs to reserve some space at the beginning of capture buffers,
- * because it needs to write SPS/PPS NAL units. The encoder writes the actual
- * frame data after the offset.
- */
-#define ENCODER_STREAM_OFFSET SZ_64
-
-#define SIZE_MACROBLOCK 16
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debug level (0-2)");
-
-struct allegro_buffer {
-       void *vaddr;
-       dma_addr_t paddr;
-       size_t size;
-       struct list_head head;
-};
-
-struct allegro_dev;
-struct allegro_channel;
-
-struct allegro_mbox {
-       struct allegro_dev *dev;
-       unsigned int head;
-       unsigned int tail;
-       unsigned int data;
-       size_t size;
-       /* protect mailbox from simultaneous accesses */
-       struct mutex lock;
-};
-
-struct allegro_dev {
-       struct v4l2_device v4l2_dev;
-       struct video_device video_dev;
-       struct v4l2_m2m_dev *m2m_dev;
-       struct platform_device *plat_dev;
-
-       /* mutex protecting vb2_queue structure */
-       struct mutex lock;
-
-       struct regmap *regmap;
-       struct regmap *sram;
-
-       const struct fw_info *fw_info;
-       struct allegro_buffer firmware;
-       struct allegro_buffer suballocator;
-
-       struct completion init_complete;
-
-       /* The mailbox interface */
-       struct allegro_mbox *mbox_command;
-       struct allegro_mbox *mbox_status;
-
-       /*
-        * The downstream driver limits the users to 64 users, thus I can use
-        * a bitfield for the user_ids that are in use. See also user_id in
-        * struct allegro_channel.
-        */
-       unsigned long channel_user_ids;
-       struct list_head channels;
-};
-
-static struct regmap_config allegro_regmap_config = {
-       .name = "regmap",
-       .reg_bits = 32,
-       .val_bits = 32,
-       .reg_stride = 4,
-       .max_register = 0xfff,
-       .cache_type = REGCACHE_NONE,
-};
-
-static struct regmap_config allegro_sram_config = {
-       .name = "sram",
-       .reg_bits = 32,
-       .val_bits = 32,
-       .reg_stride = 4,
-       .max_register = 0x7fff,
-       .cache_type = REGCACHE_NONE,
-};
-
-enum allegro_state {
-       ALLEGRO_STATE_ENCODING,
-       ALLEGRO_STATE_DRAIN,
-       ALLEGRO_STATE_WAIT_FOR_BUFFER,
-       ALLEGRO_STATE_STOPPED,
-};
-
-#define fh_to_channel(__fh) container_of(__fh, struct allegro_channel, fh)
-
-struct allegro_channel {
-       struct allegro_dev *dev;
-       struct v4l2_fh fh;
-       struct v4l2_ctrl_handler ctrl_handler;
-
-       unsigned int width;
-       unsigned int height;
-       unsigned int stride;
-       struct v4l2_fract framerate;
-
-       enum v4l2_colorspace colorspace;
-       enum v4l2_ycbcr_encoding ycbcr_enc;
-       enum v4l2_quantization quantization;
-       enum v4l2_xfer_func xfer_func;
-
-       u32 pixelformat;
-       unsigned int sizeimage_raw;
-       unsigned int osequence;
-
-       u32 codec;
-       enum v4l2_mpeg_video_h264_profile profile;
-       enum v4l2_mpeg_video_h264_level level;
-       unsigned int sizeimage_encoded;
-       unsigned int csequence;
-
-       bool frame_rc_enable;
-       unsigned int bitrate;
-       unsigned int bitrate_peak;
-       unsigned int cpb_size;
-       unsigned int gop_size;
-
-       struct allegro_buffer config_blob;
-
-       unsigned int num_ref_idx_l0;
-       unsigned int num_ref_idx_l1;
-
-       struct v4l2_ctrl *mpeg_video_h264_profile;
-       struct v4l2_ctrl *mpeg_video_h264_level;
-       struct v4l2_ctrl *mpeg_video_h264_i_frame_qp;
-       struct v4l2_ctrl *mpeg_video_h264_max_qp;
-       struct v4l2_ctrl *mpeg_video_h264_min_qp;
-       struct v4l2_ctrl *mpeg_video_h264_p_frame_qp;
-       struct v4l2_ctrl *mpeg_video_h264_b_frame_qp;
-       struct v4l2_ctrl *mpeg_video_frame_rc_enable;
-       struct { /* video bitrate mode control cluster */
-               struct v4l2_ctrl *mpeg_video_bitrate_mode;
-               struct v4l2_ctrl *mpeg_video_bitrate;
-               struct v4l2_ctrl *mpeg_video_bitrate_peak;
-       };
-       struct v4l2_ctrl *mpeg_video_cpb_size;
-       struct v4l2_ctrl *mpeg_video_gop_size;
-
-       /* user_id is used to identify the channel during CREATE_CHANNEL */
-       /* not sure, what to set here and if this is actually required */
-       int user_id;
-       /* channel_id is set by the mcu and used by all later commands */
-       int mcu_channel_id;
-
-       struct list_head buffers_reference;
-       struct list_head buffers_intermediate;
-
-       struct list_head source_shadow_list;
-       struct list_head stream_shadow_list;
-       /* protect shadow lists of buffers passed to firmware */
-       struct mutex shadow_list_lock;
-
-       struct list_head list;
-       struct completion completion;
-
-       unsigned int error;
-       enum allegro_state state;
-};
-
-static inline int
-allegro_set_state(struct allegro_channel *channel, enum allegro_state state)
-{
-       channel->state = state;
-
-       return 0;
-}
-
-static inline enum allegro_state
-allegro_get_state(struct allegro_channel *channel)
-{
-       return channel->state;
-}
-
-struct allegro_m2m_buffer {
-       struct v4l2_m2m_buffer buf;
-       struct list_head head;
-};
-
-#define to_allegro_m2m_buffer(__buf) \
-       container_of(__buf, struct allegro_m2m_buffer, buf)
-
-struct fw_info {
-       unsigned int id;
-       unsigned int id_codec;
-       char *version;
-       unsigned int mailbox_cmd;
-       unsigned int mailbox_status;
-       size_t mailbox_size;
-       enum mcu_msg_version mailbox_version;
-       size_t suballocator_size;
-};
-
-static const struct fw_info supported_firmware[] = {
-       {
-               .id = 18296,
-               .id_codec = 96272,
-               .version = "v2018.2",
-               .mailbox_cmd = 0x7800,
-               .mailbox_status = 0x7c00,
-               .mailbox_size = 0x400 - 0x8,
-               .mailbox_version = MCU_MSG_VERSION_2018_2,
-               .suballocator_size = SZ_16M,
-       }, {
-               .id = 14680,
-               .id_codec = 126572,
-               .version = "v2019.2",
-               .mailbox_cmd = 0x7000,
-               .mailbox_status = 0x7800,
-               .mailbox_size = 0x800 - 0x8,
-               .mailbox_version = MCU_MSG_VERSION_2019_2,
-               .suballocator_size = SZ_32M,
-       },
-};
-
-static inline u32 to_mcu_addr(struct allegro_dev *dev, dma_addr_t phys)
-{
-       if (upper_32_bits(phys) || (lower_32_bits(phys) & MCU_CACHE_OFFSET))
-               v4l2_warn(&dev->v4l2_dev,
-                         "address %pad is outside mcu window\n", &phys);
-
-       return lower_32_bits(phys) | MCU_CACHE_OFFSET;
-}
-
-static inline u32 to_mcu_size(struct allegro_dev *dev, size_t size)
-{
-       return lower_32_bits(size);
-}
-
-static inline u32 to_codec_addr(struct allegro_dev *dev, dma_addr_t phys)
-{
-       if (upper_32_bits(phys))
-               v4l2_warn(&dev->v4l2_dev,
-                         "address %pad cannot be used by codec\n", &phys);
-
-       return lower_32_bits(phys);
-}
-
-static inline u64 ptr_to_u64(const void *ptr)
-{
-       return (uintptr_t)ptr;
-}
-
-/* Helper functions for channel and user operations */
-
-static unsigned long allegro_next_user_id(struct allegro_dev *dev)
-{
-       if (dev->channel_user_ids == ~0UL)
-               return -EBUSY;
-
-       return ffz(dev->channel_user_ids);
-}
-
-static struct allegro_channel *
-allegro_find_channel_by_user_id(struct allegro_dev *dev,
-                               unsigned int user_id)
-{
-       struct allegro_channel *channel;
-
-       list_for_each_entry(channel, &dev->channels, list) {
-               if (channel->user_id == user_id)
-                       return channel;
-       }
-
-       return ERR_PTR(-EINVAL);
-}
-
-static struct allegro_channel *
-allegro_find_channel_by_channel_id(struct allegro_dev *dev,
-                                  unsigned int channel_id)
-{
-       struct allegro_channel *channel;
-
-       list_for_each_entry(channel, &dev->channels, list) {
-               if (channel->mcu_channel_id == channel_id)
-                       return channel;
-       }
-
-       return ERR_PTR(-EINVAL);
-}
-
-static inline bool channel_exists(struct allegro_channel *channel)
-{
-       return channel->mcu_channel_id != -1;
-}
-
-#define AL_ERROR                       0x80
-#define AL_ERR_INIT_FAILED             0x81
-#define AL_ERR_NO_FRAME_DECODED                0x82
-#define AL_ERR_RESOLUTION_CHANGE       0x85
-#define AL_ERR_NO_MEMORY               0x87
-#define AL_ERR_STREAM_OVERFLOW         0x88
-#define AL_ERR_TOO_MANY_SLICES         0x89
-#define AL_ERR_BUF_NOT_READY           0x8c
-#define AL_ERR_NO_CHANNEL_AVAILABLE    0x8d
-#define AL_ERR_RESOURCE_UNAVAILABLE    0x8e
-#define AL_ERR_NOT_ENOUGH_CORES                0x8f
-#define AL_ERR_REQUEST_MALFORMED       0x90
-#define AL_ERR_CMD_NOT_ALLOWED         0x91
-#define AL_ERR_INVALID_CMD_VALUE       0x92
-
-static inline const char *allegro_err_to_string(unsigned int err)
-{
-       switch (err) {
-       case AL_ERR_INIT_FAILED:
-               return "initialization failed";
-       case AL_ERR_NO_FRAME_DECODED:
-               return "no frame decoded";
-       case AL_ERR_RESOLUTION_CHANGE:
-               return "resolution change";
-       case AL_ERR_NO_MEMORY:
-               return "out of memory";
-       case AL_ERR_STREAM_OVERFLOW:
-               return "stream buffer overflow";
-       case AL_ERR_TOO_MANY_SLICES:
-               return "too many slices";
-       case AL_ERR_BUF_NOT_READY:
-               return "buffer not ready";
-       case AL_ERR_NO_CHANNEL_AVAILABLE:
-               return "no channel available";
-       case AL_ERR_RESOURCE_UNAVAILABLE:
-               return "resource unavailable";
-       case AL_ERR_NOT_ENOUGH_CORES:
-               return "not enough cores";
-       case AL_ERR_REQUEST_MALFORMED:
-               return "request malformed";
-       case AL_ERR_CMD_NOT_ALLOWED:
-               return "command not allowed";
-       case AL_ERR_INVALID_CMD_VALUE:
-               return "invalid command value";
-       case AL_ERROR:
-       default:
-               return "unknown error";
-       }
-}
-
-static unsigned int estimate_stream_size(unsigned int width,
-                                        unsigned int height)
-{
-       unsigned int offset = ENCODER_STREAM_OFFSET;
-       unsigned int num_blocks = DIV_ROUND_UP(width, SIZE_MACROBLOCK) *
-                                       DIV_ROUND_UP(height, SIZE_MACROBLOCK);
-       unsigned int pcm_size = SZ_256;
-       unsigned int partition_table = SZ_256;
-
-       return round_up(offset + num_blocks * pcm_size + partition_table, 32);
-}
-
-static enum v4l2_mpeg_video_h264_level
-select_minimum_h264_level(unsigned int width, unsigned int height)
-{
-       unsigned int pic_width_in_mb = DIV_ROUND_UP(width, SIZE_MACROBLOCK);
-       unsigned int frame_height_in_mb = DIV_ROUND_UP(height, SIZE_MACROBLOCK);
-       unsigned int frame_size_in_mb = pic_width_in_mb * frame_height_in_mb;
-       enum v4l2_mpeg_video_h264_level level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
-
-       /*
-        * The level limits are specified in Rec. ITU-T H.264 Annex A.3.1 and
-        * also specify limits regarding bit rate and CBP size. Only approximate
-        * the levels using the frame size.
-        *
-        * Level 5.1 allows up to 4k video resolution.
-        */
-       if (frame_size_in_mb <= 99)
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
-       else if (frame_size_in_mb <= 396)
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
-       else if (frame_size_in_mb <= 792)
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
-       else if (frame_size_in_mb <= 1620)
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
-       else if (frame_size_in_mb <= 3600)
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
-       else if (frame_size_in_mb <= 5120)
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
-       else if (frame_size_in_mb <= 8192)
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
-       else if (frame_size_in_mb <= 8704)
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
-       else if (frame_size_in_mb <= 22080)
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
-       else
-               level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
-
-       return level;
-}
-
-static unsigned int maximum_bitrate(enum v4l2_mpeg_video_h264_level level)
-{
-       switch (level) {
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
-               return 64000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
-               return 128000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
-               return 192000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
-               return 384000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
-               return 768000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
-               return 2000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
-               return 4000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
-               return 4000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
-               return 10000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
-               return 14000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
-               return 20000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
-               return 20000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
-               return 50000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
-               return 50000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
-               return 135000000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
-       default:
-               return 240000000;
-       }
-}
-
-static unsigned int maximum_cpb_size(enum v4l2_mpeg_video_h264_level level)
-{
-       switch (level) {
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
-               return 175;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
-               return 350;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
-               return 500;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
-               return 1000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
-               return 2000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
-               return 2000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
-               return 4000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
-               return 4000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
-               return 10000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
-               return 14000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
-               return 20000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
-               return 25000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
-               return 62500;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
-               return 62500;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
-               return 135000;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
-       default:
-               return 240000;
-       }
-}
-
-static const struct fw_info *
-allegro_get_firmware_info(struct allegro_dev *dev,
-                         const struct firmware *fw,
-                         const struct firmware *fw_codec)
-{
-       int i;
-       unsigned int id = fw->size;
-       unsigned int id_codec = fw_codec->size;
-
-       for (i = 0; i < ARRAY_SIZE(supported_firmware); i++)
-               if (supported_firmware[i].id == id &&
-                   supported_firmware[i].id_codec == id_codec)
-                       return &supported_firmware[i];
-
-       return NULL;
-}
-
-/*
- * Buffers that are used internally by the MCU.
- */
-
-static int allegro_alloc_buffer(struct allegro_dev *dev,
-                               struct allegro_buffer *buffer, size_t size)
-{
-       buffer->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size,
-                                          &buffer->paddr, GFP_KERNEL);
-       if (!buffer->vaddr)
-               return -ENOMEM;
-       buffer->size = size;
-
-       return 0;
-}
-
-static void allegro_free_buffer(struct allegro_dev *dev,
-                               struct allegro_buffer *buffer)
-{
-       if (buffer->vaddr) {
-               dma_free_coherent(&dev->plat_dev->dev, buffer->size,
-                                 buffer->vaddr, buffer->paddr);
-               buffer->vaddr = NULL;
-               buffer->size = 0;
-       }
-}
-
-/*
- * Mailbox interface to send messages to the MCU.
- */
-
-static void allegro_mcu_interrupt(struct allegro_dev *dev);
-static void allegro_handle_message(struct allegro_dev *dev,
-                                  union mcu_msg_response *msg);
-
-static struct allegro_mbox *allegro_mbox_init(struct allegro_dev *dev,
-                                             unsigned int base, size_t size)
-{
-       struct allegro_mbox *mbox;
-
-       mbox = devm_kmalloc(&dev->plat_dev->dev, sizeof(*mbox), GFP_KERNEL);
-       if (!mbox)
-               return ERR_PTR(-ENOMEM);
-
-       mbox->dev = dev;
-
-       mbox->head = base;
-       mbox->tail = base + 0x4;
-       mbox->data = base + 0x8;
-       mbox->size = size;
-       mutex_init(&mbox->lock);
-
-       regmap_write(dev->sram, mbox->head, 0);
-       regmap_write(dev->sram, mbox->tail, 0);
-
-       return mbox;
-}
-
-static int allegro_mbox_write(struct allegro_mbox *mbox,
-                             const u32 *src, size_t size)
-{
-       struct regmap *sram = mbox->dev->sram;
-       unsigned int tail;
-       size_t size_no_wrap;
-       int err = 0;
-       int stride = regmap_get_reg_stride(sram);
-
-       if (!src)
-               return -EINVAL;
-
-       if (size > mbox->size)
-               return -EINVAL;
-
-       mutex_lock(&mbox->lock);
-       regmap_read(sram, mbox->tail, &tail);
-       if (tail > mbox->size) {
-               err = -EIO;
-               goto out;
-       }
-       size_no_wrap = min(size, mbox->size - (size_t)tail);
-       regmap_bulk_write(sram, mbox->data + tail,
-                         src, size_no_wrap / stride);
-       regmap_bulk_write(sram, mbox->data,
-                         src + (size_no_wrap / sizeof(*src)),
-                         (size - size_no_wrap) / stride);
-       regmap_write(sram, mbox->tail, (tail + size) % mbox->size);
-
-out:
-       mutex_unlock(&mbox->lock);
-
-       return err;
-}
-
-static ssize_t allegro_mbox_read(struct allegro_mbox *mbox,
-                                u32 *dst, size_t nbyte)
-{
-       struct {
-               u16 length;
-               u16 type;
-       } __attribute__ ((__packed__)) *header;
-       struct regmap *sram = mbox->dev->sram;
-       unsigned int head;
-       ssize_t size;
-       size_t body_no_wrap;
-       int stride = regmap_get_reg_stride(sram);
-
-       regmap_read(sram, mbox->head, &head);
-       if (head > mbox->size)
-               return -EIO;
-
-       /* Assume that the header does not wrap. */
-       regmap_bulk_read(sram, mbox->data + head,
-                        dst, sizeof(*header) / stride);
-       header = (void *)dst;
-       size = header->length + sizeof(*header);
-       if (size > mbox->size || size & 0x3)
-               return -EIO;
-       if (size > nbyte)
-               return -EINVAL;
-
-       /*
-        * The message might wrap within the mailbox. If the message does not
-        * wrap, the first read will read the entire message, otherwise the
-        * first read will read message until the end of the mailbox and the
-        * second read will read the remaining bytes from the beginning of the
-        * mailbox.
-        *
-        * Skip the header, as was already read to get the size of the body.
-        */
-       body_no_wrap = min((size_t)header->length,
-                          (size_t)(mbox->size - (head + sizeof(*header))));
-       regmap_bulk_read(sram, mbox->data + head + sizeof(*header),
-                        dst + (sizeof(*header) / sizeof(*dst)),
-                        body_no_wrap / stride);
-       regmap_bulk_read(sram, mbox->data,
-                        dst + (sizeof(*header) + body_no_wrap) / sizeof(*dst),
-                        (header->length - body_no_wrap) / stride);
-
-       regmap_write(sram, mbox->head, (head + size) % mbox->size);
-
-       return size;
-}
-
-/**
- * allegro_mbox_send() - Send a message via the mailbox
- * @mbox: the mailbox which is used to send the message
- * @msg: the message to send
- */
-static int allegro_mbox_send(struct allegro_mbox *mbox, void *msg)
-{
-       struct allegro_dev *dev = mbox->dev;
-       ssize_t size;
-       int err;
-       u32 *tmp;
-
-       tmp = kzalloc(mbox->size, GFP_KERNEL);
-       if (!tmp) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       size = allegro_encode_mail(tmp, msg);
-
-       err = allegro_mbox_write(mbox, tmp, size);
-       kfree(tmp);
-       if (err)
-               goto out;
-
-       allegro_mcu_interrupt(dev);
-
-out:
-       return err;
-}
-
-/**
- * allegro_mbox_notify() - Notify the mailbox about a new message
- * @mbox: The allegro_mbox to notify
- */
-static void allegro_mbox_notify(struct allegro_mbox *mbox)
-{
-       struct allegro_dev *dev = mbox->dev;
-       union mcu_msg_response *msg;
-       ssize_t size;
-       u32 *tmp;
-       int err;
-
-       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
-       if (!msg)
-               return;
-
-       msg->header.version = dev->fw_info->mailbox_version;
-
-       tmp = kmalloc(mbox->size, GFP_KERNEL);
-       if (!tmp)
-               goto out;
-
-       size = allegro_mbox_read(mbox, tmp, mbox->size);
-       if (size < 0)
-               goto out;
-
-       err = allegro_decode_mail(msg, tmp);
-       if (err)
-               goto out;
-
-       allegro_handle_message(dev, msg);
-
-out:
-       kfree(tmp);
-       kfree(msg);
-}
-
-static void allegro_mcu_send_init(struct allegro_dev *dev,
-                                 dma_addr_t suballoc_dma, size_t suballoc_size)
-{
-       struct mcu_msg_init_request msg;
-
-       memset(&msg, 0, sizeof(msg));
-
-       msg.header.type = MCU_MSG_TYPE_INIT;
-       msg.header.version = dev->fw_info->mailbox_version;
-
-       msg.suballoc_dma = to_mcu_addr(dev, suballoc_dma);
-       msg.suballoc_size = to_mcu_size(dev, suballoc_size);
-
-       /* disable L2 cache */
-       msg.l2_cache[0] = -1;
-       msg.l2_cache[1] = -1;
-       msg.l2_cache[2] = -1;
-
-       allegro_mbox_send(dev->mbox_command, &msg);
-}
-
-static u32 v4l2_pixelformat_to_mcu_format(u32 pixelformat)
-{
-       switch (pixelformat) {
-       case V4L2_PIX_FMT_NV12:
-               /* AL_420_8BITS: 0x100 -> NV12, 0x88 -> 8 bit */
-               return 0x100 | 0x88;
-       default:
-               return -EINVAL;
-       }
-}
-
-static u32 v4l2_colorspace_to_mcu_colorspace(enum v4l2_colorspace colorspace)
-{
-       switch (colorspace) {
-       case V4L2_COLORSPACE_REC709:
-               return 2;
-       case V4L2_COLORSPACE_SMPTE170M:
-               return 3;
-       case V4L2_COLORSPACE_SMPTE240M:
-               return 4;
-       case V4L2_COLORSPACE_SRGB:
-               return 7;
-       default:
-               /* UNKNOWN */
-               return 0;
-       }
-}
-
-static u8 v4l2_profile_to_mcu_profile(enum v4l2_mpeg_video_h264_profile profile)
-{
-       switch (profile) {
-       case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
-       default:
-               return 66;
-       }
-}
-
-static u16 v4l2_level_to_mcu_level(enum v4l2_mpeg_video_h264_level level)
-{
-       switch (level) {
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
-               return 10;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
-               return 11;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
-               return 12;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
-               return 13;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
-               return 20;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
-               return 21;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
-               return 22;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
-               return 30;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
-               return 31;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
-               return 32;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
-               return 40;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
-               return 41;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
-               return 42;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
-               return 50;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
-       default:
-               return 51;
-       }
-}
-
-static u32
-v4l2_bitrate_mode_to_mcu_mode(enum v4l2_mpeg_video_bitrate_mode mode)
-{
-       switch (mode) {
-       case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
-               return 2;
-       case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
-       default:
-               return 1;
-       }
-}
-
-static u32 v4l2_cpb_size_to_mcu(unsigned int cpb_size, unsigned int bitrate)
-{
-       unsigned int cpb_size_kbit;
-       unsigned int bitrate_kbps;
-
-       /*
-        * The mcu expects the CPB size in units of a 90 kHz clock, but the
-        * channel follows the V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE and stores
-        * the CPB size in kilobytes.
-        */
-       cpb_size_kbit = cpb_size * BITS_PER_BYTE;
-       bitrate_kbps = bitrate / 1000;
-
-       return (cpb_size_kbit * 90000) / bitrate_kbps;
-}
-
-static s16 get_qp_delta(int minuend, int subtrahend)
-{
-       if (minuend == subtrahend)
-               return -1;
-       else
-               return minuend - subtrahend;
-}
-
-static int fill_create_channel_param(struct allegro_channel *channel,
-                                    struct create_channel_param *param)
-{
-       int i_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_i_frame_qp);
-       int p_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_p_frame_qp);
-       int b_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_b_frame_qp);
-       int bitrate_mode = v4l2_ctrl_g_ctrl(channel->mpeg_video_bitrate_mode);
-
-       param->width = channel->width;
-       param->height = channel->height;
-       param->format = v4l2_pixelformat_to_mcu_format(channel->pixelformat);
-       param->colorspace =
-               v4l2_colorspace_to_mcu_colorspace(channel->colorspace);
-       param->src_mode = 0x0;
-       param->profile = v4l2_profile_to_mcu_profile(channel->profile);
-       param->constraint_set_flags = BIT(1);
-       param->codec = channel->codec;
-       param->level = v4l2_level_to_mcu_level(channel->level);
-       param->tier = 0;
-
-       param->log2_max_poc = 10;
-       param->log2_max_frame_num = 4;
-       param->temporal_mvp_enable = 1;
-
-       param->dbf_ovr_en = 1;
-       param->rdo_cost_mode = 1;
-       param->custom_lda = 1;
-       param->lf = 1;
-       param->lf_x_tile = 1;
-       param->lf_x_slice = 1;
-
-       param->src_bit_depth = 8;
-
-       param->beta_offset = -1;
-       param->tc_offset = -1;
-       param->num_slices = 1;
-       param->me_range[0] = 8;
-       param->me_range[1] = 8;
-       param->me_range[2] = 16;
-       param->me_range[3] = 16;
-       param->max_cu_size = ilog2(SIZE_MACROBLOCK);
-       param->min_cu_size = ilog2(8);
-       param->max_tu_size = 2;
-       param->min_tu_size = 2;
-       param->max_transfo_depth_intra = 1;
-       param->max_transfo_depth_inter = 1;
-
-       param->prefetch_auto = 0;
-       param->prefetch_mem_offset = 0;
-       param->prefetch_mem_size = 0;
-
-       param->rate_control_mode = channel->frame_rc_enable ?
-               v4l2_bitrate_mode_to_mcu_mode(bitrate_mode) : 0;
-
-       param->cpb_size = v4l2_cpb_size_to_mcu(channel->cpb_size,
-                                              channel->bitrate_peak);
-       /* Shall be ]0;cpb_size in 90 kHz units]. Use maximum value. */
-       param->initial_rem_delay = param->cpb_size;
-       param->framerate = DIV_ROUND_UP(channel->framerate.numerator,
-                                       channel->framerate.denominator);
-       param->clk_ratio = channel->framerate.denominator == 1001 ? 1001 : 1000;
-       param->target_bitrate = channel->bitrate;
-       param->max_bitrate = channel->bitrate_peak;
-       param->initial_qp = i_frame_qp;
-       param->min_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_min_qp);
-       param->max_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_max_qp);
-       param->ip_delta = get_qp_delta(i_frame_qp, p_frame_qp);
-       param->pb_delta = get_qp_delta(p_frame_qp, b_frame_qp);
-       param->golden_ref = 0;
-       param->golden_delta = 2;
-       param->golden_ref_frequency = 10;
-       param->rate_control_option = 0x00000000;
-
-       param->num_pixel = channel->width + channel->height;
-       param->max_psnr = 4200;
-       param->max_pixel_value = 255;
-
-       param->gop_ctrl_mode = 0x00000002;
-       param->freq_idr = channel->gop_size;
-       param->freq_lt = 0;
-       param->gdr_mode = 0x00000000;
-       param->gop_length = channel->gop_size;
-       param->subframe_latency = 0x00000000;
-
-       param->lda_factors[0] = 51;
-       param->lda_factors[1] = 90;
-       param->lda_factors[2] = 151;
-       param->lda_factors[3] = 151;
-       param->lda_factors[4] = 151;
-       param->lda_factors[5] = 151;
-
-       param->max_num_merge_cand = 5;
-
-       return 0;
-}
-
-static int allegro_mcu_send_create_channel(struct allegro_dev *dev,
-                                          struct allegro_channel *channel)
-{
-       struct mcu_msg_create_channel msg;
-       struct allegro_buffer *blob = &channel->config_blob;
-       struct create_channel_param param;
-       size_t size;
-
-       memset(&param, 0, sizeof(param));
-       fill_create_channel_param(channel, &param);
-       allegro_alloc_buffer(dev, blob, sizeof(struct create_channel_param));
-       param.version = dev->fw_info->mailbox_version;
-       size = allegro_encode_config_blob(blob->vaddr, &param);
-
-       memset(&msg, 0, sizeof(msg));
-
-       msg.header.type = MCU_MSG_TYPE_CREATE_CHANNEL;
-       msg.header.version = dev->fw_info->mailbox_version;
-
-       msg.user_id = channel->user_id;
-
-       msg.blob = blob->vaddr;
-       msg.blob_size = size;
-       msg.blob_mcu_addr = to_mcu_addr(dev, blob->paddr);
-
-       allegro_mbox_send(dev->mbox_command, &msg);
-
-       return 0;
-}
-
-static int allegro_mcu_send_destroy_channel(struct allegro_dev *dev,
-                                           struct allegro_channel *channel)
-{
-       struct mcu_msg_destroy_channel msg;
-
-       memset(&msg, 0, sizeof(msg));
-
-       msg.header.type = MCU_MSG_TYPE_DESTROY_CHANNEL;
-       msg.header.version = dev->fw_info->mailbox_version;
-
-       msg.channel_id = channel->mcu_channel_id;
-
-       allegro_mbox_send(dev->mbox_command, &msg);
-
-       return 0;
-}
-
-static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev,
-                                             struct allegro_channel *channel,
-                                             dma_addr_t paddr,
-                                             unsigned long size,
-                                             u64 stream_id)
-{
-       struct mcu_msg_put_stream_buffer msg;
-
-       memset(&msg, 0, sizeof(msg));
-
-       msg.header.type = MCU_MSG_TYPE_PUT_STREAM_BUFFER;
-       msg.header.version = dev->fw_info->mailbox_version;
-
-       msg.channel_id = channel->mcu_channel_id;
-       msg.dma_addr = to_codec_addr(dev, paddr);
-       msg.mcu_addr = to_mcu_addr(dev, paddr);
-       msg.size = size;
-       msg.offset = ENCODER_STREAM_OFFSET;
-       /* copied to mcu_msg_encode_frame_response */
-       msg.stream_id = stream_id;
-
-       allegro_mbox_send(dev->mbox_command, &msg);
-
-       return 0;
-}
-
-static int allegro_mcu_send_encode_frame(struct allegro_dev *dev,
-                                        struct allegro_channel *channel,
-                                        dma_addr_t src_y, dma_addr_t src_uv,
-                                        u64 src_handle)
-{
-       struct mcu_msg_encode_frame msg;
-
-       memset(&msg, 0, sizeof(msg));
-
-       msg.header.type = MCU_MSG_TYPE_ENCODE_FRAME;
-       msg.header.version = dev->fw_info->mailbox_version;
-
-       msg.channel_id = channel->mcu_channel_id;
-       msg.encoding_options = AL_OPT_FORCE_LOAD;
-       msg.pps_qp = 26; /* qp are relative to 26 */
-       msg.user_param = 0; /* copied to mcu_msg_encode_frame_response */
-       /* src_handle is copied to mcu_msg_encode_frame_response */
-       msg.src_handle = src_handle;
-       msg.src_y = to_codec_addr(dev, src_y);
-       msg.src_uv = to_codec_addr(dev, src_uv);
-       msg.stride = channel->stride;
-       msg.ep2 = 0x0;
-       msg.ep2_v = to_mcu_addr(dev, msg.ep2);
-
-       allegro_mbox_send(dev->mbox_command, &msg);
-
-       return 0;
-}
-
-static int allegro_mcu_wait_for_init_timeout(struct allegro_dev *dev,
-                                            unsigned long timeout_ms)
-{
-       unsigned long tmo;
-
-       tmo = wait_for_completion_timeout(&dev->init_complete,
-                                         msecs_to_jiffies(timeout_ms));
-       if (tmo == 0)
-               return -ETIMEDOUT;
-
-       reinit_completion(&dev->init_complete);
-       return 0;
-}
-
-static int allegro_mcu_push_buffer_internal(struct allegro_channel *channel,
-                                           enum mcu_msg_type type)
-{
-       struct allegro_dev *dev = channel->dev;
-       struct mcu_msg_push_buffers_internal *msg;
-       struct mcu_msg_push_buffers_internal_buffer *buffer;
-       unsigned int num_buffers = 0;
-       size_t size;
-       struct allegro_buffer *al_buffer;
-       struct list_head *list;
-       int err;
-
-       switch (type) {
-       case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
-               list = &channel->buffers_reference;
-               break;
-       case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
-               list = &channel->buffers_intermediate;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       list_for_each_entry(al_buffer, list, head)
-               num_buffers++;
-       size = struct_size(msg, buffer, num_buffers);
-
-       msg = kmalloc(size, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-
-       msg->header.type = type;
-       msg->header.version = dev->fw_info->mailbox_version;
-
-       msg->channel_id = channel->mcu_channel_id;
-       msg->num_buffers = num_buffers;
-
-       buffer = msg->buffer;
-       list_for_each_entry(al_buffer, list, head) {
-               buffer->dma_addr = to_codec_addr(dev, al_buffer->paddr);
-               buffer->mcu_addr = to_mcu_addr(dev, al_buffer->paddr);
-               buffer->size = to_mcu_size(dev, al_buffer->size);
-               buffer++;
-       }
-
-       err = allegro_mbox_send(dev->mbox_command, msg);
-
-       kfree(msg);
-       return err;
-}
-
-static int allegro_mcu_push_buffer_intermediate(struct allegro_channel *channel)
-{
-       enum mcu_msg_type type = MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE;
-
-       return allegro_mcu_push_buffer_internal(channel, type);
-}
-
-static int allegro_mcu_push_buffer_reference(struct allegro_channel *channel)
-{
-       enum mcu_msg_type type = MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE;
-
-       return allegro_mcu_push_buffer_internal(channel, type);
-}
-
-static int allocate_buffers_internal(struct allegro_channel *channel,
-                                    struct list_head *list,
-                                    size_t n, size_t size)
-{
-       struct allegro_dev *dev = channel->dev;
-       unsigned int i;
-       int err;
-       struct allegro_buffer *buffer, *tmp;
-
-       for (i = 0; i < n; i++) {
-               buffer = kmalloc(sizeof(*buffer), GFP_KERNEL);
-               if (!buffer) {
-                       err = -ENOMEM;
-                       goto err;
-               }
-               INIT_LIST_HEAD(&buffer->head);
-
-               err = allegro_alloc_buffer(dev, buffer, size);
-               if (err)
-                       goto err;
-               list_add(&buffer->head, list);
-       }
-
-       return 0;
-
-err:
-       list_for_each_entry_safe(buffer, tmp, list, head) {
-               list_del(&buffer->head);
-               allegro_free_buffer(dev, buffer);
-               kfree(buffer);
-       }
-       return err;
-}
-
-static void destroy_buffers_internal(struct allegro_channel *channel,
-                                    struct list_head *list)
-{
-       struct allegro_dev *dev = channel->dev;
-       struct allegro_buffer *buffer, *tmp;
-
-       list_for_each_entry_safe(buffer, tmp, list, head) {
-               list_del(&buffer->head);
-               allegro_free_buffer(dev, buffer);
-               kfree(buffer);
-       }
-}
-
-static void destroy_reference_buffers(struct allegro_channel *channel)
-{
-       return destroy_buffers_internal(channel, &channel->buffers_reference);
-}
-
-static void destroy_intermediate_buffers(struct allegro_channel *channel)
-{
-       return destroy_buffers_internal(channel,
-                                       &channel->buffers_intermediate);
-}
-
-static int allocate_intermediate_buffers(struct allegro_channel *channel,
-                                        size_t n, size_t size)
-{
-       return allocate_buffers_internal(channel,
-                                        &channel->buffers_intermediate,
-                                        n, size);
-}
-
-static int allocate_reference_buffers(struct allegro_channel *channel,
-                                     size_t n, size_t size)
-{
-       return allocate_buffers_internal(channel,
-                                        &channel->buffers_reference,
-                                        n, PAGE_ALIGN(size));
-}
-
-static ssize_t allegro_h264_write_sps(struct allegro_channel *channel,
-                                     void *dest, size_t n)
-{
-       struct allegro_dev *dev = channel->dev;
-       struct nal_h264_sps *sps;
-       ssize_t size;
-       unsigned int size_mb = SIZE_MACROBLOCK;
-       /* Calculation of crop units in Rec. ITU-T H.264 (04/2017) p. 76 */
-       unsigned int crop_unit_x = 2;
-       unsigned int crop_unit_y = 2;
-
-       sps = kzalloc(sizeof(*sps), GFP_KERNEL);
-       if (!sps)
-               return -ENOMEM;
-
-       sps->profile_idc = nal_h264_profile_from_v4l2(channel->profile);
-       sps->constraint_set0_flag = 0;
-       sps->constraint_set1_flag = 1;
-       sps->constraint_set2_flag = 0;
-       sps->constraint_set3_flag = 0;
-       sps->constraint_set4_flag = 0;
-       sps->constraint_set5_flag = 0;
-       sps->level_idc = nal_h264_level_from_v4l2(channel->level);
-       sps->seq_parameter_set_id = 0;
-       sps->log2_max_frame_num_minus4 = 0;
-       sps->pic_order_cnt_type = 0;
-       sps->log2_max_pic_order_cnt_lsb_minus4 = 6;
-       sps->max_num_ref_frames = 3;
-       sps->gaps_in_frame_num_value_allowed_flag = 0;
-       sps->pic_width_in_mbs_minus1 =
-               DIV_ROUND_UP(channel->width, size_mb) - 1;
-       sps->pic_height_in_map_units_minus1 =
-               DIV_ROUND_UP(channel->height, size_mb) - 1;
-       sps->frame_mbs_only_flag = 1;
-       sps->mb_adaptive_frame_field_flag = 0;
-       sps->direct_8x8_inference_flag = 1;
-       sps->frame_cropping_flag =
-               (channel->width % size_mb) || (channel->height % size_mb);
-       if (sps->frame_cropping_flag) {
-               sps->crop_left = 0;
-               sps->crop_right = (round_up(channel->width, size_mb) - channel->width) / crop_unit_x;
-               sps->crop_top = 0;
-               sps->crop_bottom = (round_up(channel->height, size_mb) - channel->height) / crop_unit_y;
-       }
-       sps->vui_parameters_present_flag = 1;
-       sps->vui.aspect_ratio_info_present_flag = 0;
-       sps->vui.overscan_info_present_flag = 0;
-       sps->vui.video_signal_type_present_flag = 1;
-       sps->vui.video_format = 1;
-       sps->vui.video_full_range_flag = 0;
-       sps->vui.colour_description_present_flag = 1;
-       sps->vui.colour_primaries = 5;
-       sps->vui.transfer_characteristics = 5;
-       sps->vui.matrix_coefficients = 5;
-       sps->vui.chroma_loc_info_present_flag = 1;
-       sps->vui.chroma_sample_loc_type_top_field = 0;
-       sps->vui.chroma_sample_loc_type_bottom_field = 0;
-
-       sps->vui.timing_info_present_flag = 1;
-       sps->vui.num_units_in_tick = channel->framerate.denominator;
-       sps->vui.time_scale = 2 * channel->framerate.numerator;
-
-       sps->vui.fixed_frame_rate_flag = 1;
-       sps->vui.nal_hrd_parameters_present_flag = 0;
-       sps->vui.vcl_hrd_parameters_present_flag = 1;
-       sps->vui.vcl_hrd_parameters.cpb_cnt_minus1 = 0;
-       sps->vui.vcl_hrd_parameters.bit_rate_scale = 0;
-       sps->vui.vcl_hrd_parameters.cpb_size_scale = 1;
-       /* See Rec. ITU-T H.264 (04/2017) p. 410 E-53 */
-       sps->vui.vcl_hrd_parameters.bit_rate_value_minus1[0] =
-               channel->bitrate_peak / (1 << (6 + sps->vui.vcl_hrd_parameters.bit_rate_scale)) - 1;
-       /* See Rec. ITU-T H.264 (04/2017) p. 410 E-54 */
-       sps->vui.vcl_hrd_parameters.cpb_size_value_minus1[0] =
-               (channel->cpb_size * 1000) / (1 << (4 + sps->vui.vcl_hrd_parameters.cpb_size_scale)) - 1;
-       sps->vui.vcl_hrd_parameters.cbr_flag[0] =
-               !v4l2_ctrl_g_ctrl(channel->mpeg_video_frame_rc_enable);
-       sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 = 31;
-       sps->vui.vcl_hrd_parameters.cpb_removal_delay_length_minus1 = 31;
-       sps->vui.vcl_hrd_parameters.dpb_output_delay_length_minus1 = 31;
-       sps->vui.vcl_hrd_parameters.time_offset_length = 0;
-       sps->vui.low_delay_hrd_flag = 0;
-       sps->vui.pic_struct_present_flag = 1;
-       sps->vui.bitstream_restriction_flag = 0;
-
-       size = nal_h264_write_sps(&dev->plat_dev->dev, dest, n, sps);
-
-       kfree(sps);
-
-       return size;
-}
-
-static ssize_t allegro_h264_write_pps(struct allegro_channel *channel,
-                                     void *dest, size_t n)
-{
-       struct allegro_dev *dev = channel->dev;
-       struct nal_h264_pps *pps;
-       ssize_t size;
-
-       pps = kzalloc(sizeof(*pps), GFP_KERNEL);
-       if (!pps)
-               return -ENOMEM;
-
-       pps->pic_parameter_set_id = 0;
-       pps->seq_parameter_set_id = 0;
-       pps->entropy_coding_mode_flag = 0;
-       pps->bottom_field_pic_order_in_frame_present_flag = 0;
-       pps->num_slice_groups_minus1 = 0;
-       pps->num_ref_idx_l0_default_active_minus1 = channel->num_ref_idx_l0 - 1;
-       pps->num_ref_idx_l1_default_active_minus1 = channel->num_ref_idx_l1 - 1;
-       pps->weighted_pred_flag = 0;
-       pps->weighted_bipred_idc = 0;
-       pps->pic_init_qp_minus26 = 0;
-       pps->pic_init_qs_minus26 = 0;
-       pps->chroma_qp_index_offset = 0;
-       pps->deblocking_filter_control_present_flag = 1;
-       pps->constrained_intra_pred_flag = 0;
-       pps->redundant_pic_cnt_present_flag = 0;
-       pps->transform_8x8_mode_flag = 0;
-       pps->pic_scaling_matrix_present_flag = 0;
-       pps->second_chroma_qp_index_offset = 0;
-
-       size = nal_h264_write_pps(&dev->plat_dev->dev, dest, n, pps);
-
-       kfree(pps);
-
-       return size;
-}
-
-static bool allegro_channel_is_at_eos(struct allegro_channel *channel)
-{
-       bool is_at_eos = false;
-
-       switch (allegro_get_state(channel)) {
-       case ALLEGRO_STATE_STOPPED:
-               is_at_eos = true;
-               break;
-       case ALLEGRO_STATE_DRAIN:
-       case ALLEGRO_STATE_WAIT_FOR_BUFFER:
-               mutex_lock(&channel->shadow_list_lock);
-               if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) == 0 &&
-                   list_empty(&channel->source_shadow_list))
-                       is_at_eos = true;
-               mutex_unlock(&channel->shadow_list_lock);
-               break;
-       default:
-               break;
-       }
-
-       return is_at_eos;
-}
-
-static void allegro_channel_buf_done(struct allegro_channel *channel,
-                                    struct vb2_v4l2_buffer *buf,
-                                    enum vb2_buffer_state state)
-{
-       const struct v4l2_event eos_event = {
-               .type = V4L2_EVENT_EOS
-       };
-
-       if (allegro_channel_is_at_eos(channel)) {
-               buf->flags |= V4L2_BUF_FLAG_LAST;
-               v4l2_event_queue_fh(&channel->fh, &eos_event);
-
-               allegro_set_state(channel, ALLEGRO_STATE_STOPPED);
-       }
-
-       v4l2_m2m_buf_done(buf, state);
-}
-
-static u64 allegro_put_buffer(struct allegro_channel *channel,
-                             struct list_head *list,
-                             struct vb2_v4l2_buffer *buffer)
-{
-       struct v4l2_m2m_buffer *b = container_of(buffer,
-                                                struct v4l2_m2m_buffer, vb);
-       struct allegro_m2m_buffer *shadow = to_allegro_m2m_buffer(b);
-
-       mutex_lock(&channel->shadow_list_lock);
-       list_add_tail(&shadow->head, list);
-       mutex_unlock(&channel->shadow_list_lock);
-
-       return ptr_to_u64(buffer);
-}
-
-static struct vb2_v4l2_buffer *
-allegro_get_buffer(struct allegro_channel *channel,
-                  struct list_head *list, u64 handle)
-{
-       struct allegro_m2m_buffer *shadow, *tmp;
-       struct vb2_v4l2_buffer *buffer = NULL;
-
-       mutex_lock(&channel->shadow_list_lock);
-       list_for_each_entry_safe(shadow, tmp, list, head) {
-               if (handle == ptr_to_u64(&shadow->buf.vb)) {
-                       buffer = &shadow->buf.vb;
-                       list_del_init(&shadow->head);
-                       break;
-               }
-       }
-       mutex_unlock(&channel->shadow_list_lock);
-
-       return buffer;
-}
-
-static void allegro_channel_finish_frame(struct allegro_channel *channel,
-               struct mcu_msg_encode_frame_response *msg)
-{
-       struct allegro_dev *dev = channel->dev;
-       struct vb2_v4l2_buffer *src_buf;
-       struct vb2_v4l2_buffer *dst_buf;
-       struct {
-               u32 offset;
-               u32 size;
-       } *partition;
-       enum vb2_buffer_state state = VB2_BUF_STATE_ERROR;
-       char *curr;
-       ssize_t len;
-       ssize_t free;
-
-       src_buf = allegro_get_buffer(channel, &channel->source_shadow_list,
-                                    msg->src_handle);
-       if (!src_buf)
-               v4l2_warn(&dev->v4l2_dev,
-                         "channel %d: invalid source buffer\n",
-                         channel->mcu_channel_id);
-
-       dst_buf = allegro_get_buffer(channel, &channel->stream_shadow_list,
-                                    msg->stream_id);
-       if (!dst_buf)
-               v4l2_warn(&dev->v4l2_dev,
-                         "channel %d: invalid stream buffer\n",
-                         channel->mcu_channel_id);
-
-       if (!src_buf || !dst_buf)
-               goto err;
-
-       dst_buf->sequence = channel->csequence++;
-
-       if (msg->error_code & AL_ERROR) {
-               v4l2_err(&dev->v4l2_dev,
-                        "channel %d: failed to encode frame: %s (%x)\n",
-                        channel->mcu_channel_id,
-                        allegro_err_to_string(msg->error_code),
-                        msg->error_code);
-               goto err;
-       }
-
-       if (msg->partition_table_size != 1) {
-               v4l2_warn(&dev->v4l2_dev,
-                         "channel %d: only handling first partition table entry (%d entries)\n",
-                         channel->mcu_channel_id, msg->partition_table_size);
-       }
-
-       if (msg->partition_table_offset +
-           msg->partition_table_size * sizeof(*partition) >
-           vb2_plane_size(&dst_buf->vb2_buf, 0)) {
-               v4l2_err(&dev->v4l2_dev,
-                        "channel %d: partition table outside of dst_buf\n",
-                        channel->mcu_channel_id);
-               goto err;
-       }
-
-       partition =
-           vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + msg->partition_table_offset;
-       if (partition->offset + partition->size >
-           vb2_plane_size(&dst_buf->vb2_buf, 0)) {
-               v4l2_err(&dev->v4l2_dev,
-                        "channel %d: encoded frame is outside of dst_buf (offset 0x%x, size 0x%x)\n",
-                        channel->mcu_channel_id, partition->offset,
-                        partition->size);
-               goto err;
-       }
-
-       v4l2_dbg(2, debug, &dev->v4l2_dev,
-                "channel %d: encoded frame of size %d is at offset 0x%x\n",
-                channel->mcu_channel_id, partition->size, partition->offset);
-
-       /*
-        * The payload must include the data before the partition offset,
-        * because we will put the sps and pps data there.
-        */
-       vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
-                             partition->offset + partition->size);
-
-       curr = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
-       free = partition->offset;
-       if (msg->is_idr) {
-               len = allegro_h264_write_sps(channel, curr, free);
-               if (len < 0) {
-                       v4l2_err(&dev->v4l2_dev,
-                                "not enough space for sequence parameter set: %zd left\n",
-                                free);
-                       goto err;
-               }
-               curr += len;
-               free -= len;
-               v4l2_dbg(1, debug, &dev->v4l2_dev,
-                        "channel %d: wrote %zd byte SPS nal unit\n",
-                        channel->mcu_channel_id, len);
-       }
-
-       if (msg->slice_type == AL_ENC_SLICE_TYPE_I) {
-               len = allegro_h264_write_pps(channel, curr, free);
-               if (len < 0) {
-                       v4l2_err(&dev->v4l2_dev,
-                                "not enough space for picture parameter set: %zd left\n",
-                                free);
-                       goto err;
-               }
-               curr += len;
-               free -= len;
-               v4l2_dbg(1, debug, &dev->v4l2_dev,
-                        "channel %d: wrote %zd byte PPS nal unit\n",
-                        channel->mcu_channel_id, len);
-       }
-
-       if (msg->slice_type != AL_ENC_SLICE_TYPE_I && !msg->is_idr) {
-               dst_buf->vb2_buf.planes[0].data_offset = free;
-               free = 0;
-       } else {
-               len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free);
-               if (len < 0) {
-                       v4l2_err(&dev->v4l2_dev,
-                                "failed to write %zd filler data\n", free);
-                       goto err;
-               }
-               curr += len;
-               free -= len;
-               v4l2_dbg(2, debug, &dev->v4l2_dev,
-                        "channel %d: wrote %zd bytes filler nal unit\n",
-                        channel->mcu_channel_id, len);
-       }
-
-       if (free != 0) {
-               v4l2_err(&dev->v4l2_dev,
-                        "non-VCL NAL units do not fill space until VCL NAL unit: %zd bytes left\n",
-                        free);
-               goto err;
-       }
-
-       state = VB2_BUF_STATE_DONE;
-
-       v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
-       if (msg->is_idr)
-               dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
-       else
-               dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "channel %d: encoded frame #%03d (%s%s, QP %d, %d bytes)\n",
-                channel->mcu_channel_id,
-                dst_buf->sequence,
-                msg->is_idr ? "IDR, " : "",
-                msg->slice_type == AL_ENC_SLICE_TYPE_I ? "I slice" :
-                msg->slice_type == AL_ENC_SLICE_TYPE_P ? "P slice" : "unknown",
-                msg->qp, partition->size);
-
-err:
-       if (src_buf)
-               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-
-       if (dst_buf)
-               allegro_channel_buf_done(channel, dst_buf, state);
-}
-
-static int allegro_handle_init(struct allegro_dev *dev,
-                              struct mcu_msg_init_response *msg)
-{
-       complete(&dev->init_complete);
-
-       return 0;
-}
-
-static int
-allegro_handle_create_channel(struct allegro_dev *dev,
-                             struct mcu_msg_create_channel_response *msg)
-{
-       struct allegro_channel *channel;
-       int err = 0;
-       struct create_channel_param param;
-
-       channel = allegro_find_channel_by_user_id(dev, msg->user_id);
-       if (IS_ERR(channel)) {
-               v4l2_warn(&dev->v4l2_dev,
-                         "received %s for unknown user %d\n",
-                         msg_type_name(msg->header.type),
-                         msg->user_id);
-               return -EINVAL;
-       }
-
-       if (msg->error_code) {
-               v4l2_err(&dev->v4l2_dev,
-                        "user %d: mcu failed to create channel: %s (%x)\n",
-                        channel->user_id,
-                        allegro_err_to_string(msg->error_code),
-                        msg->error_code);
-               err = -EIO;
-               goto out;
-       }
-
-       channel->mcu_channel_id = msg->channel_id;
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "user %d: channel has channel id %d\n",
-                channel->user_id, channel->mcu_channel_id);
-
-       err = allegro_decode_config_blob(&param, msg, channel->config_blob.vaddr);
-       allegro_free_buffer(channel->dev, &channel->config_blob);
-       if (err)
-               goto out;
-
-       channel->num_ref_idx_l0 = param.num_ref_idx_l0;
-       channel->num_ref_idx_l1 = param.num_ref_idx_l1;
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "channel %d: intermediate buffers: %d x %d bytes\n",
-                channel->mcu_channel_id,
-                msg->int_buffers_count, msg->int_buffers_size);
-       err = allocate_intermediate_buffers(channel, msg->int_buffers_count,
-                                           msg->int_buffers_size);
-       if (err) {
-               v4l2_err(&dev->v4l2_dev,
-                        "channel %d: failed to allocate intermediate buffers\n",
-                        channel->mcu_channel_id);
-               goto out;
-       }
-       err = allegro_mcu_push_buffer_intermediate(channel);
-       if (err)
-               goto out;
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "channel %d: reference buffers: %d x %d bytes\n",
-                channel->mcu_channel_id,
-                msg->rec_buffers_count, msg->rec_buffers_size);
-       err = allocate_reference_buffers(channel, msg->rec_buffers_count,
-                                        msg->rec_buffers_size);
-       if (err) {
-               v4l2_err(&dev->v4l2_dev,
-                        "channel %d: failed to allocate reference buffers\n",
-                        channel->mcu_channel_id);
-               goto out;
-       }
-       err = allegro_mcu_push_buffer_reference(channel);
-       if (err)
-               goto out;
-
-out:
-       channel->error = err;
-       complete(&channel->completion);
-
-       /* Handled successfully, error is passed via channel->error */
-       return 0;
-}
-
-static int
-allegro_handle_destroy_channel(struct allegro_dev *dev,
-                              struct mcu_msg_destroy_channel_response *msg)
-{
-       struct allegro_channel *channel;
-
-       channel = allegro_find_channel_by_channel_id(dev, msg->channel_id);
-       if (IS_ERR(channel)) {
-               v4l2_err(&dev->v4l2_dev,
-                        "received %s for unknown channel %d\n",
-                        msg_type_name(msg->header.type),
-                        msg->channel_id);
-               return -EINVAL;
-       }
-
-       v4l2_dbg(2, debug, &dev->v4l2_dev,
-                "user %d: vcu destroyed channel %d\n",
-                channel->user_id, channel->mcu_channel_id);
-       complete(&channel->completion);
-
-       return 0;
-}
-
-static int
-allegro_handle_encode_frame(struct allegro_dev *dev,
-                           struct mcu_msg_encode_frame_response *msg)
-{
-       struct allegro_channel *channel;
-
-       channel = allegro_find_channel_by_channel_id(dev, msg->channel_id);
-       if (IS_ERR(channel)) {
-               v4l2_err(&dev->v4l2_dev,
-                        "received %s for unknown channel %d\n",
-                        msg_type_name(msg->header.type),
-                        msg->channel_id);
-               return -EINVAL;
-       }
-
-       allegro_channel_finish_frame(channel, msg);
-
-       return 0;
-}
-
-static void allegro_handle_message(struct allegro_dev *dev,
-                                  union mcu_msg_response *msg)
-{
-       switch (msg->header.type) {
-       case MCU_MSG_TYPE_INIT:
-               allegro_handle_init(dev, &msg->init);
-               break;
-       case MCU_MSG_TYPE_CREATE_CHANNEL:
-               allegro_handle_create_channel(dev, &msg->create_channel);
-               break;
-       case MCU_MSG_TYPE_DESTROY_CHANNEL:
-               allegro_handle_destroy_channel(dev, &msg->destroy_channel);
-               break;
-       case MCU_MSG_TYPE_ENCODE_FRAME:
-               allegro_handle_encode_frame(dev, &msg->encode_frame);
-               break;
-       default:
-               v4l2_warn(&dev->v4l2_dev,
-                         "%s: unknown message %s\n",
-                         __func__, msg_type_name(msg->header.type));
-               break;
-       }
-}
-
-static irqreturn_t allegro_hardirq(int irq, void *data)
-{
-       struct allegro_dev *dev = data;
-       unsigned int status;
-
-       regmap_read(dev->regmap, AL5_ITC_CPU_IRQ_STA, &status);
-       if (!(status & AL5_ITC_CPU_IRQ_STA_TRIGGERED))
-               return IRQ_NONE;
-
-       regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_CLR, status);
-
-       return IRQ_WAKE_THREAD;
-}
-
-static irqreturn_t allegro_irq_thread(int irq, void *data)
-{
-       struct allegro_dev *dev = data;
-
-       allegro_mbox_notify(dev->mbox_status);
-
-       return IRQ_HANDLED;
-}
-
-static void allegro_copy_firmware(struct allegro_dev *dev,
-                                 const u8 * const buf, size_t size)
-{
-       int err = 0;
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "copy mcu firmware (%zu B) to SRAM\n", size);
-       err = regmap_bulk_write(dev->sram, 0x0, buf, size / 4);
-       if (err)
-               v4l2_err(&dev->v4l2_dev,
-                        "failed to copy firmware: %d\n", err);
-}
-
-static void allegro_copy_fw_codec(struct allegro_dev *dev,
-                                 const u8 * const buf, size_t size)
-{
-       int err;
-       dma_addr_t icache_offset, dcache_offset;
-
-       /*
-        * The downstream allocates 600 KB for the codec firmware to have some
-        * extra space for "possible extensions." My tests were fine with
-        * allocating just enough memory for the actual firmware, but I am not
-        * sure that the firmware really does not use the remaining space.
-        */
-       err = allegro_alloc_buffer(dev, &dev->firmware, size);
-       if (err) {
-               v4l2_err(&dev->v4l2_dev,
-                        "failed to allocate %zu bytes for firmware\n", size);
-               return;
-       }
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "copy codec firmware (%zd B) to phys %pad\n",
-                size, &dev->firmware.paddr);
-       memcpy(dev->firmware.vaddr, buf, size);
-
-       regmap_write(dev->regmap, AXI_ADDR_OFFSET_IP,
-                    upper_32_bits(dev->firmware.paddr));
-
-       icache_offset = dev->firmware.paddr - MCU_CACHE_OFFSET;
-       v4l2_dbg(2, debug, &dev->v4l2_dev,
-                "icache_offset: msb = 0x%x, lsb = 0x%x\n",
-                upper_32_bits(icache_offset), lower_32_bits(icache_offset));
-       regmap_write(dev->regmap, AL5_ICACHE_ADDR_OFFSET_MSB,
-                    upper_32_bits(icache_offset));
-       regmap_write(dev->regmap, AL5_ICACHE_ADDR_OFFSET_LSB,
-                    lower_32_bits(icache_offset));
-
-       dcache_offset =
-           (dev->firmware.paddr & 0xffffffff00000000ULL) - MCU_CACHE_OFFSET;
-       v4l2_dbg(2, debug, &dev->v4l2_dev,
-                "dcache_offset: msb = 0x%x, lsb = 0x%x\n",
-                upper_32_bits(dcache_offset), lower_32_bits(dcache_offset));
-       regmap_write(dev->regmap, AL5_DCACHE_ADDR_OFFSET_MSB,
-                    upper_32_bits(dcache_offset));
-       regmap_write(dev->regmap, AL5_DCACHE_ADDR_OFFSET_LSB,
-                    lower_32_bits(dcache_offset));
-}
-
-static void allegro_free_fw_codec(struct allegro_dev *dev)
-{
-       allegro_free_buffer(dev, &dev->firmware);
-}
-
-/*
- * Control functions for the MCU
- */
-
-static int allegro_mcu_enable_interrupts(struct allegro_dev *dev)
-{
-       return regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_MSK, BIT(0));
-}
-
-static int allegro_mcu_disable_interrupts(struct allegro_dev *dev)
-{
-       return regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_MSK, 0);
-}
-
-static int allegro_mcu_wait_for_sleep(struct allegro_dev *dev)
-{
-       unsigned long timeout;
-       unsigned int status;
-
-       timeout = jiffies + msecs_to_jiffies(100);
-       while (regmap_read(dev->regmap, AL5_MCU_STA, &status) == 0 &&
-              status != AL5_MCU_STA_SLEEP) {
-               if (time_after(jiffies, timeout))
-                       return -ETIMEDOUT;
-               cpu_relax();
-       }
-
-       return 0;
-}
-
-static int allegro_mcu_start(struct allegro_dev *dev)
-{
-       unsigned long timeout;
-       unsigned int status;
-       int err;
-
-       err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, BIT(0));
-       if (err)
-               return err;
-
-       timeout = jiffies + msecs_to_jiffies(100);
-       while (regmap_read(dev->regmap, AL5_MCU_STA, &status) == 0 &&
-              status == AL5_MCU_STA_SLEEP) {
-               if (time_after(jiffies, timeout))
-                       return -ETIMEDOUT;
-               cpu_relax();
-       }
-
-       err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, 0);
-       if (err)
-               return err;
-
-       return 0;
-}
-
-static int allegro_mcu_reset(struct allegro_dev *dev)
-{
-       int err;
-
-       /*
-        * Ensure that the AL5_MCU_WAKEUP bit is set to 0 otherwise the mcu
-        * does not go to sleep after the reset.
-        */
-       err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, 0);
-       if (err)
-               return err;
-
-       err = regmap_write(dev->regmap,
-                          AL5_MCU_RESET_MODE, AL5_MCU_RESET_MODE_SLEEP);
-       if (err < 0)
-               return err;
-
-       err = regmap_write(dev->regmap, AL5_MCU_RESET, AL5_MCU_RESET_SOFT);
-       if (err < 0)
-               return err;
-
-       return allegro_mcu_wait_for_sleep(dev);
-}
-
-static void allegro_mcu_interrupt(struct allegro_dev *dev)
-{
-       regmap_write(dev->regmap, AL5_MCU_INTERRUPT, BIT(0));
-}
-
-static void allegro_destroy_channel(struct allegro_channel *channel)
-{
-       struct allegro_dev *dev = channel->dev;
-       unsigned long timeout;
-
-       if (channel_exists(channel)) {
-               reinit_completion(&channel->completion);
-               allegro_mcu_send_destroy_channel(dev, channel);
-               timeout = wait_for_completion_timeout(&channel->completion,
-                                                     msecs_to_jiffies(5000));
-               if (timeout == 0)
-                       v4l2_warn(&dev->v4l2_dev,
-                                 "channel %d: timeout while destroying\n",
-                                 channel->mcu_channel_id);
-
-               channel->mcu_channel_id = -1;
-       }
-
-       destroy_intermediate_buffers(channel);
-       destroy_reference_buffers(channel);
-
-       v4l2_ctrl_grab(channel->mpeg_video_h264_profile, false);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_level, false);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_i_frame_qp, false);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_max_qp, false);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, false);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, false);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, false);
-       v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, false);
-       v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, false);
-       v4l2_ctrl_grab(channel->mpeg_video_bitrate, false);
-       v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, false);
-       v4l2_ctrl_grab(channel->mpeg_video_cpb_size, false);
-       v4l2_ctrl_grab(channel->mpeg_video_gop_size, false);
-
-       if (channel->user_id != -1) {
-               clear_bit(channel->user_id, &dev->channel_user_ids);
-               channel->user_id = -1;
-       }
-}
-
-/*
- * Create the MCU channel
- *
- * After the channel has been created, the picture size, format, colorspace
- * and framerate are fixed. Also the codec, profile, bitrate, etc. cannot be
- * changed anymore.
- *
- * The channel can be created only once. The MCU will accept source buffers
- * and stream buffers only after a channel has been created.
- */
-static int allegro_create_channel(struct allegro_channel *channel)
-{
-       struct allegro_dev *dev = channel->dev;
-       unsigned long timeout;
-       enum v4l2_mpeg_video_h264_level min_level;
-
-       if (channel_exists(channel)) {
-               v4l2_warn(&dev->v4l2_dev,
-                         "channel already exists\n");
-               return 0;
-       }
-
-       channel->user_id = allegro_next_user_id(dev);
-       if (channel->user_id < 0) {
-               v4l2_err(&dev->v4l2_dev,
-                        "no free channels available\n");
-               return -EBUSY;
-       }
-       set_bit(channel->user_id, &dev->channel_user_ids);
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "user %d: creating channel (%4.4s, %dx%d@%d)\n",
-                channel->user_id,
-                (char *)&channel->codec, channel->width, channel->height,
-                DIV_ROUND_UP(channel->framerate.numerator,
-                             channel->framerate.denominator));
-
-       min_level = select_minimum_h264_level(channel->width, channel->height);
-       if (channel->level < min_level) {
-               v4l2_warn(&dev->v4l2_dev,
-                         "user %d: selected Level %s too low: increasing to Level %s\n",
-                         channel->user_id,
-                         v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL)[channel->level],
-                         v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL)[min_level]);
-               channel->level = min_level;
-       }
-
-       v4l2_ctrl_grab(channel->mpeg_video_h264_profile, true);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_level, true);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_i_frame_qp, true);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_max_qp, true);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, true);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, true);
-       v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, true);
-       v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, true);
-       v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, true);
-       v4l2_ctrl_grab(channel->mpeg_video_bitrate, true);
-       v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, true);
-       v4l2_ctrl_grab(channel->mpeg_video_cpb_size, true);
-       v4l2_ctrl_grab(channel->mpeg_video_gop_size, true);
-
-       reinit_completion(&channel->completion);
-       allegro_mcu_send_create_channel(dev, channel);
-       timeout = wait_for_completion_timeout(&channel->completion,
-                                             msecs_to_jiffies(5000));
-       if (timeout == 0)
-               channel->error = -ETIMEDOUT;
-       if (channel->error)
-               goto err;
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "channel %d: accepting buffers\n",
-                channel->mcu_channel_id);
-
-       return 0;
-
-err:
-       allegro_destroy_channel(channel);
-
-       return channel->error;
-}
-
-static void allegro_set_default_params(struct allegro_channel *channel)
-{
-       channel->width = ALLEGRO_WIDTH_DEFAULT;
-       channel->height = ALLEGRO_HEIGHT_DEFAULT;
-       channel->stride = round_up(channel->width, 32);
-       channel->framerate = ALLEGRO_FRAMERATE_DEFAULT;
-
-       channel->colorspace = V4L2_COLORSPACE_REC709;
-       channel->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
-       channel->quantization = V4L2_QUANTIZATION_DEFAULT;
-       channel->xfer_func = V4L2_XFER_FUNC_DEFAULT;
-
-       channel->pixelformat = V4L2_PIX_FMT_NV12;
-       channel->sizeimage_raw = channel->stride * channel->height * 3 / 2;
-
-       channel->codec = V4L2_PIX_FMT_H264;
-       channel->profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
-       channel->level =
-               select_minimum_h264_level(channel->width, channel->height);
-       channel->sizeimage_encoded =
-               estimate_stream_size(channel->width, channel->height);
-
-       channel->bitrate = maximum_bitrate(channel->level);
-       channel->bitrate_peak = maximum_bitrate(channel->level);
-       channel->cpb_size = maximum_cpb_size(channel->level);
-       channel->gop_size = ALLEGRO_GOP_SIZE_DEFAULT;
-}
-
-static int allegro_queue_setup(struct vb2_queue *vq,
-                              unsigned int *nbuffers, unsigned int *nplanes,
-                              unsigned int sizes[],
-                              struct device *alloc_devs[])
-{
-       struct allegro_channel *channel = vb2_get_drv_priv(vq);
-       struct allegro_dev *dev = channel->dev;
-
-       v4l2_dbg(2, debug, &dev->v4l2_dev,
-                "%s: queue setup[%s]: nplanes = %d\n",
-                V4L2_TYPE_IS_OUTPUT(vq->type) ? "output" : "capture",
-                *nplanes == 0 ? "REQBUFS" : "CREATE_BUFS", *nplanes);
-
-       if (*nplanes != 0) {
-               if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
-                       if (sizes[0] < channel->sizeimage_raw)
-                               return -EINVAL;
-               } else {
-                       if (sizes[0] < channel->sizeimage_encoded)
-                               return -EINVAL;
-               }
-       } else {
-               *nplanes = 1;
-               if (V4L2_TYPE_IS_OUTPUT(vq->type))
-                       sizes[0] = channel->sizeimage_raw;
-               else
-                       sizes[0] = channel->sizeimage_encoded;
-       }
-
-       return 0;
-}
-
-static int allegro_buf_prepare(struct vb2_buffer *vb)
-{
-       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-       struct allegro_channel *channel = vb2_get_drv_priv(vb->vb2_queue);
-       struct allegro_dev *dev = channel->dev;
-
-       if (allegro_get_state(channel) == ALLEGRO_STATE_DRAIN &&
-           V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
-               return -EBUSY;
-
-       if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
-               if (vbuf->field == V4L2_FIELD_ANY)
-                       vbuf->field = V4L2_FIELD_NONE;
-               if (vbuf->field != V4L2_FIELD_NONE) {
-                       v4l2_err(&dev->v4l2_dev,
-                                "channel %d: unsupported field\n",
-                                channel->mcu_channel_id);
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-
-static void allegro_buf_queue(struct vb2_buffer *vb)
-{
-       struct allegro_channel *channel = vb2_get_drv_priv(vb->vb2_queue);
-       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-
-       if (allegro_get_state(channel) == ALLEGRO_STATE_WAIT_FOR_BUFFER &&
-           vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               allegro_channel_buf_done(channel, vbuf, VB2_BUF_STATE_DONE);
-               return;
-       }
-
-       v4l2_m2m_buf_queue(channel->fh.m2m_ctx, vbuf);
-}
-
-static int allegro_start_streaming(struct vb2_queue *q, unsigned int count)
-{
-       struct allegro_channel *channel = vb2_get_drv_priv(q);
-       struct allegro_dev *dev = channel->dev;
-
-       v4l2_dbg(2, debug, &dev->v4l2_dev,
-                "%s: start streaming\n",
-                V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture");
-
-       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
-               channel->osequence = 0;
-               allegro_set_state(channel, ALLEGRO_STATE_ENCODING);
-       } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               channel->csequence = 0;
-       }
-
-       return 0;
-}
-
-static void allegro_stop_streaming(struct vb2_queue *q)
-{
-       struct allegro_channel *channel = vb2_get_drv_priv(q);
-       struct allegro_dev *dev = channel->dev;
-       struct vb2_v4l2_buffer *buffer;
-       struct allegro_m2m_buffer *shadow, *tmp;
-
-       v4l2_dbg(2, debug, &dev->v4l2_dev,
-                "%s: stop streaming\n",
-                V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture");
-
-       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
-               mutex_lock(&channel->shadow_list_lock);
-               list_for_each_entry_safe(shadow, tmp,
-                                        &channel->source_shadow_list, head) {
-                       list_del(&shadow->head);
-                       v4l2_m2m_buf_done(&shadow->buf.vb, VB2_BUF_STATE_ERROR);
-               }
-               mutex_unlock(&channel->shadow_list_lock);
-
-               allegro_set_state(channel, ALLEGRO_STATE_STOPPED);
-               while ((buffer = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx)))
-                       v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR);
-       } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               mutex_lock(&channel->shadow_list_lock);
-               list_for_each_entry_safe(shadow, tmp,
-                                        &channel->stream_shadow_list, head) {
-                       list_del(&shadow->head);
-                       v4l2_m2m_buf_done(&shadow->buf.vb, VB2_BUF_STATE_ERROR);
-               }
-               mutex_unlock(&channel->shadow_list_lock);
-
-               allegro_destroy_channel(channel);
-               while ((buffer = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx)))
-                       v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR);
-       }
-}
-
-static const struct vb2_ops allegro_queue_ops = {
-       .queue_setup = allegro_queue_setup,
-       .buf_prepare = allegro_buf_prepare,
-       .buf_queue = allegro_buf_queue,
-       .start_streaming = allegro_start_streaming,
-       .stop_streaming = allegro_stop_streaming,
-       .wait_prepare = vb2_ops_wait_prepare,
-       .wait_finish = vb2_ops_wait_finish,
-};
-
-static int allegro_queue_init(void *priv,
-                             struct vb2_queue *src_vq,
-                             struct vb2_queue *dst_vq)
-{
-       int err;
-       struct allegro_channel *channel = priv;
-
-       src_vq->dev = &channel->dev->plat_dev->dev;
-       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-       src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
-       src_vq->mem_ops = &vb2_dma_contig_memops;
-       src_vq->drv_priv = channel;
-       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       src_vq->ops = &allegro_queue_ops;
-       src_vq->buf_struct_size = sizeof(struct allegro_m2m_buffer);
-       src_vq->lock = &channel->dev->lock;
-       err = vb2_queue_init(src_vq);
-       if (err)
-               return err;
-
-       dst_vq->dev = &channel->dev->plat_dev->dev;
-       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
-       dst_vq->mem_ops = &vb2_dma_contig_memops;
-       dst_vq->drv_priv = channel;
-       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       dst_vq->ops = &allegro_queue_ops;
-       dst_vq->buf_struct_size = sizeof(struct allegro_m2m_buffer);
-       dst_vq->lock = &channel->dev->lock;
-       err = vb2_queue_init(dst_vq);
-       if (err)
-               return err;
-
-       return 0;
-}
-
-static int allegro_clamp_qp(struct allegro_channel *channel,
-                           struct v4l2_ctrl *ctrl)
-{
-       struct v4l2_ctrl *next_ctrl;
-
-       if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP)
-               next_ctrl = channel->mpeg_video_h264_p_frame_qp;
-       else if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP)
-               next_ctrl = channel->mpeg_video_h264_b_frame_qp;
-       else
-               return 0;
-
-       /* Modify range automatically updates the value */
-       __v4l2_ctrl_modify_range(next_ctrl, ctrl->val, 51, 1, ctrl->val);
-
-       return allegro_clamp_qp(channel, next_ctrl);
-}
-
-static int allegro_clamp_bitrate(struct allegro_channel *channel,
-                                struct v4l2_ctrl *ctrl)
-{
-       struct v4l2_ctrl *ctrl_bitrate = channel->mpeg_video_bitrate;
-       struct v4l2_ctrl *ctrl_bitrate_peak = channel->mpeg_video_bitrate_peak;
-
-       if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
-           ctrl_bitrate_peak->val < ctrl_bitrate->val)
-               ctrl_bitrate_peak->val = ctrl_bitrate->val;
-
-       return 0;
-}
-
-static int allegro_try_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct allegro_channel *channel = container_of(ctrl->handler,
-                                                      struct allegro_channel,
-                                                      ctrl_handler);
-
-       switch (ctrl->id) {
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-               allegro_clamp_bitrate(channel, ctrl);
-               break;
-       }
-
-       return 0;
-}
-
-static int allegro_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct allegro_channel *channel = container_of(ctrl->handler,
-                                                      struct allegro_channel,
-                                                      ctrl_handler);
-       struct allegro_dev *dev = channel->dev;
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "s_ctrl: %s = %d\n", v4l2_ctrl_get_name(ctrl->id), ctrl->val);
-
-       switch (ctrl->id) {
-       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
-               channel->level = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
-               channel->frame_rc_enable = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-               channel->bitrate = channel->mpeg_video_bitrate->val;
-               channel->bitrate_peak = channel->mpeg_video_bitrate_peak->val;
-               v4l2_ctrl_activate(channel->mpeg_video_bitrate_peak,
-                                  ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
-               channel->cpb_size = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               channel->gop_size = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
-       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
-       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
-               allegro_clamp_qp(channel, ctrl);
-               break;
-       }
-
-       return 0;
-}
-
-static const struct v4l2_ctrl_ops allegro_ctrl_ops = {
-       .try_ctrl = allegro_try_ctrl,
-       .s_ctrl = allegro_s_ctrl,
-};
-
-static int allegro_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct allegro_dev *dev = video_get_drvdata(vdev);
-       struct allegro_channel *channel = NULL;
-       struct v4l2_ctrl_handler *handler;
-       u64 mask;
-       int ret;
-
-       channel = kzalloc(sizeof(*channel), GFP_KERNEL);
-       if (!channel)
-               return -ENOMEM;
-
-       v4l2_fh_init(&channel->fh, vdev);
-
-       init_completion(&channel->completion);
-       INIT_LIST_HEAD(&channel->source_shadow_list);
-       INIT_LIST_HEAD(&channel->stream_shadow_list);
-       mutex_init(&channel->shadow_list_lock);
-
-       channel->dev = dev;
-
-       allegro_set_default_params(channel);
-
-       handler = &channel->ctrl_handler;
-       v4l2_ctrl_handler_init(handler, 0);
-       channel->mpeg_video_h264_profile = v4l2_ctrl_new_std_menu(handler,
-                       &allegro_ctrl_ops,
-                       V4L2_CID_MPEG_VIDEO_H264_PROFILE,
-                       V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0,
-                       V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
-       mask = 1 << V4L2_MPEG_VIDEO_H264_LEVEL_1B;
-       channel->mpeg_video_h264_level = v4l2_ctrl_new_std_menu(handler,
-                       &allegro_ctrl_ops,
-                       V4L2_CID_MPEG_VIDEO_H264_LEVEL,
-                       V4L2_MPEG_VIDEO_H264_LEVEL_5_1, mask,
-                       V4L2_MPEG_VIDEO_H264_LEVEL_5_1);
-       channel->mpeg_video_h264_i_frame_qp =
-               v4l2_ctrl_new_std(handler,
-                                 &allegro_ctrl_ops,
-                                 V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
-                                 0, 51, 1, 30);
-       channel->mpeg_video_h264_max_qp =
-               v4l2_ctrl_new_std(handler,
-                                 &allegro_ctrl_ops,
-                                 V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
-                                 0, 51, 1, 51);
-       channel->mpeg_video_h264_min_qp =
-               v4l2_ctrl_new_std(handler,
-                                 &allegro_ctrl_ops,
-                                 V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
-                                 0, 51, 1, 0);
-       channel->mpeg_video_h264_p_frame_qp =
-               v4l2_ctrl_new_std(handler,
-                                 &allegro_ctrl_ops,
-                                 V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
-                                 0, 51, 1, 30);
-       channel->mpeg_video_h264_b_frame_qp =
-               v4l2_ctrl_new_std(handler,
-                                 &allegro_ctrl_ops,
-                                 V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
-                                 0, 51, 1, 30);
-       channel->mpeg_video_frame_rc_enable =
-               v4l2_ctrl_new_std(handler,
-                                 &allegro_ctrl_ops,
-                                 V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
-                                 false, 0x1,
-                                 true, false);
-       channel->mpeg_video_bitrate_mode = v4l2_ctrl_new_std_menu(handler,
-                       &allegro_ctrl_ops,
-                       V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
-                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
-                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
-       channel->mpeg_video_bitrate = v4l2_ctrl_new_std(handler,
-                       &allegro_ctrl_ops,
-                       V4L2_CID_MPEG_VIDEO_BITRATE,
-                       0, maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1),
-                       1, channel->bitrate);
-       channel->mpeg_video_bitrate_peak = v4l2_ctrl_new_std(handler,
-                       &allegro_ctrl_ops,
-                       V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
-                       0, maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1),
-                       1, channel->bitrate_peak);
-       channel->mpeg_video_cpb_size = v4l2_ctrl_new_std(handler,
-                       &allegro_ctrl_ops,
-                       V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
-                       0, maximum_cpb_size(V4L2_MPEG_VIDEO_H264_LEVEL_5_1),
-                       1, channel->cpb_size);
-       channel->mpeg_video_gop_size = v4l2_ctrl_new_std(handler,
-                       &allegro_ctrl_ops,
-                       V4L2_CID_MPEG_VIDEO_GOP_SIZE,
-                       0, ALLEGRO_GOP_SIZE_MAX,
-                       1, channel->gop_size);
-       v4l2_ctrl_new_std(handler,
-                         &allegro_ctrl_ops,
-                         V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
-                         1, 32,
-                         1, 1);
-       if (handler->error != 0) {
-               ret = handler->error;
-               goto error;
-       }
-
-       channel->fh.ctrl_handler = handler;
-
-       v4l2_ctrl_cluster(3, &channel->mpeg_video_bitrate_mode);
-
-       channel->mcu_channel_id = -1;
-       channel->user_id = -1;
-
-       INIT_LIST_HEAD(&channel->buffers_reference);
-       INIT_LIST_HEAD(&channel->buffers_intermediate);
-
-       channel->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, channel,
-                                               allegro_queue_init);
-
-       if (IS_ERR(channel->fh.m2m_ctx)) {
-               ret = PTR_ERR(channel->fh.m2m_ctx);
-               goto error;
-       }
-
-       list_add(&channel->list, &dev->channels);
-       file->private_data = &channel->fh;
-       v4l2_fh_add(&channel->fh);
-
-       return 0;
-
-error:
-       v4l2_ctrl_handler_free(handler);
-       kfree(channel);
-       return ret;
-}
-
-static int allegro_release(struct file *file)
-{
-       struct allegro_channel *channel = fh_to_channel(file->private_data);
-
-       v4l2_m2m_ctx_release(channel->fh.m2m_ctx);
-
-       list_del(&channel->list);
-
-       v4l2_ctrl_handler_free(&channel->ctrl_handler);
-
-       v4l2_fh_del(&channel->fh);
-       v4l2_fh_exit(&channel->fh);
-
-       kfree(channel);
-
-       return 0;
-}
-
-static int allegro_querycap(struct file *file, void *fh,
-                           struct v4l2_capability *cap)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct allegro_dev *dev = video_get_drvdata(vdev);
-
-       strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
-       strscpy(cap->card, "Allegro DVT Video Encoder", sizeof(cap->card));
-       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
-                dev_name(&dev->plat_dev->dev));
-
-       return 0;
-}
-
-static int allegro_enum_fmt_vid(struct file *file, void *fh,
-                               struct v4l2_fmtdesc *f)
-{
-       if (f->index)
-               return -EINVAL;
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               f->pixelformat = V4L2_PIX_FMT_NV12;
-               break;
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               f->pixelformat = V4L2_PIX_FMT_H264;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int allegro_g_fmt_vid_cap(struct file *file, void *fh,
-                                struct v4l2_format *f)
-{
-       struct allegro_channel *channel = fh_to_channel(fh);
-
-       f->fmt.pix.field = V4L2_FIELD_NONE;
-       f->fmt.pix.width = channel->width;
-       f->fmt.pix.height = channel->height;
-
-       f->fmt.pix.colorspace = channel->colorspace;
-       f->fmt.pix.ycbcr_enc = channel->ycbcr_enc;
-       f->fmt.pix.quantization = channel->quantization;
-       f->fmt.pix.xfer_func = channel->xfer_func;
-
-       f->fmt.pix.pixelformat = channel->codec;
-       f->fmt.pix.bytesperline = 0;
-       f->fmt.pix.sizeimage = channel->sizeimage_encoded;
-
-       return 0;
-}
-
-static int allegro_try_fmt_vid_cap(struct file *file, void *fh,
-                                  struct v4l2_format *f)
-{
-       f->fmt.pix.field = V4L2_FIELD_NONE;
-
-       f->fmt.pix.width = clamp_t(__u32, f->fmt.pix.width,
-                                  ALLEGRO_WIDTH_MIN, ALLEGRO_WIDTH_MAX);
-       f->fmt.pix.height = clamp_t(__u32, f->fmt.pix.height,
-                                   ALLEGRO_HEIGHT_MIN, ALLEGRO_HEIGHT_MAX);
-
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
-       f->fmt.pix.bytesperline = 0;
-       f->fmt.pix.sizeimage =
-               estimate_stream_size(f->fmt.pix.width, f->fmt.pix.height);
-
-       return 0;
-}
-
-static int allegro_g_fmt_vid_out(struct file *file, void *fh,
-                                struct v4l2_format *f)
-{
-       struct allegro_channel *channel = fh_to_channel(fh);
-
-       f->fmt.pix.field = V4L2_FIELD_NONE;
-
-       f->fmt.pix.width = channel->width;
-       f->fmt.pix.height = channel->height;
-
-       f->fmt.pix.colorspace = channel->colorspace;
-       f->fmt.pix.ycbcr_enc = channel->ycbcr_enc;
-       f->fmt.pix.quantization = channel->quantization;
-       f->fmt.pix.xfer_func = channel->xfer_func;
-
-       f->fmt.pix.pixelformat = channel->pixelformat;
-       f->fmt.pix.bytesperline = channel->stride;
-       f->fmt.pix.sizeimage = channel->sizeimage_raw;
-
-       return 0;
-}
-
-static int allegro_try_fmt_vid_out(struct file *file, void *fh,
-                                  struct v4l2_format *f)
-{
-       f->fmt.pix.field = V4L2_FIELD_NONE;
-
-       /*
-        * The firmware of the Allegro codec handles the padding internally
-        * and expects the visual frame size when configuring a channel.
-        * Therefore, unlike other encoder drivers, this driver does not round
-        * up the width and height to macroblock alignment and does not
-        * implement the selection api.
-        */
-       f->fmt.pix.width = clamp_t(__u32, f->fmt.pix.width,
-                                  ALLEGRO_WIDTH_MIN, ALLEGRO_WIDTH_MAX);
-       f->fmt.pix.height = clamp_t(__u32, f->fmt.pix.height,
-                                   ALLEGRO_HEIGHT_MIN, ALLEGRO_HEIGHT_MAX);
-
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
-       f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 32);
-       f->fmt.pix.sizeimage =
-               f->fmt.pix.bytesperline * f->fmt.pix.height * 3 / 2;
-
-       return 0;
-}
-
-static int allegro_s_fmt_vid_out(struct file *file, void *fh,
-                                struct v4l2_format *f)
-{
-       struct allegro_channel *channel = fh_to_channel(fh);
-       int err;
-
-       err = allegro_try_fmt_vid_out(file, fh, f);
-       if (err)
-               return err;
-
-       channel->width = f->fmt.pix.width;
-       channel->height = f->fmt.pix.height;
-       channel->stride = f->fmt.pix.bytesperline;
-       channel->sizeimage_raw = f->fmt.pix.sizeimage;
-
-       channel->colorspace = f->fmt.pix.colorspace;
-       channel->ycbcr_enc = f->fmt.pix.ycbcr_enc;
-       channel->quantization = f->fmt.pix.quantization;
-       channel->xfer_func = f->fmt.pix.xfer_func;
-
-       channel->level =
-               select_minimum_h264_level(channel->width, channel->height);
-       channel->sizeimage_encoded =
-               estimate_stream_size(channel->width, channel->height);
-
-       return 0;
-}
-
-static int allegro_channel_cmd_stop(struct allegro_channel *channel)
-{
-       struct allegro_dev *dev = channel->dev;
-       struct vb2_v4l2_buffer *dst_buf;
-
-       switch (allegro_get_state(channel)) {
-       case ALLEGRO_STATE_DRAIN:
-       case ALLEGRO_STATE_WAIT_FOR_BUFFER:
-               return -EBUSY;
-       case ALLEGRO_STATE_ENCODING:
-               allegro_set_state(channel, ALLEGRO_STATE_DRAIN);
-               break;
-       default:
-               return 0;
-       }
-
-       /* If there are output buffers, they must be encoded */
-       if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) != 0) {
-               v4l2_dbg(1, debug,  &dev->v4l2_dev,
-                        "channel %d: CMD_STOP: continue encoding src buffers\n",
-                        channel->mcu_channel_id);
-               return 0;
-       }
-
-       /* If there are capture buffers, use it to signal EOS */
-       dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx);
-       if (dst_buf) {
-               v4l2_dbg(1, debug,  &dev->v4l2_dev,
-                        "channel %d: CMD_STOP: signaling EOS\n",
-                        channel->mcu_channel_id);
-               allegro_channel_buf_done(channel, dst_buf, VB2_BUF_STATE_DONE);
-               return 0;
-       }
-
-       /*
-        * If there are no capture buffers, we need to wait for the next
-        * buffer to signal EOS.
-        */
-       v4l2_dbg(1, debug,  &dev->v4l2_dev,
-                "channel %d: CMD_STOP: wait for CAPTURE buffer to signal EOS\n",
-                channel->mcu_channel_id);
-       allegro_set_state(channel, ALLEGRO_STATE_WAIT_FOR_BUFFER);
-
-       return 0;
-}
-
-static int allegro_channel_cmd_start(struct allegro_channel *channel)
-{
-       switch (allegro_get_state(channel)) {
-       case ALLEGRO_STATE_DRAIN:
-       case ALLEGRO_STATE_WAIT_FOR_BUFFER:
-               return -EBUSY;
-       case ALLEGRO_STATE_STOPPED:
-               allegro_set_state(channel, ALLEGRO_STATE_ENCODING);
-               break;
-       default:
-               return 0;
-       }
-
-       return 0;
-}
-
-static int allegro_encoder_cmd(struct file *file, void *fh,
-                              struct v4l2_encoder_cmd *cmd)
-{
-       struct allegro_channel *channel = fh_to_channel(fh);
-       int err;
-
-       err = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd);
-       if (err)
-               return err;
-
-       switch (cmd->cmd) {
-       case V4L2_ENC_CMD_STOP:
-               err = allegro_channel_cmd_stop(channel);
-               break;
-       case V4L2_ENC_CMD_START:
-               err = allegro_channel_cmd_start(channel);
-               break;
-       default:
-               err = -EINVAL;
-               break;
-       }
-
-       return err;
-}
-
-static int allegro_enum_framesizes(struct file *file, void *fh,
-                                  struct v4l2_frmsizeenum *fsize)
-{
-       switch (fsize->pixel_format) {
-       case V4L2_PIX_FMT_H264:
-       case V4L2_PIX_FMT_NV12:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (fsize->index)
-               return -EINVAL;
-
-       fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
-       fsize->stepwise.min_width = ALLEGRO_WIDTH_MIN;
-       fsize->stepwise.max_width = ALLEGRO_WIDTH_MAX;
-       fsize->stepwise.step_width = 1;
-       fsize->stepwise.min_height = ALLEGRO_HEIGHT_MIN;
-       fsize->stepwise.max_height = ALLEGRO_HEIGHT_MAX;
-       fsize->stepwise.step_height = 1;
-
-       return 0;
-}
-
-static int allegro_ioctl_streamon(struct file *file, void *priv,
-                                 enum v4l2_buf_type type)
-{
-       struct v4l2_fh *fh = file->private_data;
-       struct allegro_channel *channel = fh_to_channel(fh);
-       int err;
-
-       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               err = allegro_create_channel(channel);
-               if (err)
-                       return err;
-       }
-
-       return v4l2_m2m_streamon(file, fh->m2m_ctx, type);
-}
-
-static int allegro_g_parm(struct file *file, void *fh,
-                         struct v4l2_streamparm *a)
-{
-       struct allegro_channel *channel = fh_to_channel(fh);
-       struct v4l2_fract *timeperframe;
-
-       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-               return -EINVAL;
-
-       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
-       timeperframe = &a->parm.output.timeperframe;
-       timeperframe->numerator = channel->framerate.denominator;
-       timeperframe->denominator = channel->framerate.numerator;
-
-       return 0;
-}
-
-static int allegro_s_parm(struct file *file, void *fh,
-                         struct v4l2_streamparm *a)
-{
-       struct allegro_channel *channel = fh_to_channel(fh);
-       struct v4l2_fract *timeperframe;
-       int div;
-
-       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-               return -EINVAL;
-
-       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
-       timeperframe = &a->parm.output.timeperframe;
-
-       if (timeperframe->numerator == 0 || timeperframe->denominator == 0)
-               return allegro_g_parm(file, fh, a);
-
-       div = gcd(timeperframe->denominator, timeperframe->numerator);
-       channel->framerate.numerator = timeperframe->denominator / div;
-       channel->framerate.denominator = timeperframe->numerator / div;
-
-       return 0;
-}
-
-static int allegro_subscribe_event(struct v4l2_fh *fh,
-                                  const struct v4l2_event_subscription *sub)
-{
-       switch (sub->type) {
-       case V4L2_EVENT_EOS:
-               return v4l2_event_subscribe(fh, sub, 0, NULL);
-       default:
-               return v4l2_ctrl_subscribe_event(fh, sub);
-       }
-}
-
-static const struct v4l2_ioctl_ops allegro_ioctl_ops = {
-       .vidioc_querycap = allegro_querycap,
-       .vidioc_enum_fmt_vid_cap = allegro_enum_fmt_vid,
-       .vidioc_enum_fmt_vid_out = allegro_enum_fmt_vid,
-       .vidioc_g_fmt_vid_cap = allegro_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = allegro_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = allegro_try_fmt_vid_cap,
-       .vidioc_g_fmt_vid_out = allegro_g_fmt_vid_out,
-       .vidioc_try_fmt_vid_out = allegro_try_fmt_vid_out,
-       .vidioc_s_fmt_vid_out = allegro_s_fmt_vid_out,
-
-       .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
-       .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
-
-       .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
-       .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
-       .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
-       .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
-       .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
-
-       .vidioc_streamon = allegro_ioctl_streamon,
-       .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
-
-       .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
-       .vidioc_encoder_cmd = allegro_encoder_cmd,
-       .vidioc_enum_framesizes = allegro_enum_framesizes,
-
-       .vidioc_g_parm          = allegro_g_parm,
-       .vidioc_s_parm          = allegro_s_parm,
-
-       .vidioc_subscribe_event = allegro_subscribe_event,
-       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static const struct v4l2_file_operations allegro_fops = {
-       .owner = THIS_MODULE,
-       .open = allegro_open,
-       .release = allegro_release,
-       .poll = v4l2_m2m_fop_poll,
-       .unlocked_ioctl = video_ioctl2,
-       .mmap = v4l2_m2m_fop_mmap,
-};
-
-static int allegro_register_device(struct allegro_dev *dev)
-{
-       struct video_device *video_dev = &dev->video_dev;
-
-       strscpy(video_dev->name, "allegro", sizeof(video_dev->name));
-       video_dev->fops = &allegro_fops;
-       video_dev->ioctl_ops = &allegro_ioctl_ops;
-       video_dev->release = video_device_release_empty;
-       video_dev->lock = &dev->lock;
-       video_dev->v4l2_dev = &dev->v4l2_dev;
-       video_dev->vfl_dir = VFL_DIR_M2M;
-       video_dev->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
-       video_set_drvdata(video_dev, dev);
-
-       return video_register_device(video_dev, VFL_TYPE_VIDEO, 0);
-}
-
-static void allegro_device_run(void *priv)
-{
-       struct allegro_channel *channel = priv;
-       struct allegro_dev *dev = channel->dev;
-       struct vb2_v4l2_buffer *src_buf;
-       struct vb2_v4l2_buffer *dst_buf;
-       dma_addr_t src_y;
-       dma_addr_t src_uv;
-       dma_addr_t dst_addr;
-       unsigned long dst_size;
-       u64 src_handle;
-       u64 dst_handle;
-
-       dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx);
-       dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
-       dst_size = vb2_plane_size(&dst_buf->vb2_buf, 0);
-       dst_handle = allegro_put_buffer(channel, &channel->stream_shadow_list,
-                                       dst_buf);
-       allegro_mcu_send_put_stream_buffer(dev, channel, dst_addr, dst_size,
-                                          dst_handle);
-
-       src_buf = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx);
-       src_buf->sequence = channel->osequence++;
-       src_y = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
-       src_uv = src_y + (channel->stride * channel->height);
-       src_handle = allegro_put_buffer(channel, &channel->source_shadow_list,
-                                       src_buf);
-       allegro_mcu_send_encode_frame(dev, channel, src_y, src_uv, src_handle);
-
-       v4l2_m2m_job_finish(dev->m2m_dev, channel->fh.m2m_ctx);
-}
-
-static const struct v4l2_m2m_ops allegro_m2m_ops = {
-       .device_run = allegro_device_run,
-};
-
-static int allegro_mcu_hw_init(struct allegro_dev *dev,
-                              const struct fw_info *info)
-{
-       int err;
-
-       dev->mbox_command = allegro_mbox_init(dev, info->mailbox_cmd,
-                                             info->mailbox_size);
-       dev->mbox_status = allegro_mbox_init(dev, info->mailbox_status,
-                                            info->mailbox_size);
-       if (IS_ERR(dev->mbox_command) || IS_ERR(dev->mbox_status)) {
-               v4l2_err(&dev->v4l2_dev,
-                        "failed to initialize mailboxes\n");
-               return -EIO;
-       }
-
-       allegro_mcu_enable_interrupts(dev);
-
-       /* The mcu sends INIT after reset. */
-       allegro_mcu_start(dev);
-       err = allegro_mcu_wait_for_init_timeout(dev, 5000);
-       if (err < 0) {
-               v4l2_err(&dev->v4l2_dev,
-                        "mcu did not send INIT after reset\n");
-               err = -EIO;
-               goto err_disable_interrupts;
-       }
-
-       err = allegro_alloc_buffer(dev, &dev->suballocator,
-                                  info->suballocator_size);
-       if (err) {
-               v4l2_err(&dev->v4l2_dev,
-                        "failed to allocate %zu bytes for suballocator\n",
-                        info->suballocator_size);
-               goto err_reset_mcu;
-       }
-
-       allegro_mcu_send_init(dev, dev->suballocator.paddr,
-                             dev->suballocator.size);
-       err = allegro_mcu_wait_for_init_timeout(dev, 5000);
-       if (err < 0) {
-               v4l2_err(&dev->v4l2_dev,
-                        "mcu failed to configure sub-allocator\n");
-               err = -EIO;
-               goto err_free_suballocator;
-       }
-
-       return 0;
-
-err_free_suballocator:
-       allegro_free_buffer(dev, &dev->suballocator);
-err_reset_mcu:
-       allegro_mcu_reset(dev);
-err_disable_interrupts:
-       allegro_mcu_disable_interrupts(dev);
-
-       return err;
-}
-
-static int allegro_mcu_hw_deinit(struct allegro_dev *dev)
-{
-       int err;
-
-       err = allegro_mcu_reset(dev);
-       if (err)
-               v4l2_warn(&dev->v4l2_dev,
-                         "mcu failed to enter sleep state\n");
-
-       err = allegro_mcu_disable_interrupts(dev);
-       if (err)
-               v4l2_warn(&dev->v4l2_dev,
-                         "failed to disable interrupts\n");
-
-       allegro_free_buffer(dev, &dev->suballocator);
-
-       return 0;
-}
-
-static void allegro_fw_callback(const struct firmware *fw, void *context)
-{
-       struct allegro_dev *dev = context;
-       const char *fw_codec_name = "al5e.fw";
-       const struct firmware *fw_codec;
-       int err;
-
-       if (!fw)
-               return;
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "requesting codec firmware '%s'\n", fw_codec_name);
-       err = request_firmware(&fw_codec, fw_codec_name, &dev->plat_dev->dev);
-       if (err)
-               goto err_release_firmware;
-
-       dev->fw_info = allegro_get_firmware_info(dev, fw, fw_codec);
-       if (!dev->fw_info) {
-               v4l2_err(&dev->v4l2_dev, "firmware is not supported\n");
-               goto err_release_firmware_codec;
-       }
-
-       v4l2_info(&dev->v4l2_dev,
-                 "using mcu firmware version '%s'\n", dev->fw_info->version);
-
-       /* Ensure that the mcu is sleeping at the reset vector */
-       err = allegro_mcu_reset(dev);
-       if (err) {
-               v4l2_err(&dev->v4l2_dev, "failed to reset mcu\n");
-               goto err_release_firmware_codec;
-       }
-
-       allegro_copy_firmware(dev, fw->data, fw->size);
-       allegro_copy_fw_codec(dev, fw_codec->data, fw_codec->size);
-
-       err = allegro_mcu_hw_init(dev, dev->fw_info);
-       if (err) {
-               v4l2_err(&dev->v4l2_dev, "failed to initialize mcu\n");
-               goto err_free_fw_codec;
-       }
-
-       dev->m2m_dev = v4l2_m2m_init(&allegro_m2m_ops);
-       if (IS_ERR(dev->m2m_dev)) {
-               v4l2_err(&dev->v4l2_dev, "failed to init mem2mem device\n");
-               goto err_mcu_hw_deinit;
-       }
-
-       err = allegro_register_device(dev);
-       if (err) {
-               v4l2_err(&dev->v4l2_dev, "failed to register video device\n");
-               goto err_m2m_release;
-       }
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "allegro codec registered as /dev/video%d\n",
-                dev->video_dev.num);
-
-       release_firmware(fw_codec);
-       release_firmware(fw);
-
-       return;
-
-err_m2m_release:
-       v4l2_m2m_release(dev->m2m_dev);
-       dev->m2m_dev = NULL;
-err_mcu_hw_deinit:
-       allegro_mcu_hw_deinit(dev);
-err_free_fw_codec:
-       allegro_free_fw_codec(dev);
-err_release_firmware_codec:
-       release_firmware(fw_codec);
-err_release_firmware:
-       release_firmware(fw);
-}
-
-static int allegro_firmware_request_nowait(struct allegro_dev *dev)
-{
-       const char *fw = "al5e_b.fw";
-
-       v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "requesting firmware '%s'\n", fw);
-       return request_firmware_nowait(THIS_MODULE, true, fw,
-                                      &dev->plat_dev->dev, GFP_KERNEL, dev,
-                                      allegro_fw_callback);
-}
-
-static int allegro_probe(struct platform_device *pdev)
-{
-       struct allegro_dev *dev;
-       struct resource *res, *sram_res;
-       int ret;
-       int irq;
-       void __iomem *regs, *sram_regs;
-
-       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-       dev->plat_dev = pdev;
-       init_completion(&dev->init_complete);
-       INIT_LIST_HEAD(&dev->channels);
-
-       mutex_init(&dev->lock);
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
-       if (!res) {
-               dev_err(&pdev->dev,
-                       "regs resource missing from device tree\n");
-               return -EINVAL;
-       }
-       regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-       if (!regs) {
-               dev_err(&pdev->dev, "failed to map registers\n");
-               return -ENOMEM;
-       }
-       dev->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
-                                           &allegro_regmap_config);
-       if (IS_ERR(dev->regmap)) {
-               dev_err(&pdev->dev, "failed to init regmap\n");
-               return PTR_ERR(dev->regmap);
-       }
-
-       sram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
-       if (!sram_res) {
-               dev_err(&pdev->dev,
-                       "sram resource missing from device tree\n");
-               return -EINVAL;
-       }
-       sram_regs = devm_ioremap(&pdev->dev,
-                                sram_res->start,
-                                resource_size(sram_res));
-       if (!sram_regs) {
-               dev_err(&pdev->dev, "failed to map sram\n");
-               return -ENOMEM;
-       }
-       dev->sram = devm_regmap_init_mmio(&pdev->dev, sram_regs,
-                                         &allegro_sram_config);
-       if (IS_ERR(dev->sram)) {
-               dev_err(&pdev->dev, "failed to init sram\n");
-               return PTR_ERR(dev->sram);
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-       ret = devm_request_threaded_irq(&pdev->dev, irq,
-                                       allegro_hardirq,
-                                       allegro_irq_thread,
-                                       IRQF_SHARED, dev_name(&pdev->dev), dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
-               return ret;
-       }
-
-       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-       if (ret)
-               return ret;
-
-       platform_set_drvdata(pdev, dev);
-
-       ret = allegro_firmware_request_nowait(dev);
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev,
-                        "failed to request firmware: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int allegro_remove(struct platform_device *pdev)
-{
-       struct allegro_dev *dev = platform_get_drvdata(pdev);
-
-       video_unregister_device(&dev->video_dev);
-       if (dev->m2m_dev)
-               v4l2_m2m_release(dev->m2m_dev);
-       allegro_mcu_hw_deinit(dev);
-       allegro_free_fw_codec(dev);
-
-       v4l2_device_unregister(&dev->v4l2_dev);
-
-       return 0;
-}
-
-static const struct of_device_id allegro_dt_ids[] = {
-       { .compatible = "allegro,al5e-1.1" },
-       { /* sentinel */ }
-};
-
-MODULE_DEVICE_TABLE(of, allegro_dt_ids);
-
-static struct platform_driver allegro_driver = {
-       .probe = allegro_probe,
-       .remove = allegro_remove,
-       .driver = {
-               .name = "allegro",
-               .of_match_table = of_match_ptr(allegro_dt_ids),
-       },
-};
-
-module_platform_driver(allegro_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Michael Tretter <kernel@pengutronix.de>");
-MODULE_DESCRIPTION("Allegro DVT encoder driver");
diff --git a/drivers/staging/media/allegro-dvt/allegro-mail.c b/drivers/staging/media/allegro-dvt/allegro-mail.c
deleted file mode 100644 (file)
index 9286d21..0000000
+++ /dev/null
@@ -1,543 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
- *
- * Helper functions for handling messages that are send via mailbox to the
- * Allegro VCU firmware.
- */
-
-#include <linux/bitfield.h>
-#include <linux/export.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/videodev2.h>
-
-#include "allegro-mail.h"
-
-const char *msg_type_name(enum mcu_msg_type type)
-{
-       static char buf[9];
-
-       switch (type) {
-       case MCU_MSG_TYPE_INIT:
-               return "INIT";
-       case MCU_MSG_TYPE_CREATE_CHANNEL:
-               return "CREATE_CHANNEL";
-       case MCU_MSG_TYPE_DESTROY_CHANNEL:
-               return "DESTROY_CHANNEL";
-       case MCU_MSG_TYPE_ENCODE_FRAME:
-               return "ENCODE_FRAME";
-       case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
-               return "PUT_STREAM_BUFFER";
-       case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
-               return "PUSH_BUFFER_INTERMEDIATE";
-       case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
-               return "PUSH_BUFFER_REFERENCE";
-       default:
-               snprintf(buf, sizeof(buf), "(0x%04x)", type);
-               return buf;
-       }
-}
-EXPORT_SYMBOL(msg_type_name);
-
-static ssize_t
-allegro_enc_init(u32 *dst, struct mcu_msg_init_request *msg)
-{
-       unsigned int i = 0;
-       enum mcu_msg_version version = msg->header.version;
-
-       dst[i++] = msg->reserved0;
-       dst[i++] = msg->suballoc_dma;
-       dst[i++] = msg->suballoc_size;
-       dst[i++] = msg->l2_cache[0];
-       dst[i++] = msg->l2_cache[1];
-       dst[i++] = msg->l2_cache[2];
-       if (version >= MCU_MSG_VERSION_2019_2) {
-               dst[i++] = -1;
-               dst[i++] = 0;
-       }
-
-       return i * sizeof(*dst);
-}
-
-static inline u32 settings_get_mcu_codec(struct create_channel_param *param)
-{
-       enum mcu_msg_version version = param->version;
-       u32 pixelformat = param->codec;
-
-       if (version < MCU_MSG_VERSION_2019_2) {
-               switch (pixelformat) {
-               case V4L2_PIX_FMT_H264:
-               default:
-                       return 1;
-               }
-       } else {
-               switch (pixelformat) {
-               case V4L2_PIX_FMT_H264:
-               default:
-                       return 0;
-               }
-       }
-}
-
-ssize_t
-allegro_encode_config_blob(u32 *dst, struct create_channel_param *param)
-{
-       enum mcu_msg_version version = param->version;
-       unsigned int i = 0;
-       unsigned int j = 0;
-       u32 val;
-       unsigned int codec = settings_get_mcu_codec(param);
-
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->layer_id;
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->height) |
-                  FIELD_PREP(GENMASK(15, 0), param->width);
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->videomode;
-       dst[i++] = param->format;
-       if (version < MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->colorspace;
-       dst[i++] = param->src_mode;
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->src_bit_depth;
-       dst[i++] = FIELD_PREP(GENMASK(31, 24), codec) |
-                  FIELD_PREP(GENMASK(23, 8), param->constraint_set_flags) |
-                  FIELD_PREP(GENMASK(7, 0), param->profile);
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->tier) |
-                  FIELD_PREP(GENMASK(15, 0), param->level);
-
-       val = 0;
-       val |= param->temporal_mvp_enable ? BIT(20) : 0;
-       val |= FIELD_PREP(GENMASK(7, 4), param->log2_max_frame_num) |
-              FIELD_PREP(GENMASK(3, 0), param->log2_max_poc);
-       dst[i++] = val;
-
-       val = 0;
-       val |= param->dbf_ovr_en ? BIT(2) : 0;
-       dst[i++] = val;
-
-       if (version >= MCU_MSG_VERSION_2019_2) {
-               val = 0;
-               val |= param->custom_lda ? BIT(2) : 0;
-               val |= param->rdo_cost_mode ? BIT(20) : 0;
-               dst[i++] = val;
-
-               val = 0;
-               val |= param->lf ? BIT(2) : 0;
-               val |= param->lf_x_tile ? BIT(3) : 0;
-               val |= param->lf_x_slice ? BIT(4) : 0;
-               dst[i++] = val;
-       } else {
-               val = 0;
-               dst[i++] = val;
-       }
-
-       dst[i++] = FIELD_PREP(GENMASK(15, 8), param->beta_offset) |
-                  FIELD_PREP(GENMASK(7, 0), param->tc_offset);
-       dst[i++] = param->unknown11;
-       dst[i++] = param->unknown12;
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->num_slices;
-       else
-               dst[i++] = FIELD_PREP(GENMASK(31, 16), param->prefetch_auto) |
-                          FIELD_PREP(GENMASK(15, 0), param->num_slices);
-       dst[i++] = param->prefetch_mem_offset;
-       dst[i++] = param->prefetch_mem_size;
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clip_vrt_range) |
-                  FIELD_PREP(GENMASK(15, 0), param->clip_hrz_range);
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[1]) |
-                  FIELD_PREP(GENMASK(15, 0), param->me_range[0]);
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[3]) |
-                  FIELD_PREP(GENMASK(15, 0), param->me_range[2]);
-       dst[i++] = FIELD_PREP(GENMASK(31, 24), param->min_tu_size) |
-                  FIELD_PREP(GENMASK(23, 16), param->max_tu_size) |
-                  FIELD_PREP(GENMASK(15, 8), param->min_cu_size) |
-                  FIELD_PREP(GENMASK(8, 0), param->max_cu_size);
-       dst[i++] = FIELD_PREP(GENMASK(15, 8), param->max_transfo_depth_intra) |
-                  FIELD_PREP(GENMASK(7, 0), param->max_transfo_depth_inter);
-       dst[i++] = param->entropy_mode;
-       dst[i++] = param->wp_mode;
-
-       dst[i++] = param->rate_control_mode;
-       dst[i++] = param->initial_rem_delay;
-       dst[i++] = param->cpb_size;
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clk_ratio) |
-                  FIELD_PREP(GENMASK(15, 0), param->framerate);
-       dst[i++] = param->target_bitrate;
-       dst[i++] = param->max_bitrate;
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->min_qp) |
-                  FIELD_PREP(GENMASK(15, 0), param->initial_qp);
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->ip_delta) |
-                  FIELD_PREP(GENMASK(15, 0), param->max_qp);
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref) |
-                  FIELD_PREP(GENMASK(15, 0), param->pb_delta);
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref_frequency) |
-                  FIELD_PREP(GENMASK(15, 0), param->golden_delta);
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->rate_control_option;
-       else
-               dst[i++] = 0;
-
-       if (version >= MCU_MSG_VERSION_2019_2) {
-               dst[i++] = param->num_pixel;
-               dst[i++] = FIELD_PREP(GENMASK(31, 16), param->max_pixel_value) |
-                       FIELD_PREP(GENMASK(15, 0), param->max_psnr);
-               for (j = 0; j < 3; j++)
-                       dst[i++] = param->maxpicturesize[j];
-       }
-
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->gop_ctrl_mode;
-       else
-               dst[i++] = 0;
-
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |
-                          FIELD_PREP(GENMASK(23, 16), param->num_b) |
-                          FIELD_PREP(GENMASK(15, 0), param->gop_length);
-       dst[i++] = param->freq_idr;
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->enable_lt;
-       dst[i++] = param->freq_lt;
-       dst[i++] = param->gdr_mode;
-       if (version < MCU_MSG_VERSION_2019_2)
-               dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |
-                          FIELD_PREP(GENMASK(23, 16), param->num_b) |
-                          FIELD_PREP(GENMASK(15, 0), param->gop_length);
-
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->tmpdqp;
-
-       dst[i++] = param->subframe_latency;
-       dst[i++] = param->lda_control_mode;
-       if (version < MCU_MSG_VERSION_2019_2)
-               dst[i++] = param->unknown41;
-
-       if (version >= MCU_MSG_VERSION_2019_2) {
-               for (j = 0; j < 6; j++)
-                       dst[i++] = param->lda_factors[j];
-               dst[i++] = param->max_num_merge_cand;
-       }
-
-       return i * sizeof(*dst);
-}
-
-static ssize_t
-allegro_enc_create_channel(u32 *dst, struct mcu_msg_create_channel *msg)
-{
-       enum mcu_msg_version version = msg->header.version;
-       unsigned int i = 0;
-
-       dst[i++] = msg->user_id;
-
-       if (version >= MCU_MSG_VERSION_2019_2) {
-               dst[i++] = msg->blob_mcu_addr;
-       } else {
-               memcpy(&dst[i], msg->blob, msg->blob_size);
-               i += msg->blob_size / sizeof(*dst);
-       }
-
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = msg->ep1_addr;
-
-       return i * sizeof(*dst);
-}
-
-ssize_t allegro_decode_config_blob(struct create_channel_param *param,
-                                  struct mcu_msg_create_channel_response *msg,
-                                  u32 *src)
-{
-       enum mcu_msg_version version = msg->header.version;
-
-       if (version >= MCU_MSG_VERSION_2019_2) {
-               param->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[9]);
-               param->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[9]);
-       } else {
-               param->num_ref_idx_l0 = msg->num_ref_idx_l0;
-               param->num_ref_idx_l1 = msg->num_ref_idx_l1;
-       }
-
-       return 0;
-}
-
-static ssize_t
-allegro_enc_destroy_channel(u32 *dst, struct mcu_msg_destroy_channel *msg)
-{
-       unsigned int i = 0;
-
-       dst[i++] = msg->channel_id;
-
-       return i * sizeof(*dst);
-}
-
-static ssize_t
-allegro_enc_push_buffers(u32 *dst, struct mcu_msg_push_buffers_internal *msg)
-{
-       unsigned int i = 0;
-       struct mcu_msg_push_buffers_internal_buffer *buffer;
-       unsigned int num_buffers = msg->num_buffers;
-       unsigned int j;
-
-       dst[i++] = msg->channel_id;
-
-       for (j = 0; j < num_buffers; j++) {
-               buffer = &msg->buffer[j];
-               dst[i++] = buffer->dma_addr;
-               dst[i++] = buffer->mcu_addr;
-               dst[i++] = buffer->size;
-       }
-
-       return i * sizeof(*dst);
-}
-
-static ssize_t
-allegro_enc_put_stream_buffer(u32 *dst,
-                             struct mcu_msg_put_stream_buffer *msg)
-{
-       unsigned int i = 0;
-
-       dst[i++] = msg->channel_id;
-       dst[i++] = msg->dma_addr;
-       dst[i++] = msg->mcu_addr;
-       dst[i++] = msg->size;
-       dst[i++] = msg->offset;
-       dst[i++] = lower_32_bits(msg->stream_id);
-       dst[i++] = upper_32_bits(msg->stream_id);
-
-       return i * sizeof(*dst);
-}
-
-static ssize_t
-allegro_enc_encode_frame(u32 *dst, struct mcu_msg_encode_frame *msg)
-{
-       enum mcu_msg_version version = msg->header.version;
-       unsigned int i = 0;
-
-       dst[i++] = msg->channel_id;
-
-       dst[i++] = msg->reserved;
-       dst[i++] = msg->encoding_options;
-       dst[i++] = FIELD_PREP(GENMASK(31, 16), msg->padding) |
-                  FIELD_PREP(GENMASK(15, 0), msg->pps_qp);
-
-       if (version >= MCU_MSG_VERSION_2019_2) {
-               dst[i++] = 0;
-               dst[i++] = 0;
-               dst[i++] = 0;
-               dst[i++] = 0;
-       }
-
-       dst[i++] = lower_32_bits(msg->user_param);
-       dst[i++] = upper_32_bits(msg->user_param);
-       dst[i++] = lower_32_bits(msg->src_handle);
-       dst[i++] = upper_32_bits(msg->src_handle);
-       dst[i++] = msg->request_options;
-       dst[i++] = msg->src_y;
-       dst[i++] = msg->src_uv;
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = msg->is_10_bit;
-       dst[i++] = msg->stride;
-       if (version >= MCU_MSG_VERSION_2019_2)
-               dst[i++] = msg->format;
-       dst[i++] = msg->ep2;
-       dst[i++] = lower_32_bits(msg->ep2_v);
-       dst[i++] = upper_32_bits(msg->ep2_v);
-
-       return i * sizeof(*dst);
-}
-
-static ssize_t
-allegro_dec_init(struct mcu_msg_init_response *msg, u32 *src)
-{
-       unsigned int i = 0;
-
-       msg->reserved0 = src[i++];
-
-       return i * sizeof(*src);
-}
-
-static ssize_t
-allegro_dec_create_channel(struct mcu_msg_create_channel_response *msg,
-                          u32 *src)
-{
-       enum mcu_msg_version version = msg->header.version;
-       unsigned int i = 0;
-
-       msg->channel_id = src[i++];
-       msg->user_id = src[i++];
-       /*
-        * Version >= MCU_MSG_VERSION_2019_2 is handled in
-        * allegro_decode_config_blob().
-        */
-       if (version < MCU_MSG_VERSION_2019_2) {
-               msg->options = src[i++];
-               msg->num_core = src[i++];
-               msg->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[i]);
-               msg->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[i++]);
-       }
-       msg->int_buffers_count = src[i++];
-       msg->int_buffers_size = src[i++];
-       msg->rec_buffers_count = src[i++];
-       msg->rec_buffers_size = src[i++];
-       msg->reserved = src[i++];
-       msg->error_code = src[i++];
-
-       return i * sizeof(*src);
-}
-
-static ssize_t
-allegro_dec_destroy_channel(struct mcu_msg_destroy_channel_response *msg,
-                           u32 *src)
-{
-       unsigned int i = 0;
-
-       msg->channel_id = src[i++];
-
-       return i * sizeof(*src);
-}
-
-static ssize_t
-allegro_dec_encode_frame(struct mcu_msg_encode_frame_response *msg, u32 *src)
-{
-       enum mcu_msg_version version = msg->header.version;
-       unsigned int i = 0;
-       unsigned int j;
-
-       msg->channel_id = src[i++];
-
-       msg->stream_id = src[i++];
-       msg->stream_id |= (((u64)src[i++]) << 32);
-       msg->user_param = src[i++];
-       msg->user_param |= (((u64)src[i++]) << 32);
-       msg->src_handle = src[i++];
-       msg->src_handle |= (((u64)src[i++]) << 32);
-       msg->skip = FIELD_GET(GENMASK(31, 16), src[i]);
-       msg->is_ref = FIELD_GET(GENMASK(15, 0), src[i++]);
-       msg->initial_removal_delay = src[i++];
-       msg->dpb_output_delay = src[i++];
-       msg->size = src[i++];
-       msg->frame_tag_size = src[i++];
-       msg->stuffing = src[i++];
-       msg->filler = src[i++];
-       msg->num_column = FIELD_GET(GENMASK(31, 16), src[i]);
-       msg->num_row = FIELD_GET(GENMASK(15, 0), src[i++]);
-       msg->num_ref_idx_l1 = FIELD_GET(GENMASK(31, 24), src[i]);
-       msg->num_ref_idx_l0 = FIELD_GET(GENMASK(23, 16), src[i]);
-       msg->qp = FIELD_GET(GENMASK(15, 0), src[i++]);
-       msg->partition_table_offset = src[i++];
-       msg->partition_table_size = src[i++];
-       msg->sum_complex = src[i++];
-       for (j = 0; j < 4; j++)
-               msg->tile_width[j] = src[i++];
-       for (j = 0; j < 22; j++)
-               msg->tile_height[j] = src[i++];
-       msg->error_code = src[i++];
-       msg->slice_type = src[i++];
-       msg->pic_struct = src[i++];
-       msg->reserved = FIELD_GET(GENMASK(31, 24), src[i]);
-       msg->is_last_slice = FIELD_GET(GENMASK(23, 16), src[i]);
-       msg->is_first_slice = FIELD_GET(GENMASK(15, 8), src[i]);
-       msg->is_idr = FIELD_GET(GENMASK(7, 0), src[i++]);
-
-       msg->reserved1 = FIELD_GET(GENMASK(31, 16), src[i]);
-       msg->pps_qp = FIELD_GET(GENMASK(15, 0), src[i++]);
-
-       msg->reserved2 = src[i++];
-       if (version >= MCU_MSG_VERSION_2019_2) {
-               msg->reserved3 = src[i++];
-               msg->reserved4 = src[i++];
-               msg->reserved5 = src[i++];
-               msg->reserved6 = src[i++];
-       }
-
-       return i * sizeof(*src);
-}
-
-/**
- * allegro_encode_mail() - Encode allegro messages to firmware format
- * @dst: Pointer to the memory that will be filled with data
- * @msg: The allegro message that will be encoded
- */
-ssize_t allegro_encode_mail(u32 *dst, void *msg)
-{
-       const struct mcu_msg_header *header = msg;
-       ssize_t size;
-
-       if (!msg || !dst)
-               return -EINVAL;
-
-       switch (header->type) {
-       case MCU_MSG_TYPE_INIT:
-               size = allegro_enc_init(&dst[1], msg);
-               break;
-       case MCU_MSG_TYPE_CREATE_CHANNEL:
-               size = allegro_enc_create_channel(&dst[1], msg);
-               break;
-       case MCU_MSG_TYPE_DESTROY_CHANNEL:
-               size = allegro_enc_destroy_channel(&dst[1], msg);
-               break;
-       case MCU_MSG_TYPE_ENCODE_FRAME:
-               size = allegro_enc_encode_frame(&dst[1], msg);
-               break;
-       case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
-               size = allegro_enc_put_stream_buffer(&dst[1], msg);
-               break;
-       case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
-       case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
-               size = allegro_enc_push_buffers(&dst[1], msg);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /*
-        * The encoded messages might have different length depending on
-        * the firmware version or certain fields. Therefore, we have to
-        * set the body length after encoding the message.
-        */
-       dst[0] = FIELD_PREP(GENMASK(31, 16), header->type) |
-                FIELD_PREP(GENMASK(15, 0), size);
-
-       return size + sizeof(*dst);
-}
-
-/**
- * allegro_decode_mail() - Parse allegro messages from the firmware.
- * @msg: The mcu_msg_response that will be filled with parsed values.
- * @src: Pointer to the memory that will be parsed
- *
- * The message format in the mailbox depends on the firmware. Parse the
- * different formats into a uniform message format that can be used without
- * taking care of the firmware version.
- */
-int allegro_decode_mail(void *msg, u32 *src)
-{
-       struct mcu_msg_header *header;
-
-       if (!src || !msg)
-               return -EINVAL;
-
-       header = msg;
-       header->type = FIELD_GET(GENMASK(31, 16), src[0]);
-
-       src++;
-       switch (header->type) {
-       case MCU_MSG_TYPE_INIT:
-               allegro_dec_init(msg, src);
-               break;
-       case MCU_MSG_TYPE_CREATE_CHANNEL:
-               allegro_dec_create_channel(msg, src);
-               break;
-       case MCU_MSG_TYPE_DESTROY_CHANNEL:
-               allegro_dec_destroy_channel(msg, src);
-               break;
-       case MCU_MSG_TYPE_ENCODE_FRAME:
-               allegro_dec_encode_frame(msg, src);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/media/allegro-dvt/allegro-mail.h b/drivers/staging/media/allegro-dvt/allegro-mail.h
deleted file mode 100644 (file)
index 486ecb1..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
- *
- * Allegro VCU firmware mailbox mail definitions
- */
-
-#ifndef ALLEGRO_MAIL_H
-#define ALLEGRO_MAIL_H
-
-#include <linux/kernel.h>
-
-enum mcu_msg_type {
-       MCU_MSG_TYPE_INIT = 0x0000,
-       MCU_MSG_TYPE_CREATE_CHANNEL = 0x0005,
-       MCU_MSG_TYPE_DESTROY_CHANNEL = 0x0006,
-       MCU_MSG_TYPE_ENCODE_FRAME = 0x0007,
-       MCU_MSG_TYPE_PUT_STREAM_BUFFER = 0x0012,
-       MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE = 0x000e,
-       MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE = 0x000f,
-};
-
-enum mcu_msg_version {
-       MCU_MSG_VERSION_2018_2,
-       MCU_MSG_VERSION_2019_2,
-};
-
-const char *msg_type_name(enum mcu_msg_type type);
-
-struct mcu_msg_header {
-       enum mcu_msg_type type;
-       enum mcu_msg_version version;
-};
-
-struct mcu_msg_init_request {
-       struct mcu_msg_header header;
-       u32 reserved0;          /* maybe a unused channel id */
-       u32 suballoc_dma;
-       u32 suballoc_size;
-       s32 l2_cache[3];
-};
-
-struct mcu_msg_init_response {
-       struct mcu_msg_header header;
-       u32 reserved0;
-};
-
-struct create_channel_param {
-       enum mcu_msg_version version;
-       u32 layer_id;
-       u16 width;
-       u16 height;
-       u32 videomode;
-       u32 format;
-       u32 colorspace;
-       u32 src_mode;
-       u32 src_bit_depth;
-       u8 profile;
-       u16 constraint_set_flags;
-       u32 codec;
-       u16 level;
-       u16 tier;
-       u32 log2_max_poc;
-       u32 log2_max_frame_num;
-       u32 temporal_mvp_enable;
-       u32 enable_reordering;
-       u32 dbf_ovr_en;
-       u32 num_ref_idx_l0;
-       u32 num_ref_idx_l1;
-       u32 custom_lda;
-       u32 rdo_cost_mode;
-       u32 lf;
-       u32 lf_x_tile;
-       u32 lf_x_slice;
-       s8 beta_offset;
-       s8 tc_offset;
-       u16 reserved10;
-       u32 unknown11;
-       u32 unknown12;
-       u16 num_slices;
-       u16 prefetch_auto;
-       u32 prefetch_mem_offset;
-       u32 prefetch_mem_size;
-       u16 clip_hrz_range;
-       u16 clip_vrt_range;
-       u16 me_range[4];
-       u8 max_cu_size;
-       u8 min_cu_size;
-       u8 max_tu_size;
-       u8 min_tu_size;
-       u8 max_transfo_depth_inter;
-       u8 max_transfo_depth_intra;
-       u16 reserved20;
-       u32 entropy_mode;
-       u32 wp_mode;
-
-       /* rate control param */
-       u32 rate_control_mode;
-       u32 initial_rem_delay;
-       u32 cpb_size;
-       u16 framerate;
-       u16 clk_ratio;
-       u32 target_bitrate;
-       u32 max_bitrate;
-       u16 initial_qp;
-       u16 min_qp;
-       u16 max_qp;
-       s16 ip_delta;
-       s16 pb_delta;
-       u16 golden_ref;
-       u16 golden_delta;
-       u16 golden_ref_frequency;
-       u32 rate_control_option;
-       u32 num_pixel;
-       u16 max_psnr;
-       u16 max_pixel_value;
-       u32 maxpicturesize[3];
-
-       /* gop param */
-       u32 gop_ctrl_mode;
-       u32 freq_idr;
-       u32 freq_lt;
-       u32 gdr_mode;
-       u16 gop_length;
-       u8 num_b;
-       u8 freq_golden_ref;
-       u32 enable_lt;
-       u32 tmpdqp;
-
-       u32 subframe_latency;
-       u32 lda_control_mode;
-       u32 unknown41;
-
-       u32 lda_factors[6];
-
-       u32 max_num_merge_cand;
-};
-
-struct mcu_msg_create_channel {
-       struct mcu_msg_header header;
-       u32 user_id;
-       u32 *blob;
-       size_t blob_size;
-       u32 blob_mcu_addr;
-       u32 ep1_addr;
-};
-
-struct mcu_msg_create_channel_response {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       u32 user_id;
-       u32 options;
-       u32 num_core;
-       u32 num_ref_idx_l0;
-       u32 num_ref_idx_l1;
-       u32 int_buffers_count;
-       u32 int_buffers_size;
-       u32 rec_buffers_count;
-       u32 rec_buffers_size;
-       u32 reserved;
-       u32 error_code;
-};
-
-struct mcu_msg_destroy_channel {
-       struct mcu_msg_header header;
-       u32 channel_id;
-};
-
-struct mcu_msg_destroy_channel_response {
-       struct mcu_msg_header header;
-       u32 channel_id;
-};
-
-struct mcu_msg_push_buffers_internal_buffer {
-       u32 dma_addr;
-       u32 mcu_addr;
-       u32 size;
-};
-
-struct mcu_msg_push_buffers_internal {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       size_t num_buffers;
-       struct mcu_msg_push_buffers_internal_buffer buffer[];
-};
-
-struct mcu_msg_put_stream_buffer {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       u32 dma_addr;
-       u32 mcu_addr;
-       u32 size;
-       u32 offset;
-       u64 stream_id;
-};
-
-struct mcu_msg_encode_frame {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       u32 reserved;
-
-       u32 encoding_options;
-#define AL_OPT_USE_QP_TABLE            BIT(0)
-#define AL_OPT_FORCE_LOAD              BIT(1)
-#define AL_OPT_USE_L2                  BIT(2)
-#define AL_OPT_DISABLE_INTRA           BIT(3)
-#define AL_OPT_DEPENDENT_SLICES                BIT(4)
-
-       s16 pps_qp;
-       u16 padding;
-       u64 user_param;
-       u64 src_handle;
-
-       u32 request_options;
-#define AL_OPT_SCENE_CHANGE            BIT(0)
-#define AL_OPT_RESTART_GOP             BIT(1)
-#define AL_OPT_USE_LONG_TERM           BIT(2)
-#define AL_OPT_UPDATE_PARAMS           BIT(3)
-
-       /* u32 scene_change_delay (optional) */
-       /* rate control param (optional) */
-       /* gop param (optional) */
-       /* dynamic resolution params (optional) */
-       u32 src_y;
-       u32 src_uv;
-       u32 is_10_bit;
-       u32 stride;
-       u32 format;
-       u32 ep2;
-       u64 ep2_v;
-};
-
-struct mcu_msg_encode_frame_response {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       u64 stream_id;          /* see mcu_msg_put_stream_buffer */
-       u64 user_param;         /* see mcu_msg_encode_frame */
-       u64 src_handle;         /* see mcu_msg_encode_frame */
-       u16 skip;
-       u16 is_ref;
-       u32 initial_removal_delay;
-       u32 dpb_output_delay;
-       u32 size;
-       u32 frame_tag_size;
-       s32 stuffing;
-       s32 filler;
-       u16 num_column;
-       u16 num_row;
-       u16 qp;
-       u8 num_ref_idx_l0;
-       u8 num_ref_idx_l1;
-       u32 partition_table_offset;
-       s32 partition_table_size;
-       u32 sum_complex;
-       s32 tile_width[4];
-       s32 tile_height[22];
-       u32 error_code;
-
-       u32 slice_type;
-#define AL_ENC_SLICE_TYPE_B             0
-#define AL_ENC_SLICE_TYPE_P             1
-#define AL_ENC_SLICE_TYPE_I             2
-
-       u32 pic_struct;
-       u8 is_idr;
-       u8 is_first_slice;
-       u8 is_last_slice;
-       u8 reserved;
-       u16 pps_qp;
-       u16 reserved1;
-       u32 reserved2;
-       u32 reserved3;
-       u32 reserved4;
-       u32 reserved5;
-       u32 reserved6;
-};
-
-union mcu_msg_response {
-       struct mcu_msg_header header;
-       struct mcu_msg_init_response init;
-       struct mcu_msg_create_channel_response create_channel;
-       struct mcu_msg_destroy_channel_response destroy_channel;
-       struct mcu_msg_encode_frame_response encode_frame;
-};
-
-ssize_t allegro_encode_config_blob(u32 *dst, struct create_channel_param *param);
-ssize_t allegro_decode_config_blob(struct create_channel_param *param,
-                                  struct mcu_msg_create_channel_response *msg,
-                                  u32 *src);
-
-int allegro_decode_mail(void *msg, u32 *src);
-ssize_t allegro_encode_mail(u32 *dst, void *msg);
-
-#endif
diff --git a/drivers/staging/media/allegro-dvt/nal-h264.c b/drivers/staging/media/allegro-dvt/nal-h264.c
deleted file mode 100644 (file)
index bd48b88..0000000
+++ /dev/null
@@ -1,1001 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
- *
- * Convert NAL units between raw byte sequence payloads (RBSP) and C structs
- *
- * The conversion is defined in "ITU-T Rec. H.264 (04/2017) Advanced video
- * coding for generic audiovisual services". Decoder drivers may use the
- * parser to parse RBSP from encoded streams and configure the hardware, if
- * the hardware is not able to parse RBSP itself.  Encoder drivers may use the
- * generator to generate the RBSP for SPS/PPS nal units and add them to the
- * encoded stream if the hardware does not generate the units.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/v4l2-controls.h>
-
-#include <linux/device.h>
-#include <linux/export.h>
-#include <linux/log2.h>
-
-#include "nal-h264.h"
-
-/*
- * See Rec. ITU-T H.264 (04/2017) Table 7-1 â€“ NAL unit type codes, syntax
- * element categories, and NAL unit type classes
- */
-enum nal_unit_type {
-       SEQUENCE_PARAMETER_SET = 7,
-       PICTURE_PARAMETER_SET = 8,
-       FILLER_DATA = 12,
-};
-
-struct rbsp;
-
-struct nal_h264_ops {
-       int (*rbsp_bit)(struct rbsp *rbsp, int *val);
-       int (*rbsp_bits)(struct rbsp *rbsp, int n, unsigned int *val);
-       int (*rbsp_uev)(struct rbsp *rbsp, unsigned int *val);
-       int (*rbsp_sev)(struct rbsp *rbsp, int *val);
-};
-
-/**
- * struct rbsp - State object for handling a raw byte sequence payload
- * @data: pointer to the data of the rbsp
- * @size: maximum size of the data of the rbsp
- * @pos: current bit position inside the rbsp
- * @num_consecutive_zeros: number of zeros before @pos
- * @ops: per datatype functions for interacting with the rbsp
- * @error: an error occurred while handling the rbsp
- *
- * This struct is passed around the various parsing functions and tracks the
- * current position within the raw byte sequence payload.
- *
- * The @ops field allows to separate the operation, i.e., reading/writing a
- * value from/to that rbsp, from the structure of the NAL unit. This allows to
- * have a single function for iterating the NAL unit, while @ops has function
- * pointers for handling each type in the rbsp.
- */
-struct rbsp {
-       u8 *data;
-       size_t size;
-       unsigned int pos;
-       unsigned int num_consecutive_zeros;
-       struct nal_h264_ops *ops;
-       int error;
-};
-
-static void rbsp_init(struct rbsp *rbsp, void *addr, size_t size,
-                     struct nal_h264_ops *ops)
-{
-       if (!rbsp)
-               return;
-
-       rbsp->data = addr;
-       rbsp->size = size;
-       rbsp->pos = 0;
-       rbsp->ops = ops;
-       rbsp->error = 0;
-}
-
-/**
- * nal_h264_profile_from_v4l2() - Get profile_idc for v4l2 h264 profile
- * @profile: the profile as &enum v4l2_mpeg_video_h264_profile
- *
- * Convert the &enum v4l2_mpeg_video_h264_profile to profile_idc as specified
- * in Rec. ITU-T H.264 (04/2017) A.2.
- *
- * Return: the profile_idc for the passed level
- */
-int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile)
-{
-       switch (profile) {
-       case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
-               return 66;
-       case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
-               return 77;
-       case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
-               return 88;
-       case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
-               return 100;
-       default:
-               return -EINVAL;
-       }
-}
-
-/**
- * nal_h264_level_from_v4l2() - Get level_idc for v4l2 h264 level
- * @level: the level as &enum v4l2_mpeg_video_h264_level
- *
- * Convert the &enum v4l2_mpeg_video_h264_level to level_idc as specified in
- * Rec. ITU-T H.264 (04/2017) A.3.2.
- *
- * Return: the level_idc for the passed level
- */
-int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level)
-{
-       switch (level) {
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
-               return 10;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
-               return 9;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
-               return 11;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
-               return 12;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
-               return 13;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
-               return 20;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
-               return 21;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
-               return 22;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
-               return 30;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
-               return 31;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
-               return 32;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
-               return 40;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
-               return 41;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
-               return 42;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
-               return 50;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
-               return 51;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value);
-static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value);
-
-/*
- * When reading or writing, the emulation_prevention_three_byte is detected
- * only when the 2 one bits need to be inserted. Therefore, we are not
- * actually adding the 0x3 byte, but the 2 one bits and the six 0 bits of the
- * next byte.
- */
-#define EMULATION_PREVENTION_THREE_BYTE (0x3 << 6)
-
-static int add_emulation_prevention_three_byte(struct rbsp *rbsp)
-{
-       rbsp->num_consecutive_zeros = 0;
-       rbsp_write_bits(rbsp, 8, EMULATION_PREVENTION_THREE_BYTE);
-
-       return 0;
-}
-
-static int discard_emulation_prevention_three_byte(struct rbsp *rbsp)
-{
-       unsigned int tmp = 0;
-
-       rbsp->num_consecutive_zeros = 0;
-       rbsp_read_bits(rbsp, 8, &tmp);
-       if (tmp != EMULATION_PREVENTION_THREE_BYTE)
-               return -EINVAL;
-
-       return 0;
-}
-
-static inline int rbsp_read_bit(struct rbsp *rbsp)
-{
-       int shift;
-       int ofs;
-       int bit;
-       int err;
-
-       if (rbsp->num_consecutive_zeros == 22) {
-               err = discard_emulation_prevention_three_byte(rbsp);
-               if (err)
-                       return err;
-       }
-
-       shift = 7 - (rbsp->pos % 8);
-       ofs = rbsp->pos / 8;
-       if (ofs >= rbsp->size)
-               return -EINVAL;
-
-       bit = (rbsp->data[ofs] >> shift) & 1;
-
-       rbsp->pos++;
-
-       if (bit == 1 ||
-           (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0)))
-               rbsp->num_consecutive_zeros = 0;
-       else
-               rbsp->num_consecutive_zeros++;
-
-       return bit;
-}
-
-static inline int rbsp_write_bit(struct rbsp *rbsp, bool value)
-{
-       int shift;
-       int ofs;
-
-       if (rbsp->num_consecutive_zeros == 22)
-               add_emulation_prevention_three_byte(rbsp);
-
-       shift = 7 - (rbsp->pos % 8);
-       ofs = rbsp->pos / 8;
-       if (ofs >= rbsp->size)
-               return -EINVAL;
-
-       rbsp->data[ofs] &= ~(1 << shift);
-       rbsp->data[ofs] |= value << shift;
-
-       rbsp->pos++;
-
-       if (value ||
-           (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0))) {
-               rbsp->num_consecutive_zeros = 0;
-       } else {
-               rbsp->num_consecutive_zeros++;
-       }
-
-       return 0;
-}
-
-static inline int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value)
-{
-       int i;
-       int bit;
-       unsigned int tmp = 0;
-
-       if (n > 8 * sizeof(*value))
-               return -EINVAL;
-
-       for (i = n; i > 0; i--) {
-               bit = rbsp_read_bit(rbsp);
-               if (bit < 0)
-                       return bit;
-               tmp |= bit << (i - 1);
-       }
-
-       if (value)
-               *value = tmp;
-
-       return 0;
-}
-
-static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value)
-{
-       int ret;
-
-       if (n > 8 * sizeof(value))
-               return -EINVAL;
-
-       while (n--) {
-               ret = rbsp_write_bit(rbsp, (value >> n) & 1);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static int rbsp_read_uev(struct rbsp *rbsp, unsigned int *value)
-{
-       int leading_zero_bits = 0;
-       unsigned int tmp = 0;
-       int ret;
-
-       while ((ret = rbsp_read_bit(rbsp)) == 0)
-               leading_zero_bits++;
-       if (ret < 0)
-               return ret;
-
-       if (leading_zero_bits > 0) {
-               ret = rbsp_read_bits(rbsp, leading_zero_bits, &tmp);
-               if (ret)
-                       return ret;
-       }
-
-       if (value)
-               *value = (1 << leading_zero_bits) - 1 + tmp;
-
-       return 0;
-}
-
-static int rbsp_write_uev(struct rbsp *rbsp, unsigned int *value)
-{
-       int ret;
-       int leading_zero_bits;
-
-       if (!value)
-               return -EINVAL;
-
-       leading_zero_bits = ilog2(*value + 1);
-
-       ret = rbsp_write_bits(rbsp, leading_zero_bits, 0);
-       if (ret)
-               return ret;
-
-       return rbsp_write_bits(rbsp, leading_zero_bits + 1, *value + 1);
-}
-
-static int rbsp_read_sev(struct rbsp *rbsp, int *value)
-{
-       int ret;
-       unsigned int tmp;
-
-       ret = rbsp_read_uev(rbsp, &tmp);
-       if (ret)
-               return ret;
-
-       if (value) {
-               if (tmp & 1)
-                       *value = (tmp + 1) / 2;
-               else
-                       *value = -(tmp / 2);
-       }
-
-       return 0;
-}
-
-static int rbsp_write_sev(struct rbsp *rbsp, int *value)
-{
-       unsigned int tmp;
-
-       if (!value)
-               return -EINVAL;
-
-       if (*value > 0)
-               tmp = (2 * (*value)) | 1;
-       else
-               tmp = -2 * (*value);
-
-       return rbsp_write_uev(rbsp, &tmp);
-}
-
-static int __rbsp_write_bit(struct rbsp *rbsp, int *value)
-{
-       return rbsp_write_bit(rbsp, *value);
-}
-
-static int __rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int *value)
-{
-       return rbsp_write_bits(rbsp, n, *value);
-}
-
-static struct nal_h264_ops write = {
-       .rbsp_bit = __rbsp_write_bit,
-       .rbsp_bits = __rbsp_write_bits,
-       .rbsp_uev = rbsp_write_uev,
-       .rbsp_sev = rbsp_write_sev,
-};
-
-static int __rbsp_read_bit(struct rbsp *rbsp, int *value)
-{
-       int tmp = rbsp_read_bit(rbsp);
-
-       if (tmp < 0)
-               return tmp;
-       *value = tmp;
-
-       return 0;
-}
-
-static struct nal_h264_ops read = {
-       .rbsp_bit = __rbsp_read_bit,
-       .rbsp_bits = rbsp_read_bits,
-       .rbsp_uev = rbsp_read_uev,
-       .rbsp_sev = rbsp_read_sev,
-};
-
-static inline void rbsp_bit(struct rbsp *rbsp, int *value)
-{
-       if (rbsp->error)
-               return;
-       rbsp->error = rbsp->ops->rbsp_bit(rbsp, value);
-}
-
-static inline void rbsp_bits(struct rbsp *rbsp, int n, int *value)
-{
-       if (rbsp->error)
-               return;
-       rbsp->error = rbsp->ops->rbsp_bits(rbsp, n, value);
-}
-
-static inline void rbsp_uev(struct rbsp *rbsp, unsigned int *value)
-{
-       if (rbsp->error)
-               return;
-       rbsp->error = rbsp->ops->rbsp_uev(rbsp, value);
-}
-
-static inline void rbsp_sev(struct rbsp *rbsp, int *value)
-{
-       if (rbsp->error)
-               return;
-       rbsp->error = rbsp->ops->rbsp_sev(rbsp, value);
-}
-
-static void nal_h264_rbsp_trailing_bits(struct rbsp *rbsp)
-{
-       unsigned int rbsp_stop_one_bit = 1;
-       unsigned int rbsp_alignment_zero_bit = 0;
-
-       rbsp_bit(rbsp, &rbsp_stop_one_bit);
-       rbsp_bits(rbsp, round_up(rbsp->pos, 8) - rbsp->pos,
-                 &rbsp_alignment_zero_bit);
-}
-
-static void nal_h264_write_start_code_prefix(struct rbsp *rbsp)
-{
-       u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
-       int i = 4;
-
-       if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
-               rbsp->error = -EINVAL;
-               return;
-       }
-
-       p[0] = 0x00;
-       p[1] = 0x00;
-       p[2] = 0x00;
-       p[3] = 0x01;
-
-       rbsp->pos += i * 8;
-}
-
-static void nal_h264_read_start_code_prefix(struct rbsp *rbsp)
-{
-       u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
-       int i = 4;
-
-       if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
-               rbsp->error = -EINVAL;
-               return;
-       }
-
-       if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x01) {
-               rbsp->error = -EINVAL;
-               return;
-       }
-
-       rbsp->pos += i * 8;
-}
-
-static void nal_h264_write_filler_data(struct rbsp *rbsp)
-{
-       u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
-       int i;
-
-       /* Keep 1 byte extra for terminating the NAL unit */
-       i = rbsp->size - DIV_ROUND_UP(rbsp->pos, 8) - 1;
-       memset(p, 0xff, i);
-       rbsp->pos += i * 8;
-}
-
-static void nal_h264_read_filler_data(struct rbsp *rbsp)
-{
-       u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
-
-       while (*p == 0xff) {
-               if (DIV_ROUND_UP(rbsp->pos, 8) > rbsp->size) {
-                       rbsp->error = -EINVAL;
-                       return;
-               }
-
-               p++;
-               rbsp->pos += 8;
-       }
-}
-
-static void nal_h264_rbsp_hrd_parameters(struct rbsp *rbsp,
-                                        struct nal_h264_hrd_parameters *hrd)
-{
-       unsigned int i;
-
-       if (!hrd) {
-               rbsp->error = -EINVAL;
-               return;
-       }
-
-       rbsp_uev(rbsp, &hrd->cpb_cnt_minus1);
-       rbsp_bits(rbsp, 4, &hrd->bit_rate_scale);
-       rbsp_bits(rbsp, 4, &hrd->cpb_size_scale);
-
-       for (i = 0; i <= hrd->cpb_cnt_minus1; i++) {
-               rbsp_uev(rbsp, &hrd->bit_rate_value_minus1[i]);
-               rbsp_uev(rbsp, &hrd->cpb_size_value_minus1[i]);
-               rbsp_bit(rbsp, &hrd->cbr_flag[i]);
-       }
-
-       rbsp_bits(rbsp, 5, &hrd->initial_cpb_removal_delay_length_minus1);
-       rbsp_bits(rbsp, 5, &hrd->cpb_removal_delay_length_minus1);
-       rbsp_bits(rbsp, 5, &hrd->dpb_output_delay_length_minus1);
-       rbsp_bits(rbsp, 5, &hrd->time_offset_length);
-}
-
-static void nal_h264_rbsp_vui_parameters(struct rbsp *rbsp,
-                                        struct nal_h264_vui_parameters *vui)
-{
-       if (!vui) {
-               rbsp->error = -EINVAL;
-               return;
-       }
-
-       rbsp_bit(rbsp, &vui->aspect_ratio_info_present_flag);
-       if (vui->aspect_ratio_info_present_flag) {
-               rbsp_bits(rbsp, 8, &vui->aspect_ratio_idc);
-               if (vui->aspect_ratio_idc == 255) {
-                       rbsp_bits(rbsp, 16, &vui->sar_width);
-                       rbsp_bits(rbsp, 16, &vui->sar_height);
-               }
-       }
-
-       rbsp_bit(rbsp, &vui->overscan_info_present_flag);
-       if (vui->overscan_info_present_flag)
-               rbsp_bit(rbsp, &vui->overscan_appropriate_flag);
-
-       rbsp_bit(rbsp, &vui->video_signal_type_present_flag);
-       if (vui->video_signal_type_present_flag) {
-               rbsp_bits(rbsp, 3, &vui->video_format);
-               rbsp_bit(rbsp, &vui->video_full_range_flag);
-
-               rbsp_bit(rbsp, &vui->colour_description_present_flag);
-               if (vui->colour_description_present_flag) {
-                       rbsp_bits(rbsp, 8, &vui->colour_primaries);
-                       rbsp_bits(rbsp, 8, &vui->transfer_characteristics);
-                       rbsp_bits(rbsp, 8, &vui->matrix_coefficients);
-               }
-       }
-
-       rbsp_bit(rbsp, &vui->chroma_loc_info_present_flag);
-       if (vui->chroma_loc_info_present_flag) {
-               rbsp_uev(rbsp, &vui->chroma_sample_loc_type_top_field);
-               rbsp_uev(rbsp, &vui->chroma_sample_loc_type_bottom_field);
-       }
-
-       rbsp_bit(rbsp, &vui->timing_info_present_flag);
-       if (vui->timing_info_present_flag) {
-               rbsp_bits(rbsp, 32, &vui->num_units_in_tick);
-               rbsp_bits(rbsp, 32, &vui->time_scale);
-               rbsp_bit(rbsp, &vui->fixed_frame_rate_flag);
-       }
-
-       rbsp_bit(rbsp, &vui->nal_hrd_parameters_present_flag);
-       if (vui->nal_hrd_parameters_present_flag)
-               nal_h264_rbsp_hrd_parameters(rbsp, &vui->nal_hrd_parameters);
-
-       rbsp_bit(rbsp, &vui->vcl_hrd_parameters_present_flag);
-       if (vui->vcl_hrd_parameters_present_flag)
-               nal_h264_rbsp_hrd_parameters(rbsp, &vui->vcl_hrd_parameters);
-
-       if (vui->nal_hrd_parameters_present_flag ||
-           vui->vcl_hrd_parameters_present_flag)
-               rbsp_bit(rbsp, &vui->low_delay_hrd_flag);
-
-       rbsp_bit(rbsp, &vui->pic_struct_present_flag);
-
-       rbsp_bit(rbsp, &vui->bitstream_restriction_flag);
-       if (vui->bitstream_restriction_flag) {
-               rbsp_bit(rbsp, &vui->motion_vectors_over_pic_boundaries_flag);
-               rbsp_uev(rbsp, &vui->max_bytes_per_pic_denom);
-               rbsp_uev(rbsp, &vui->max_bits_per_mb_denom);
-               rbsp_uev(rbsp, &vui->log2_max_mv_length_horizontal);
-               rbsp_uev(rbsp, &vui->log21_max_mv_length_vertical);
-               rbsp_uev(rbsp, &vui->max_num_reorder_frames);
-               rbsp_uev(rbsp, &vui->max_dec_frame_buffering);
-       }
-}
-
-static void nal_h264_rbsp_sps(struct rbsp *rbsp, struct nal_h264_sps *sps)
-{
-       unsigned int i;
-
-       if (!sps) {
-               rbsp->error = -EINVAL;
-               return;
-       }
-
-       rbsp_bits(rbsp, 8, &sps->profile_idc);
-       rbsp_bit(rbsp, &sps->constraint_set0_flag);
-       rbsp_bit(rbsp, &sps->constraint_set1_flag);
-       rbsp_bit(rbsp, &sps->constraint_set2_flag);
-       rbsp_bit(rbsp, &sps->constraint_set3_flag);
-       rbsp_bit(rbsp, &sps->constraint_set4_flag);
-       rbsp_bit(rbsp, &sps->constraint_set5_flag);
-       rbsp_bits(rbsp, 2, &sps->reserved_zero_2bits);
-       rbsp_bits(rbsp, 8, &sps->level_idc);
-
-       rbsp_uev(rbsp, &sps->seq_parameter_set_id);
-
-       if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
-           sps->profile_idc == 122 || sps->profile_idc == 244 ||
-           sps->profile_idc == 44 || sps->profile_idc == 83 ||
-           sps->profile_idc == 86 || sps->profile_idc == 118 ||
-           sps->profile_idc == 128 || sps->profile_idc == 138 ||
-           sps->profile_idc == 139 || sps->profile_idc == 134 ||
-           sps->profile_idc == 135) {
-               rbsp_uev(rbsp, &sps->chroma_format_idc);
-
-               if (sps->chroma_format_idc == 3)
-                       rbsp_bit(rbsp, &sps->separate_colour_plane_flag);
-               rbsp_uev(rbsp, &sps->bit_depth_luma_minus8);
-               rbsp_uev(rbsp, &sps->bit_depth_chroma_minus8);
-               rbsp_bit(rbsp, &sps->qpprime_y_zero_transform_bypass_flag);
-               rbsp_bit(rbsp, &sps->seq_scaling_matrix_present_flag);
-               if (sps->seq_scaling_matrix_present_flag)
-                       rbsp->error = -EINVAL;
-       }
-
-       rbsp_uev(rbsp, &sps->log2_max_frame_num_minus4);
-
-       rbsp_uev(rbsp, &sps->pic_order_cnt_type);
-       switch (sps->pic_order_cnt_type) {
-       case 0:
-               rbsp_uev(rbsp, &sps->log2_max_pic_order_cnt_lsb_minus4);
-               break;
-       case 1:
-               rbsp_bit(rbsp, &sps->delta_pic_order_always_zero_flag);
-               rbsp_sev(rbsp, &sps->offset_for_non_ref_pic);
-               rbsp_sev(rbsp, &sps->offset_for_top_to_bottom_field);
-
-               rbsp_uev(rbsp, &sps->num_ref_frames_in_pic_order_cnt_cycle);
-               for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
-                       rbsp_sev(rbsp, &sps->offset_for_ref_frame[i]);
-               break;
-       default:
-               rbsp->error = -EINVAL;
-               break;
-       }
-
-       rbsp_uev(rbsp, &sps->max_num_ref_frames);
-       rbsp_bit(rbsp, &sps->gaps_in_frame_num_value_allowed_flag);
-       rbsp_uev(rbsp, &sps->pic_width_in_mbs_minus1);
-       rbsp_uev(rbsp, &sps->pic_height_in_map_units_minus1);
-
-       rbsp_bit(rbsp, &sps->frame_mbs_only_flag);
-       if (!sps->frame_mbs_only_flag)
-               rbsp_bit(rbsp, &sps->mb_adaptive_frame_field_flag);
-
-       rbsp_bit(rbsp, &sps->direct_8x8_inference_flag);
-
-       rbsp_bit(rbsp, &sps->frame_cropping_flag);
-       if (sps->frame_cropping_flag) {
-               rbsp_uev(rbsp, &sps->crop_left);
-               rbsp_uev(rbsp, &sps->crop_right);
-               rbsp_uev(rbsp, &sps->crop_top);
-               rbsp_uev(rbsp, &sps->crop_bottom);
-       }
-
-       rbsp_bit(rbsp, &sps->vui_parameters_present_flag);
-       if (sps->vui_parameters_present_flag)
-               nal_h264_rbsp_vui_parameters(rbsp, &sps->vui);
-}
-
-static void nal_h264_rbsp_pps(struct rbsp *rbsp, struct nal_h264_pps *pps)
-{
-       int i;
-
-       rbsp_uev(rbsp, &pps->pic_parameter_set_id);
-       rbsp_uev(rbsp, &pps->seq_parameter_set_id);
-       rbsp_bit(rbsp, &pps->entropy_coding_mode_flag);
-       rbsp_bit(rbsp, &pps->bottom_field_pic_order_in_frame_present_flag);
-       rbsp_uev(rbsp, &pps->num_slice_groups_minus1);
-       if (pps->num_slice_groups_minus1 > 0) {
-               rbsp_uev(rbsp, &pps->slice_group_map_type);
-               switch (pps->slice_group_map_type) {
-               case 0:
-                       for (i = 0; i < pps->num_slice_groups_minus1; i++)
-                               rbsp_uev(rbsp, &pps->run_length_minus1[i]);
-                       break;
-               case 2:
-                       for (i = 0; i < pps->num_slice_groups_minus1; i++) {
-                               rbsp_uev(rbsp, &pps->top_left[i]);
-                               rbsp_uev(rbsp, &pps->bottom_right[i]);
-                       }
-                       break;
-               case 3: case 4: case 5:
-                       rbsp_bit(rbsp, &pps->slice_group_change_direction_flag);
-                       rbsp_uev(rbsp, &pps->slice_group_change_rate_minus1);
-                       break;
-               case 6:
-                       rbsp_uev(rbsp, &pps->pic_size_in_map_units_minus1);
-                       for (i = 0; i < pps->pic_size_in_map_units_minus1; i++)
-                               rbsp_bits(rbsp,
-                                         order_base_2(pps->num_slice_groups_minus1 + 1),
-                                         &pps->slice_group_id[i]);
-                       break;
-               default:
-                       break;
-               }
-       }
-       rbsp_uev(rbsp, &pps->num_ref_idx_l0_default_active_minus1);
-       rbsp_uev(rbsp, &pps->num_ref_idx_l1_default_active_minus1);
-       rbsp_bit(rbsp, &pps->weighted_pred_flag);
-       rbsp_bits(rbsp, 2, &pps->weighted_bipred_idc);
-       rbsp_sev(rbsp, &pps->pic_init_qp_minus26);
-       rbsp_sev(rbsp, &pps->pic_init_qs_minus26);
-       rbsp_sev(rbsp, &pps->chroma_qp_index_offset);
-       rbsp_bit(rbsp, &pps->deblocking_filter_control_present_flag);
-       rbsp_bit(rbsp, &pps->constrained_intra_pred_flag);
-       rbsp_bit(rbsp, &pps->redundant_pic_cnt_present_flag);
-       if (/* more_rbsp_data() */ false) {
-               rbsp_bit(rbsp, &pps->transform_8x8_mode_flag);
-               rbsp_bit(rbsp, &pps->pic_scaling_matrix_present_flag);
-               if (pps->pic_scaling_matrix_present_flag)
-                       rbsp->error = -EINVAL;
-               rbsp_sev(rbsp, &pps->second_chroma_qp_index_offset);
-       }
-}
-
-/**
- * nal_h264_write_sps() - Write SPS NAL unit into RBSP format
- * @dev: device pointer
- * @dest: the buffer that is filled with RBSP data
- * @n: maximum size of @dest in bytes
- * @sps: &struct nal_h264_sps to convert to RBSP
- *
- * Convert @sps to RBSP data and write it into @dest.
- *
- * The size of the SPS NAL unit is not known in advance and this function will
- * fail, if @dest does not hold sufficient space for the SPS NAL unit.
- *
- * Return: number of bytes written to @dest or negative error code
- */
-ssize_t nal_h264_write_sps(const struct device *dev,
-                          void *dest, size_t n, struct nal_h264_sps *sps)
-{
-       struct rbsp rbsp;
-       unsigned int forbidden_zero_bit = 0;
-       unsigned int nal_ref_idc = 0;
-       unsigned int nal_unit_type = SEQUENCE_PARAMETER_SET;
-
-       if (!dest)
-               return -EINVAL;
-
-       rbsp_init(&rbsp, dest, n, &write);
-
-       nal_h264_write_start_code_prefix(&rbsp);
-
-       rbsp_bit(&rbsp, &forbidden_zero_bit);
-       rbsp_bits(&rbsp, 2, &nal_ref_idc);
-       rbsp_bits(&rbsp, 5, &nal_unit_type);
-
-       nal_h264_rbsp_sps(&rbsp, sps);
-
-       nal_h264_rbsp_trailing_bits(&rbsp);
-
-       if (rbsp.error)
-               return rbsp.error;
-
-       return DIV_ROUND_UP(rbsp.pos, 8);
-}
-EXPORT_SYMBOL_GPL(nal_h264_write_sps);
-
-/**
- * nal_h264_read_sps() - Read SPS NAL unit from RBSP format
- * @dev: device pointer
- * @sps: the &struct nal_h264_sps to fill from the RBSP data
- * @src: the buffer that contains the RBSP data
- * @n: size of @src in bytes
- *
- * Read RBSP data from @src and use it to fill @sps.
- *
- * Return: number of bytes read from @src or negative error code
- */
-ssize_t nal_h264_read_sps(const struct device *dev,
-                         struct nal_h264_sps *sps, void *src, size_t n)
-{
-       struct rbsp rbsp;
-       unsigned int forbidden_zero_bit;
-       unsigned int nal_ref_idc;
-       unsigned int nal_unit_type;
-
-       if (!src)
-               return -EINVAL;
-
-       rbsp_init(&rbsp, src, n, &read);
-
-       nal_h264_read_start_code_prefix(&rbsp);
-
-       rbsp_bit(&rbsp, &forbidden_zero_bit);
-       rbsp_bits(&rbsp, 2, &nal_ref_idc);
-       rbsp_bits(&rbsp, 5, &nal_unit_type);
-
-       if (rbsp.error ||
-           forbidden_zero_bit != 0 ||
-           nal_ref_idc != 0 ||
-           nal_unit_type != SEQUENCE_PARAMETER_SET)
-               return -EINVAL;
-
-       nal_h264_rbsp_sps(&rbsp, sps);
-
-       nal_h264_rbsp_trailing_bits(&rbsp);
-
-       if (rbsp.error)
-               return rbsp.error;
-
-       return DIV_ROUND_UP(rbsp.pos, 8);
-}
-EXPORT_SYMBOL_GPL(nal_h264_read_sps);
-
-/**
- * nal_h264_write_pps() - Write PPS NAL unit into RBSP format
- * @dev: device pointer
- * @dest: the buffer that is filled with RBSP data
- * @n: maximum size of @dest in bytes
- * @pps: &struct nal_h264_pps to convert to RBSP
- *
- * Convert @pps to RBSP data and write it into @dest.
- *
- * The size of the PPS NAL unit is not known in advance and this function will
- * fail, if @dest does not hold sufficient space for the PPS NAL unit.
- *
- * Return: number of bytes written to @dest or negative error code
- */
-ssize_t nal_h264_write_pps(const struct device *dev,
-                          void *dest, size_t n, struct nal_h264_pps *pps)
-{
-       struct rbsp rbsp;
-       unsigned int forbidden_zero_bit = 0;
-       unsigned int nal_ref_idc = 0;
-       unsigned int nal_unit_type = PICTURE_PARAMETER_SET;
-
-       if (!dest)
-               return -EINVAL;
-
-       rbsp_init(&rbsp, dest, n, &write);
-
-       nal_h264_write_start_code_prefix(&rbsp);
-
-       /* NAL unit header */
-       rbsp_bit(&rbsp, &forbidden_zero_bit);
-       rbsp_bits(&rbsp, 2, &nal_ref_idc);
-       rbsp_bits(&rbsp, 5, &nal_unit_type);
-
-       nal_h264_rbsp_pps(&rbsp, pps);
-
-       nal_h264_rbsp_trailing_bits(&rbsp);
-
-       if (rbsp.error)
-               return rbsp.error;
-
-       return DIV_ROUND_UP(rbsp.pos, 8);
-}
-EXPORT_SYMBOL_GPL(nal_h264_write_pps);
-
-/**
- * nal_h264_read_pps() - Read PPS NAL unit from RBSP format
- * @dev: device pointer
- * @pps: the &struct nal_h264_pps to fill from the RBSP data
- * @src: the buffer that contains the RBSP data
- * @n: size of @src in bytes
- *
- * Read RBSP data from @src and use it to fill @pps.
- *
- * Return: number of bytes read from @src or negative error code
- */
-ssize_t nal_h264_read_pps(const struct device *dev,
-                         struct nal_h264_pps *pps, void *src, size_t n)
-{
-       struct rbsp rbsp;
-
-       if (!src)
-               return -EINVAL;
-
-       rbsp_init(&rbsp, src, n, &read);
-
-       nal_h264_read_start_code_prefix(&rbsp);
-
-       /* NAL unit header */
-       rbsp.pos += 8;
-
-       nal_h264_rbsp_pps(&rbsp, pps);
-
-       nal_h264_rbsp_trailing_bits(&rbsp);
-
-       if (rbsp.error)
-               return rbsp.error;
-
-       return DIV_ROUND_UP(rbsp.pos, 8);
-}
-EXPORT_SYMBOL_GPL(nal_h264_read_pps);
-
-/**
- * nal_h264_write_filler() - Write filler data RBSP
- * @dev: device pointer
- * @dest: buffer to fill with filler data
- * @n: size of the buffer to fill with filler data
- *
- * Write a filler data RBSP to @dest with a size of @n bytes and return the
- * number of written filler data bytes.
- *
- * Use this function to generate dummy data in an RBSP data stream that can be
- * safely ignored by h264 decoders.
- *
- * The RBSP format of the filler data is specified in Rec. ITU-T H.264
- * (04/2017) 7.3.2.7 Filler data RBSP syntax.
- *
- * Return: number of filler data bytes (including marker) or negative error
- */
-ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n)
-{
-       struct rbsp rbsp;
-       unsigned int forbidden_zero_bit = 0;
-       unsigned int nal_ref_idc = 0;
-       unsigned int nal_unit_type = FILLER_DATA;
-
-       if (!dest)
-               return -EINVAL;
-
-       rbsp_init(&rbsp, dest, n, &write);
-
-       nal_h264_write_start_code_prefix(&rbsp);
-
-       rbsp_bit(&rbsp, &forbidden_zero_bit);
-       rbsp_bits(&rbsp, 2, &nal_ref_idc);
-       rbsp_bits(&rbsp, 5, &nal_unit_type);
-
-       nal_h264_write_filler_data(&rbsp);
-
-       nal_h264_rbsp_trailing_bits(&rbsp);
-
-       return DIV_ROUND_UP(rbsp.pos, 8);
-}
-EXPORT_SYMBOL_GPL(nal_h264_write_filler);
-
-/**
- * nal_h264_read_filler() - Read filler data RBSP
- * @dev: device pointer
- * @src: buffer with RBSP data that is read
- * @n: maximum size of src that shall be read
- *
- * Read a filler data RBSP from @src up to a maximum size of @n bytes and
- * return the size of the filler data in bytes including the marker.
- *
- * This function is used to parse filler data and skip the respective bytes in
- * the RBSP data.
- *
- * The RBSP format of the filler data is specified in Rec. ITU-T H.264
- * (04/2017) 7.3.2.7 Filler data RBSP syntax.
- *
- * Return: number of filler data bytes (including marker) or negative error
- */
-ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n)
-{
-       struct rbsp rbsp;
-       unsigned int forbidden_zero_bit;
-       unsigned int nal_ref_idc;
-       unsigned int nal_unit_type;
-
-       if (!src)
-               return -EINVAL;
-
-       rbsp_init(&rbsp, src, n, &read);
-
-       nal_h264_read_start_code_prefix(&rbsp);
-
-       rbsp_bit(&rbsp, &forbidden_zero_bit);
-       rbsp_bits(&rbsp, 2, &nal_ref_idc);
-       rbsp_bits(&rbsp, 5, &nal_unit_type);
-
-       if (rbsp.error)
-               return rbsp.error;
-       if (forbidden_zero_bit != 0 ||
-           nal_ref_idc != 0 ||
-           nal_unit_type != FILLER_DATA)
-               return -EINVAL;
-
-       nal_h264_read_filler_data(&rbsp);
-       nal_h264_rbsp_trailing_bits(&rbsp);
-
-       if (rbsp.error)
-               return rbsp.error;
-
-       return DIV_ROUND_UP(rbsp.pos, 8);
-}
-EXPORT_SYMBOL_GPL(nal_h264_read_filler);
diff --git a/drivers/staging/media/allegro-dvt/nal-h264.h b/drivers/staging/media/allegro-dvt/nal-h264.h
deleted file mode 100644 (file)
index 2ba7cbc..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
- *
- * Convert NAL units between raw byte sequence payloads (RBSP) and C structs.
- */
-
-#ifndef __NAL_H264_H__
-#define __NAL_H264_H__
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-
-/**
- * struct nal_h264_hdr_parameters - HDR parameters
- *
- * C struct representation of the sequence parameter set NAL unit as defined by
- * Rec. ITU-T H.264 (04/2017) E.1.2 HRD parameters syntax.
- */
-struct nal_h264_hrd_parameters {
-       unsigned int cpb_cnt_minus1;
-       unsigned int bit_rate_scale;
-       unsigned int cpb_size_scale;
-       struct {
-               int bit_rate_value_minus1[16];
-               int cpb_size_value_minus1[16];
-               unsigned int cbr_flag[16];
-       };
-       unsigned int initial_cpb_removal_delay_length_minus1;
-       unsigned int cpb_removal_delay_length_minus1;
-       unsigned int dpb_output_delay_length_minus1;
-       unsigned int time_offset_length;
-};
-
-/**
- * struct nal_h264_vui_parameters - VUI parameters
- *
- * C struct representation of the VUI parameters as defined by Rec. ITU-T
- * H.264 (04/2017) E.1.1 VUI parameters syntax.
- */
-struct nal_h264_vui_parameters {
-       unsigned int aspect_ratio_info_present_flag;
-       struct {
-               unsigned int aspect_ratio_idc;
-               unsigned int sar_width;
-               unsigned int sar_height;
-       };
-       unsigned int overscan_info_present_flag;
-       unsigned int overscan_appropriate_flag;
-       unsigned int video_signal_type_present_flag;
-       struct {
-               unsigned int video_format;
-               unsigned int video_full_range_flag;
-               unsigned int colour_description_present_flag;
-               struct {
-                       unsigned int colour_primaries;
-                       unsigned int transfer_characteristics;
-                       unsigned int matrix_coefficients;
-               };
-       };
-       unsigned int chroma_loc_info_present_flag;
-       struct {
-               unsigned int chroma_sample_loc_type_top_field;
-               unsigned int chroma_sample_loc_type_bottom_field;
-       };
-       unsigned int timing_info_present_flag;
-       struct {
-               unsigned int num_units_in_tick;
-               unsigned int time_scale;
-               unsigned int fixed_frame_rate_flag;
-       };
-       unsigned int nal_hrd_parameters_present_flag;
-       struct nal_h264_hrd_parameters nal_hrd_parameters;
-       unsigned int vcl_hrd_parameters_present_flag;
-       struct nal_h264_hrd_parameters vcl_hrd_parameters;
-       unsigned int low_delay_hrd_flag;
-       unsigned int pic_struct_present_flag;
-       unsigned int bitstream_restriction_flag;
-       struct {
-               unsigned int motion_vectors_over_pic_boundaries_flag;
-               unsigned int max_bytes_per_pic_denom;
-               unsigned int max_bits_per_mb_denom;
-               unsigned int log2_max_mv_length_horizontal;
-               unsigned int log21_max_mv_length_vertical;
-               unsigned int max_num_reorder_frames;
-               unsigned int max_dec_frame_buffering;
-       };
-};
-
-/**
- * struct nal_h264_sps - Sequence parameter set
- *
- * C struct representation of the sequence parameter set NAL unit as defined by
- * Rec. ITU-T H.264 (04/2017) 7.3.2.1.1 Sequence parameter set data syntax.
- */
-struct nal_h264_sps {
-       unsigned int profile_idc;
-       unsigned int constraint_set0_flag;
-       unsigned int constraint_set1_flag;
-       unsigned int constraint_set2_flag;
-       unsigned int constraint_set3_flag;
-       unsigned int constraint_set4_flag;
-       unsigned int constraint_set5_flag;
-       unsigned int reserved_zero_2bits;
-       unsigned int level_idc;
-       unsigned int seq_parameter_set_id;
-       struct {
-               unsigned int chroma_format_idc;
-               unsigned int separate_colour_plane_flag;
-               unsigned int bit_depth_luma_minus8;
-               unsigned int bit_depth_chroma_minus8;
-               unsigned int qpprime_y_zero_transform_bypass_flag;
-               unsigned int seq_scaling_matrix_present_flag;
-       };
-       unsigned int log2_max_frame_num_minus4;
-       unsigned int pic_order_cnt_type;
-       union {
-               unsigned int log2_max_pic_order_cnt_lsb_minus4;
-               struct {
-                       unsigned int delta_pic_order_always_zero_flag;
-                       int offset_for_non_ref_pic;
-                       int offset_for_top_to_bottom_field;
-                       unsigned int num_ref_frames_in_pic_order_cnt_cycle;
-                       int offset_for_ref_frame[255];
-               };
-       };
-       unsigned int max_num_ref_frames;
-       unsigned int gaps_in_frame_num_value_allowed_flag;
-       unsigned int pic_width_in_mbs_minus1;
-       unsigned int pic_height_in_map_units_minus1;
-       unsigned int frame_mbs_only_flag;
-       unsigned int mb_adaptive_frame_field_flag;
-       unsigned int direct_8x8_inference_flag;
-       unsigned int frame_cropping_flag;
-       struct {
-               unsigned int crop_left;
-               unsigned int crop_right;
-               unsigned int crop_top;
-               unsigned int crop_bottom;
-       };
-       unsigned int vui_parameters_present_flag;
-       struct nal_h264_vui_parameters vui;
-};
-
-/**
- * struct nal_h264_pps - Picture parameter set
- *
- * C struct representation of the picture parameter set NAL unit as defined by
- * Rec. ITU-T H.264 (04/2017) 7.3.2.2 Picture parameter set RBSP syntax.
- */
-struct nal_h264_pps {
-       unsigned int pic_parameter_set_id;
-       unsigned int seq_parameter_set_id;
-       unsigned int entropy_coding_mode_flag;
-       unsigned int bottom_field_pic_order_in_frame_present_flag;
-       unsigned int num_slice_groups_minus1;
-       unsigned int slice_group_map_type;
-       union {
-               unsigned int run_length_minus1[8];
-               struct {
-                       unsigned int top_left[8];
-                       unsigned int bottom_right[8];
-               };
-               struct {
-                       unsigned int slice_group_change_direction_flag;
-                       unsigned int slice_group_change_rate_minus1;
-               };
-               struct {
-                       unsigned int pic_size_in_map_units_minus1;
-                       unsigned int slice_group_id[8];
-               };
-       };
-       unsigned int num_ref_idx_l0_default_active_minus1;
-       unsigned int num_ref_idx_l1_default_active_minus1;
-       unsigned int weighted_pred_flag;
-       unsigned int weighted_bipred_idc;
-       int pic_init_qp_minus26;
-       int pic_init_qs_minus26;
-       int chroma_qp_index_offset;
-       unsigned int deblocking_filter_control_present_flag;
-       unsigned int constrained_intra_pred_flag;
-       unsigned int redundant_pic_cnt_present_flag;
-       struct {
-               unsigned int transform_8x8_mode_flag;
-               unsigned int pic_scaling_matrix_present_flag;
-               int second_chroma_qp_index_offset;
-       };
-};
-
-int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile);
-int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level);
-
-ssize_t nal_h264_write_sps(const struct device *dev,
-                          void *dest, size_t n, struct nal_h264_sps *sps);
-ssize_t nal_h264_read_sps(const struct device *dev,
-                         struct nal_h264_sps *sps, void *src, size_t n);
-void nal_h264_print_sps(const struct device *dev, struct nal_h264_sps *sps);
-
-ssize_t nal_h264_write_pps(const struct device *dev,
-                          void *dest, size_t n, struct nal_h264_pps *pps);
-ssize_t nal_h264_read_pps(const struct device *dev,
-                         struct nal_h264_pps *pps, void *src, size_t n);
-void nal_h264_print_pps(const struct device *dev, struct nal_h264_pps *pps);
-
-ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n);
-ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n);
-
-#endif /* __NAL_H264_H__ */