summaryrefslogtreecommitdiff
path: root/drivers/staging
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-02-21 14:10:36 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2021-02-21 14:10:36 -0800
commitde1617578849acab8e16c9ffdce39b91fb50639d (patch)
tree913a330d92a5ce327a48531f58c78b0d72a109a7 /drivers/staging
parent66f73fb3facd42d0a7c899d7f4c712332b28499a (diff)
parent8f202f8e9ff38e29694a4bc0a519b4e03c1726ee (diff)
Merge tag 'media/v5.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab: - some core fixes in VB2 mem2mem support - some improvements and cleanups in V4L2 async kAPI - newer controls in V4L2 API for H-264 and HEVC codecs - allegro-dvt driver was promoted from staging - new i2c sendor drivers: imx334, ov5648, ov8865 - new automobile camera module: rdacm21 - ipu3 cio2 driver started gained support for some ACPI BIOSes - new ATSC frontend: MaxLinear mxl692 VSB tuner/demod - the SMIA/CCS driver gained more support for CSS standard - several driver fixes, updates and improvements * tag 'media/v5.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (362 commits) media: v4l: async: Fix kerneldoc documentation for async functions media: i2c: max9271: Add MODULE_* macros media: i2c: Kconfig: Make MAX9271 a module media: imx334: 'ret' is uninitialized, should have been PTR_ERR() media: i2c: Add imx334 camera sensor driver media: dt-bindings: media: Add bindings for imx334 media: ov8856: Configure sensor for GRBG Bayer for all modes media: i2c: imx219: Implement V4L2_CID_LINK_FREQ control media: ov5675: fix vflip/hflip control media: ipu3-cio2: Build bridge only if ACPI is enabled media: Remove the legacy v4l2-clk API media: ov6650: Use the generic clock framework media: mt9m111: Use the generic clock framework media: ov9640: Use the generic clock framework media: pxa_camera: Drop the v4l2-clk clock register media: mach-pxa: Register the camera sensor fixed-rate clock media: i2c: imx258: get clock from device properties and enable it via runtime PM media: i2c: imx258: simplify getting state container media: i2c: imx258: add support for binding via device tree media: dt-bindings: media: imx258: add bindings for IMX258 sensor ...
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/allegro-dvt/Kconfig16
-rw-r--r--drivers/staging/media/allegro-dvt/Makefile5
-rw-r--r--drivers/staging/media/allegro-dvt/TODO4
-rw-r--r--drivers/staging/media/allegro-dvt/allegro-core.c3227
-rw-r--r--drivers/staging/media/allegro-dvt/allegro-mail.c543
-rw-r--r--drivers/staging/media/allegro-dvt/allegro-mail.h294
-rw-r--r--drivers/staging/media/allegro-dvt/nal-h264.c1001
-rw-r--r--drivers/staging/media/allegro-dvt/nal-h264.h208
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.c24
-rw-r--r--drivers/staging/media/atomisp/pci/ia_css_firmware.h1
-rw-r--r--drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c1
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_params.c6
-rw-r--r--drivers/staging/media/hantro/hantro_v4l2.c2
-rw-r--r--drivers/staging/media/imx/Kconfig9
-rw-r--r--drivers/staging/media/imx/Makefile2
-rw-r--r--drivers/staging/media/imx/imx-media-capture.c10
-rw-r--r--drivers/staging/media/imx/imx-media-csc-scaler.c4
-rw-r--r--drivers/staging/media/imx/imx-media-csi.c14
-rw-r--r--drivers/staging/media/imx/imx-media-dev.c7
-rw-r--r--drivers/staging/media/imx/imx-media-of.c2
-rw-r--r--drivers/staging/media/imx/imx6-mipi-csi2.c127
-rw-r--r--drivers/staging/media/imx/imx7-media-csi.c43
-rw-r--r--drivers/staging/media/imx/imx7-mipi-csis.c15
-rw-r--r--drivers/staging/media/ipu3/ipu3-v4l2.c3
-rw-r--r--drivers/staging/media/omap4iss/iss.c1
-rw-r--r--drivers/staging/media/omap4iss/iss_video.h1
-rw-r--r--drivers/staging/media/rkvdec/rkvdec.c2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.c49
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.h1
-rw-r--r--drivers/staging/media/tegra-video/csi.c35
-rw-r--r--drivers/staging/media/tegra-video/csi.h14
-rw-r--r--drivers/staging/media/tegra-video/tegra210.c340
-rw-r--r--drivers/staging/media/tegra-video/vi.c348
-rw-r--r--drivers/staging/media/tegra-video/vi.h23
-rw-r--r--drivers/staging/media/tegra-video/video.c18
-rw-r--r--drivers/staging/media/zoran/zoran_driver.c2
38 files changed, 790 insertions, 5615 deletions
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index e8996b1c3b35..ca59986b20f8 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -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"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 24b5873ff760..716929a1a313 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -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
index 6b7107d9995c..000000000000
--- a/drivers/staging/media/allegro-dvt/Kconfig
+++ /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
index 8e306dcdc55c..000000000000
--- a/drivers/staging/media/allegro-dvt/Makefile
+++ /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
index 99e19be0e45a..000000000000
--- a/drivers/staging/media/allegro-dvt/TODO
+++ /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
index 9f718f43282b..000000000000
--- a/drivers/staging/media/allegro-dvt/allegro-core.c
+++ /dev/null
@@ -1,3227 +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);
-
- list_add(&channel->list, &dev->channels);
-
- 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;
- }
-
- 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
index 9286d2162377..000000000000
--- a/drivers/staging/media/allegro-dvt/allegro-mail.c
+++ /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
index 486ecb12b098..000000000000
--- a/drivers/staging/media/allegro-dvt/allegro-mail.h
+++ /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
index bd48b8883572..000000000000
--- a/drivers/staging/media/allegro-dvt/nal-h264.c
+++ /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
index 2ba7cbced7a5..000000000000
--- a/drivers/staging/media/allegro-dvt/nal-h264.h
+++ /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__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
index b666cb23e5ca..2ef5f44e4b6b 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
@@ -349,12 +349,20 @@ static int isp_subdev_get_selection(struct v4l2_subdev *sd,
return 0;
}
-static char *atomisp_pad_str[] = { "ATOMISP_SUBDEV_PAD_SINK",
- "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE",
- "ATOMISP_SUBDEV_PAD_SOURCE_VF",
- "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW",
- "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO"
- };
+static const char *atomisp_pad_str(unsigned int pad)
+{
+ static const char *const pad_str[] = {
+ "ATOMISP_SUBDEV_PAD_SINK",
+ "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE",
+ "ATOMISP_SUBDEV_PAD_SOURCE_VF",
+ "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW",
+ "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO",
+ };
+
+ if (pad >= ARRAY_SIZE(pad_str))
+ return "ATOMISP_INVALID_PAD";
+ return pad_str[pad];
+}
int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
@@ -378,7 +386,7 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
dev_dbg(isp->dev,
"sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n",
- atomisp_pad_str[pad], target == V4L2_SEL_TGT_CROP
+ atomisp_pad_str(pad), target == V4L2_SEL_TGT_CROP
? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE",
r->left, r->top, r->width, r->height,
which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
@@ -612,7 +620,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
enum atomisp_input_stream_id stream_id;
dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n",
- atomisp_pad_str[pad], ffmt->width, ffmt->height, ffmt->code,
+ atomisp_pad_str(pad), ffmt->width, ffmt->height, ffmt->code,
which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
: "V4L2_SUBDEV_FORMAT_ACTIVE");
diff --git a/drivers/staging/media/atomisp/pci/ia_css_firmware.h b/drivers/staging/media/atomisp/pci/ia_css_firmware.h
index edab72256494..e5e2f6fb37e0 100644
--- a/drivers/staging/media/atomisp/pci/ia_css_firmware.h
+++ b/drivers/staging/media/atomisp/pci/ia_css_firmware.h
@@ -20,6 +20,7 @@
* This file contains firmware loading/unloading support functionality
*/
+#include <linux/device.h>
#include "ia_css_err.h"
#include "ia_css_env.h"
diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c
index b4813cd50daa..4a18da6bf0c1 100644
--- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c
+++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c
@@ -368,6 +368,7 @@ static mipi_predictor_t sh_css_csi2_compression_type_2_mipi_predictor(
break;
case IA_CSS_CSI2_COMPRESSION_TYPE_2:
predictor = MIPI_PREDICTOR_TYPE2 - 1;
+ break;
default:
break;
}
diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c
index 24fc497bd491..9fad28b97201 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_params.c
+++ b/drivers/staging/media/atomisp/pci/sh_css_params.c
@@ -949,7 +949,7 @@ sh_css_set_black_frame(struct ia_css_stream *stream,
params = stream->isp_params_configs;
height = raw_black_frame->info.res.height;
- width = raw_black_frame->info.padded_width,
+ width = raw_black_frame->info.padded_width;
ptr = raw_black_frame->data
+ raw_black_frame->planes.raw.offset;
@@ -1442,8 +1442,8 @@ static int sh_css_params_default_morph_table(
IA_CSS_ENTER_PRIVATE("");
- step = (ISP_VEC_NELEMS / 16) * 128,
- width = binary->morph_tbl_width,
+ step = (ISP_VEC_NELEMS / 16) * 128;
+ width = binary->morph_tbl_width;
height = binary->morph_tbl_height;
tab = ia_css_morph_table_allocate(width, height);
diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c
index f5fbdbc4ffdb..1bc118e375a1 100644
--- a/drivers/staging/media/hantro/hantro_v4l2.c
+++ b/drivers/staging/media/hantro/hantro_v4l2.c
@@ -316,7 +316,7 @@ hantro_reset_fmt(struct v4l2_pix_format_mplane *fmt,
fmt->pixelformat = vpu_fmt->fourcc;
fmt->field = V4L2_FIELD_NONE;
- fmt->colorspace = V4L2_COLORSPACE_JPEG,
+ fmt->colorspace = V4L2_COLORSPACE_JPEG;
fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig
index f555aac8a9d5..15322dc3124a 100644
--- a/drivers/staging/media/imx/Kconfig
+++ b/drivers/staging/media/imx/Kconfig
@@ -2,7 +2,7 @@
config VIDEO_IMX_MEDIA
tristate "i.MX5/6 V4L2 media core driver"
depends on ARCH_MXC || COMPILE_TEST
- depends on VIDEO_V4L2 && IMX_IPUV3_CORE
+ depends on VIDEO_V4L2
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
depends on HAS_DMA
@@ -14,21 +14,22 @@ config VIDEO_IMX_MEDIA
driver for the i.MX5/6 SOC.
if VIDEO_IMX_MEDIA
-menu "i.MX5/6/7 Media Sub devices"
+menu "i.MX5/6/7/8 Media Sub devices"
config VIDEO_IMX_CSI
tristate "i.MX5/6 Camera Sensor Interface driver"
depends on VIDEO_IMX_MEDIA && VIDEO_DEV && I2C
+ depends on IMX_IPUV3_CORE
default y
help
A video4linux camera sensor interface driver for i.MX5/6.
config VIDEO_IMX7_CSI
- tristate "i.MX6UL/L / i.MX7 Camera Sensor Interface driver"
+ tristate "i.MX6UL/L / i.MX7 / i.MX8M Camera Sensor Interface driver"
depends on VIDEO_IMX_MEDIA && VIDEO_DEV && I2C
default y
help
Enable support for video4linux camera sensor interface driver for
- i.MX6UL/L or i.MX7.
+ i.MX6UL/L, i.MX7 or i.MX8M.
endmenu
endif
diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index 9bd9e873ba7c..69cc5da04a2e 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -8,9 +8,9 @@ imx-media-common-objs := imx-media-capture.o imx-media-dev-common.o \
imx6-media-csi-objs := imx-media-csi.o imx-media-fim.o
-obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx6-media.o
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-common.o
+obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-media.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-media-csi.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o
diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c
index c1931eb2540e..e10ce103a5b4 100644
--- a/drivers/staging/media/imx/imx-media-capture.c
+++ b/drivers/staging/media/imx/imx-media-capture.c
@@ -816,14 +816,8 @@ void imx_media_capture_device_unregister(struct imx_media_video_dev *vdev)
struct capture_priv *priv = to_capture_priv(vdev);
struct video_device *vfd = priv->vdev.vfd;
- mutex_lock(&priv->mutex);
-
- if (video_is_registered(vfd)) {
- video_unregister_device(vfd);
- media_entity_cleanup(&vfd->entity);
- }
-
- mutex_unlock(&priv->mutex);
+ media_entity_cleanup(&vfd->entity);
+ video_unregister_device(vfd);
}
EXPORT_SYMBOL_GPL(imx_media_capture_device_unregister);
diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c
index fab1155a5958..63a0204502a8 100644
--- a/drivers/staging/media/imx/imx-media-csc-scaler.c
+++ b/drivers/staging/media/imx/imx-media-csc-scaler.c
@@ -869,11 +869,7 @@ void imx_media_csc_scaler_device_unregister(struct imx_media_video_dev *vdev)
struct ipu_csc_scaler_priv *priv = vdev_to_priv(vdev);
struct video_device *vfd = priv->vdev.vfd;
- mutex_lock(&priv->mutex);
-
video_unregister_device(vfd);
-
- mutex_unlock(&priv->mutex);
}
struct imx_media_video_dev *
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index db77fef07654..ef5add079774 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -1922,19 +1922,13 @@ static int imx_csi_async_register(struct csi_priv *priv)
port, 0,
FWNODE_GRAPH_ENDPOINT_NEXT);
if (ep) {
- asd = kzalloc(sizeof(*asd), GFP_KERNEL);
- if (!asd) {
- fwnode_handle_put(ep);
- return -ENOMEM;
- }
-
- ret = v4l2_async_notifier_add_fwnode_remote_subdev(
- &priv->notifier, ep, asd);
+ asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+ &priv->notifier, ep, struct v4l2_async_subdev);
fwnode_handle_put(ep);
- if (ret) {
- kfree(asd);
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
/* OK if asd already exists */
if (ret != -EEXIST)
return ret;
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index 6d2205461e56..338b8bd0bb07 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -53,6 +53,7 @@ static int imx6_media_probe_complete(struct v4l2_async_notifier *notifier)
imxmd->m2m_vdev = imx_media_csc_scaler_device_init(imxmd);
if (IS_ERR(imxmd->m2m_vdev)) {
ret = PTR_ERR(imxmd->m2m_vdev);
+ imxmd->m2m_vdev = NULL;
goto unlock;
}
@@ -107,10 +108,14 @@ static int imx_media_remove(struct platform_device *pdev)
v4l2_info(&imxmd->v4l2_dev, "Removing imx-media\n");
+ if (imxmd->m2m_vdev) {
+ imx_media_csc_scaler_device_unregister(imxmd->m2m_vdev);
+ imxmd->m2m_vdev = NULL;
+ }
+
v4l2_async_notifier_unregister(&imxmd->notifier);
imx_media_unregister_ipu_internal_subdevs(imxmd);
v4l2_async_notifier_cleanup(&imxmd->notifier);
- imx_media_csc_scaler_device_unregister(imxmd->m2m_vdev);
media_device_unregister(&imxmd->md);
v4l2_device_unregister(&imxmd->v4l2_dev);
media_device_cleanup(&imxmd->md);
diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c
index 82e13e972e23..b677cf0e0c84 100644
--- a/drivers/staging/media/imx/imx-media-of.c
+++ b/drivers/staging/media/imx/imx-media-of.c
@@ -31,7 +31,7 @@ int imx_media_of_add_csi(struct imx_media_dev *imxmd,
/* add CSI fwnode to async notifier */
asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier,
of_fwnode_handle(csi_np),
- sizeof(*asd));
+ struct v4l2_async_subdev);
if (IS_ERR(asd)) {
ret = PTR_ERR(asd);
if (ret == -EEXIST)
diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c
index 94d87d27d389..4f8fcc91aaae 100644
--- a/drivers/staging/media/imx/imx6-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx6-mipi-csi2.c
@@ -42,7 +42,10 @@ struct csi2_dev {
struct clk *pllref_clk;
struct clk *pix_clk; /* what is this? */
void __iomem *base;
- struct v4l2_fwnode_bus_mipi_csi2 bus;
+
+ struct v4l2_subdev *remote;
+ unsigned int remote_pad;
+ unsigned short data_lanes;
/* lock to protect all members below */
struct mutex lock;
@@ -138,10 +141,8 @@ static void csi2_enable(struct csi2_dev *csi2, bool enable)
}
}
-static void csi2_set_lanes(struct csi2_dev *csi2)
+static void csi2_set_lanes(struct csi2_dev *csi2, unsigned int lanes)
{
- int lanes = csi2->bus.num_data_lanes;
-
writel(lanes - 1, csi2->base + CSI2_N_LANES);
}
@@ -250,13 +251,12 @@ static int __maybe_unused csi2_dphy_wait_ulp(struct csi2_dev *csi2)
}
/* Waits for low-power LP-11 state on data and clock lanes. */
-static void csi2_dphy_wait_stopstate(struct csi2_dev *csi2)
+static void csi2_dphy_wait_stopstate(struct csi2_dev *csi2, unsigned int lanes)
{
u32 mask, reg;
int ret;
- mask = PHY_STOPSTATECLK | (((1 << csi2->bus.num_data_lanes) - 1) <<
- PHY_STOPSTATEDATA_BIT);
+ mask = PHY_STOPSTATECLK | (((1 << lanes) - 1) << PHY_STOPSTATEDATA_BIT);
ret = readl_poll_timeout(csi2->base + CSI2_PHY_STATE, reg,
(reg & mask) == mask, 0, 500000);
@@ -300,8 +300,65 @@ static void csi2ipu_gasket_init(struct csi2_dev *csi2)
writel(reg, csi2->base + CSI2IPU_GASKET);
}
+static int csi2_get_active_lanes(struct csi2_dev *csi2, unsigned int *lanes)
+{
+ struct v4l2_mbus_config mbus_config = { 0 };
+ unsigned int num_lanes = UINT_MAX;
+ int ret;
+
+ *lanes = csi2->data_lanes;
+
+ ret = v4l2_subdev_call(csi2->remote, pad, get_mbus_config,
+ csi2->remote_pad, &mbus_config);
+ if (ret == -ENOIOCTLCMD) {
+ dev_dbg(csi2->dev, "No remote mbus configuration available\n");
+ return 0;
+ }
+
+ if (ret) {
+ dev_err(csi2->dev, "Failed to get remote mbus configuration\n");
+ return ret;
+ }
+
+ if (mbus_config.type != V4L2_MBUS_CSI2_DPHY) {
+ dev_err(csi2->dev, "Unsupported media bus type %u\n",
+ mbus_config.type);
+ return -EINVAL;
+ }
+
+ switch (mbus_config.flags & V4L2_MBUS_CSI2_LANES) {
+ case V4L2_MBUS_CSI2_1_LANE:
+ num_lanes = 1;
+ break;
+ case V4L2_MBUS_CSI2_2_LANE:
+ num_lanes = 2;
+ break;
+ case V4L2_MBUS_CSI2_3_LANE:
+ num_lanes = 3;
+ break;
+ case V4L2_MBUS_CSI2_4_LANE:
+ num_lanes = 4;
+ break;
+ default:
+ num_lanes = csi2->data_lanes;
+ break;
+ }
+
+ if (num_lanes > csi2->data_lanes) {
+ dev_err(csi2->dev,
+ "Unsupported mbus config: too many data lanes %u\n",
+ num_lanes);
+ return -EINVAL;
+ }
+
+ *lanes = num_lanes;
+
+ return 0;
+}
+
static int csi2_start(struct csi2_dev *csi2)
{
+ unsigned int lanes;
int ret;
ret = clk_prepare_enable(csi2->pix_clk);
@@ -316,12 +373,16 @@ static int csi2_start(struct csi2_dev *csi2)
if (ret)
goto err_disable_clk;
+ ret = csi2_get_active_lanes(csi2, &lanes);
+ if (ret)
+ goto err_disable_clk;
+
/* Step 4 */
- csi2_set_lanes(csi2);
+ csi2_set_lanes(csi2, lanes);
csi2_enable(csi2, true);
/* Step 5 */
- csi2_dphy_wait_stopstate(csi2);
+ csi2_dphy_wait_stopstate(csi2, lanes);
/* Step 6 */
ret = v4l2_subdev_call(csi2->src_sd, video, s_stream, 1);
@@ -544,12 +605,35 @@ static int csi2_notify_bound(struct v4l2_async_notifier *notifier,
{
struct csi2_dev *csi2 = notifier_to_dev(notifier);
struct media_pad *sink = &csi2->sd.entity.pads[CSI2_SINK_PAD];
+ int pad;
+
+ pad = media_entity_get_fwnode_pad(&sd->entity, asd->match.fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (pad < 0) {
+ dev_err(csi2->dev, "Failed to find pad for %s\n", sd->name);
+ return pad;
+ }
+
+ csi2->remote = sd;
+ csi2->remote_pad = pad;
+
+ dev_dbg(csi2->dev, "Bound %s pad: %d\n", sd->name, pad);
return v4l2_create_fwnode_links_to_pad(sd, sink);
}
+static void csi2_notify_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
+{
+ struct csi2_dev *csi2 = notifier_to_dev(notifier);
+
+ csi2->remote = NULL;
+}
+
static const struct v4l2_async_notifier_operations csi2_notify_ops = {
.bound = csi2_notify_bound,
+ .unbind = csi2_notify_unbind,
};
static int csi2_async_register(struct csi2_dev *csi2)
@@ -557,7 +641,7 @@ static int csi2_async_register(struct csi2_dev *csi2)
struct v4l2_fwnode_endpoint vep = {
.bus_type = V4L2_MBUS_CSI2_DPHY,
};
- struct v4l2_async_subdev *asd = NULL;
+ struct v4l2_async_subdev *asd;
struct fwnode_handle *ep;
int ret;
@@ -572,24 +656,18 @@ static int csi2_async_register(struct csi2_dev *csi2)
if (ret)
goto err_parse;
- csi2->bus = vep.bus.mipi_csi2;
-
- dev_dbg(csi2->dev, "data lanes: %d\n", csi2->bus.num_data_lanes);
- dev_dbg(csi2->dev, "flags: 0x%08x\n", csi2->bus.flags);
+ csi2->data_lanes = vep.bus.mipi_csi2.num_data_lanes;
- asd = kzalloc(sizeof(*asd), GFP_KERNEL);
- if (!asd) {
- ret = -ENOMEM;
- goto err_parse;
- }
-
- ret = v4l2_async_notifier_add_fwnode_remote_subdev(
- &csi2->notifier, ep, asd);
- if (ret)
- goto err_parse;
+ dev_dbg(csi2->dev, "data lanes: %d\n", vep.bus.mipi_csi2.num_data_lanes);
+ dev_dbg(csi2->dev, "flags: 0x%08x\n", vep.bus.mipi_csi2.flags);
+ asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+ &csi2->notifier, ep, struct v4l2_async_subdev);
fwnode_handle_put(ep);
+ if (IS_ERR(asd))
+ return PTR_ERR(asd);
+
csi2->notifier.ops = &csi2_notify_ops;
ret = v4l2_async_subdev_notifier_register(&csi2->sd,
@@ -601,7 +679,6 @@ static int csi2_async_register(struct csi2_dev *csi2)
err_parse:
fwnode_handle_put(ep);
- kfree(asd);
return ret;
}
diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c
index a3f3df901704..3046f880c014 100644
--- a/drivers/staging/media/imx/imx7-media-csi.c
+++ b/drivers/staging/media/imx/imx7-media-csi.c
@@ -499,6 +499,7 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sink_fmt)
{
struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ struct media_entity *src;
struct media_pad *pad;
int ret;
@@ -509,11 +510,21 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
if (!csi->src_sd)
return -EPIPE;
+ src = &csi->src_sd->entity;
+
/*
- * find the entity that is selected by the CSI mux. This is needed
+ * if the source is neither a CSI MUX or CSI-2 get the one directly
+ * upstream from this CSI
+ */
+ if (src->function != MEDIA_ENT_F_VID_IF_BRIDGE &&
+ src->function != MEDIA_ENT_F_VID_MUX)
+ src = &csi->sd.entity;
+
+ /*
+ * find the entity that is selected by the source. This is needed
* to distinguish between a parallel or CSI-2 pipeline.
*/
- pad = imx_media_pipeline_pad(&csi->src_sd->entity, 0, 0, true);
+ pad = imx_media_pipeline_pad(src, 0, 0, true);
if (!pad)
return -ENODEV;
@@ -1164,12 +1175,12 @@ static int imx7_csi_notify_bound(struct v4l2_async_notifier *notifier,
struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier);
struct media_pad *sink = &csi->sd.entity.pads[IMX7_CSI_PAD_SINK];
- /* The bound subdev must always be the CSI mux */
- if (WARN_ON(sd->entity.function != MEDIA_ENT_F_VID_MUX))
- return -ENXIO;
-
- /* Mark it as such via its group id */
- sd->grp_id = IMX_MEDIA_GRP_ID_CSI_MUX;
+ /*
+ * If the subdev is a video mux, it must be one of the CSI
+ * muxes. Mark it as such via its group id.
+ */
+ if (sd->entity.function == MEDIA_ENT_F_VID_MUX)
+ sd->grp_id = IMX_MEDIA_GRP_ID_CSI_MUX;
return v4l2_create_fwnode_links_to_pad(sd, sink);
}
@@ -1180,7 +1191,7 @@ static const struct v4l2_async_notifier_operations imx7_csi_notify_ops = {
static int imx7_csi_async_register(struct imx7_csi *csi)
{
- struct v4l2_async_subdev *asd = NULL;
+ struct v4l2_async_subdev *asd;
struct fwnode_handle *ep;
int ret;
@@ -1189,19 +1200,13 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
FWNODE_GRAPH_ENDPOINT_NEXT);
if (ep) {
- asd = kzalloc(sizeof(*asd), GFP_KERNEL);
- if (!asd) {
- fwnode_handle_put(ep);
- return -ENOMEM;
- }
-
- ret = v4l2_async_notifier_add_fwnode_remote_subdev(
- &csi->notifier, ep, asd);
+ asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+ &csi->notifier, ep, struct v4l2_async_subdev);
fwnode_handle_put(ep);
- if (ret) {
- kfree(asd);
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
/* OK if asd already exists */
if (ret != -EEXIST)
return ret;
diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c
index 7612993cc1d6..a01a7364b4b9 100644
--- a/drivers/staging/media/imx/imx7-mipi-csis.c
+++ b/drivers/staging/media/imx/imx7-mipi-csis.c
@@ -1004,7 +1004,7 @@ static int mipi_csis_async_register(struct csi_state *state)
struct v4l2_fwnode_endpoint vep = {
.bus_type = V4L2_MBUS_CSI2_DPHY,
};
- struct v4l2_async_subdev *asd = NULL;
+ struct v4l2_async_subdev *asd;
struct fwnode_handle *ep;
int ret;
@@ -1024,17 +1024,13 @@ static int mipi_csis_async_register(struct csi_state *state)
dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes);
dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags);
- asd = kzalloc(sizeof(*asd), GFP_KERNEL);
- if (!asd) {
- ret = -ENOMEM;
+ asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+ &state->notifier, ep, struct v4l2_async_subdev);
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
goto err_parse;
}
- ret = v4l2_async_notifier_add_fwnode_remote_subdev(
- &state->notifier, ep, asd);
- if (ret)
- goto err_parse;
-
fwnode_handle_put(ep);
state->notifier.ops = &mipi_csis_notify_ops;
@@ -1048,7 +1044,6 @@ static int mipi_csis_async_register(struct csi_state *state)
err_parse:
fwnode_handle_put(ep);
- kfree(asd);
return ret;
}
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
index 4dc8d9165f63..60aa02eb7d2a 100644
--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
@@ -773,9 +773,6 @@ static int imgu_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
pixm->pixelformat = fmt->fourcc;
- memset(pixm->plane_fmt[0].reserved, 0,
- sizeof(pixm->plane_fmt[0].reserved));
-
return 0;
}
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index e06ea7ea1e50..dae9073e7d3c 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -1349,4 +1349,3 @@ module_platform_driver(iss_driver);
MODULE_DESCRIPTION("TI OMAP4 ISS driver");
MODULE_AUTHOR("Sergio Aguirre <sergio.a.aguirre@gmail.com>");
MODULE_LICENSE("GPL");
-MODULE_VERSION(ISS_VIDEO_DRIVER_VERSION);
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index 8b3dd92021e1..526281bf0051 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -18,7 +18,6 @@
#include <media/videobuf2-dma-contig.h>
#define ISS_VIDEO_DRIVER_NAME "issvideo"
-#define ISS_VIDEO_DRIVER_VERSION "0.0.2"
struct iss_device;
struct iss_video;
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index aa4f8c287618..d3eb81ee8dc2 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -143,7 +143,7 @@ static void rkvdec_reset_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f,
memset(f, 0, sizeof(*f));
f->fmt.pix_mp.pixelformat = fourcc;
f->fmt.pix_mp.field = V4L2_FIELD_NONE;
- f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709,
+ f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index ddad5d274ee8..7bd9291c8d5f 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -34,56 +34,48 @@ static const struct cedrus_control cedrus_controls[] = {
.id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
},
.codec = CEDRUS_CODEC_MPEG2,
- .required = true,
},
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
},
.codec = CEDRUS_CODEC_MPEG2,
- .required = false,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
},
.codec = CEDRUS_CODEC_H264,
- .required = true,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_SLICE_PARAMS,
},
.codec = CEDRUS_CODEC_H264,
- .required = true,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_SPS,
},
.codec = CEDRUS_CODEC_H264,
- .required = true,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_PPS,
},
.codec = CEDRUS_CODEC_H264,
- .required = true,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX,
},
.codec = CEDRUS_CODEC_H264,
- .required = false,
},
{
.cfg = {
.id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS,
},
.codec = CEDRUS_CODEC_H264,
- .required = false,
},
{
.cfg = {
@@ -92,7 +84,6 @@ static const struct cedrus_control cedrus_controls[] = {
.def = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
},
.codec = CEDRUS_CODEC_H264,
- .required = false,
},
{
.cfg = {
@@ -101,7 +92,6 @@ static const struct cedrus_control cedrus_controls[] = {
.def = V4L2_STATELESS_H264_START_CODE_NONE,
},
.codec = CEDRUS_CODEC_H264,
- .required = false,
},
/*
* We only expose supported profiles information,
@@ -120,28 +110,24 @@ static const struct cedrus_control cedrus_controls[] = {
BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
},
.codec = CEDRUS_CODEC_H264,
- .required = false,
},
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_SPS,
},
.codec = CEDRUS_CODEC_H265,
- .required = true,
},
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_PPS,
},
.codec = CEDRUS_CODEC_H265,
- .required = true,
},
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS,
},
.codec = CEDRUS_CODEC_H265,
- .required = true,
},
{
.cfg = {
@@ -150,7 +136,6 @@ static const struct cedrus_control cedrus_controls[] = {
.def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
},
.codec = CEDRUS_CODEC_H265,
- .required = false,
},
{
.cfg = {
@@ -159,14 +144,12 @@ static const struct cedrus_control cedrus_controls[] = {
.def = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
},
.codec = CEDRUS_CODEC_H265,
- .required = false,
},
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER,
},
.codec = CEDRUS_CODEC_VP8,
- .required = true,
},
};
@@ -227,12 +210,8 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
static int cedrus_request_validate(struct media_request *req)
{
struct media_request_object *obj;
- struct v4l2_ctrl_handler *parent_hdl, *hdl;
struct cedrus_ctx *ctx = NULL;
- struct v4l2_ctrl *ctrl_test;
unsigned int count;
- unsigned int i;
- int ret = 0;
list_for_each_entry(obj, &req->objects, list) {
struct vb2_buffer *vb;
@@ -259,34 +238,6 @@ static int cedrus_request_validate(struct media_request *req)
return -EINVAL;
}
- parent_hdl = &ctx->hdl;
-
- hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl);
- if (!hdl) {
- v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control(s)\n");
- return -ENOENT;
- }
-
- for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
- if (cedrus_controls[i].codec != ctx->current_codec ||
- !cedrus_controls[i].required)
- continue;
-
- ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl,
- cedrus_controls[i].cfg.id);
- if (!ctrl_test) {
- v4l2_info(&ctx->dev->v4l2_dev,
- "Missing required codec control\n");
- ret = -ENOENT;
- break;
- }
- }
-
- v4l2_ctrl_request_hdl_put(hdl);
-
- if (ret)
- return ret;
-
return vb2_request_validate(req);
}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index c96077aaef49..251a6a660351 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -56,7 +56,6 @@ enum cedrus_h264_pic_type {
struct cedrus_control {
struct v4l2_ctrl_config cfg;
enum cedrus_codec codec;
- unsigned char required:1;
};
struct cedrus_h264_run {
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index a19c85c57fca..033a6935c26d 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -253,13 +253,14 @@ static unsigned int csi_get_pixel_rate(struct tegra_csi_channel *csi_chan)
}
void tegra_csi_calc_settle_time(struct tegra_csi_channel *csi_chan,
+ u8 csi_port_num,
u8 *clk_settle_time,
u8 *ths_settle_time)
{
struct tegra_csi *csi = csi_chan->csi;
unsigned int cil_clk_mhz;
unsigned int pix_clk_mhz;
- int clk_idx = (csi_chan->csi_port_num >> 1) + 1;
+ int clk_idx = (csi_port_num >> 1) + 1;
cil_clk_mhz = clk_get_rate(csi->clks[clk_idx].clk) / MHZ;
pix_clk_mhz = csi_get_pixel_rate(csi_chan) / MHZ;
@@ -410,7 +411,7 @@ static int tegra_csi_channel_alloc(struct tegra_csi *csi,
unsigned int num_pads)
{
struct tegra_csi_channel *chan;
- int ret = 0;
+ int ret = 0, i;
chan = kzalloc(sizeof(*chan), GFP_KERNEL);
if (!chan)
@@ -418,8 +419,21 @@ static int tegra_csi_channel_alloc(struct tegra_csi *csi,
list_add_tail(&chan->list, &csi->csi_chans);
chan->csi = csi;
- chan->csi_port_num = port_num;
- chan->numlanes = lanes;
+ /*
+ * Each CSI brick has maximum of 4 lanes.
+ * For lanes more than 4, use multiple of immediate CSI bricks as gang.
+ */
+ if (lanes <= CSI_LANES_PER_BRICK) {
+ chan->numlanes = lanes;
+ chan->numgangports = 1;
+ } else {
+ chan->numlanes = CSI_LANES_PER_BRICK;
+ chan->numgangports = lanes / CSI_LANES_PER_BRICK;
+ }
+
+ for (i = 0; i < chan->numgangports; i++)
+ chan->csi_port_nums[i] = port_num + i * CSI_PORTS_PER_BRICK;
+
chan->of_node = node;
chan->numpads = num_pads;
if (num_pads & 0x2) {
@@ -500,7 +514,14 @@ static int tegra_csi_channels_alloc(struct tegra_csi *csi)
}
lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
- if (!lanes || ((lanes & (lanes - 1)) != 0)) {
+ /*
+ * Each CSI brick has maximum 4 data lanes.
+ * For lanes more than 4, validate lanes to be multiple of 4
+ * so multiple of consecutive CSI bricks can be ganged up for
+ * streaming.
+ */
+ if (!lanes || ((lanes & (lanes - 1)) != 0) ||
+ (lanes > CSI_LANES_PER_BRICK && ((portno & 1) != 0))) {
dev_err(csi->dev, "invalid data-lanes %d for %pOF\n",
lanes, channel);
ret = -EINVAL;
@@ -544,7 +565,7 @@ static int tegra_csi_channel_init(struct tegra_csi_channel *chan)
subdev->dev = csi->dev;
if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "%s-%d", "tpg",
- chan->csi_port_num);
+ chan->csi_port_nums[0]);
else
snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "%s",
kbasename(chan->of_node->full_name));
@@ -596,7 +617,7 @@ static int tegra_csi_channels_init(struct tegra_csi *csi)
if (ret) {
dev_err(csi->dev,
"failed to initialize channel-%d: %d\n",
- chan->csi_port_num, ret);
+ chan->csi_port_nums[0], ret);
return ret;
}
}
diff --git a/drivers/staging/media/tegra-video/csi.h b/drivers/staging/media/tegra-video/csi.h
index c65ff73b1cdc..386f7c664259 100644
--- a/drivers/staging/media/tegra-video/csi.h
+++ b/drivers/staging/media/tegra-video/csi.h
@@ -17,6 +17,10 @@
* CILB.
*/
#define CSI_PORTS_PER_BRICK 2
+#define CSI_LANES_PER_BRICK 4
+
+/* Maximum 2 CSI x4 ports can be ganged up for streaming */
+#define GANG_PORTS_MAX 2
/* each CSI channel can have one sink and one source pads */
#define TEGRA_CSI_PADS_NUM 2
@@ -43,8 +47,10 @@ struct tegra_csi;
* @numpads: number of pads.
* @csi: Tegra CSI device structure
* @of_node: csi device tree node
- * @numlanes: number of lanes used per port/channel
- * @csi_port_num: CSI channel port number
+ * @numgangports: number of immediate ports ganged up to meet the
+ * channel bus-width
+ * @numlanes: number of lanes used per port
+ * @csi_port_nums: CSI channel port numbers
* @pg_mode: test pattern generator mode for channel
* @format: active format of the channel
* @framerate: active framerate for TPG
@@ -60,8 +66,9 @@ struct tegra_csi_channel {
unsigned int numpads;
struct tegra_csi *csi;
struct device_node *of_node;
+ u8 numgangports;
unsigned int numlanes;
- u8 csi_port_num;
+ u8 csi_port_nums[GANG_PORTS_MAX];
u8 pg_mode;
struct v4l2_mbus_framefmt format;
unsigned int framerate;
@@ -150,6 +157,7 @@ extern const struct tegra_csi_soc tegra210_csi_soc;
void tegra_csi_error_recover(struct v4l2_subdev *subdev);
void tegra_csi_calc_settle_time(struct tegra_csi_channel *csi_chan,
+ u8 csi_port_num,
u8 *clk_settle_time,
u8 *ths_settle_time);
#endif
diff --git a/drivers/staging/media/tegra-video/tegra210.c b/drivers/staging/media/tegra-video/tegra210.c
index ac066c030a4f..f10a041e3e6c 100644
--- a/drivers/staging/media/tegra-video/tegra210.c
+++ b/drivers/staging/media/tegra-video/tegra210.c
@@ -149,21 +149,22 @@ static u32 tegra_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
}
/* Tegra210 VI_CSI registers accessors */
-static void vi_csi_write(struct tegra_vi_channel *chan, unsigned int addr,
- u32 val)
+static void vi_csi_write(struct tegra_vi_channel *chan, u8 portno,
+ unsigned int addr, u32 val)
{
void __iomem *vi_csi_base;
- vi_csi_base = chan->vi->iomem + TEGRA210_VI_CSI_BASE(chan->portno);
+ vi_csi_base = chan->vi->iomem + TEGRA210_VI_CSI_BASE(portno);
writel_relaxed(val, vi_csi_base + addr);
}
-static u32 vi_csi_read(struct tegra_vi_channel *chan, unsigned int addr)
+static u32 vi_csi_read(struct tegra_vi_channel *chan, u8 portno,
+ unsigned int addr)
{
void __iomem *vi_csi_base;
- vi_csi_base = chan->vi->iomem + TEGRA210_VI_CSI_BASE(chan->portno);
+ vi_csi_base = chan->vi->iomem + TEGRA210_VI_CSI_BASE(portno);
return readl_relaxed(vi_csi_base + addr);
}
@@ -171,27 +172,52 @@ static u32 vi_csi_read(struct tegra_vi_channel *chan, unsigned int addr)
/*
* Tegra210 VI channel capture operations
*/
-static int tegra_channel_capture_setup(struct tegra_vi_channel *chan)
+static int tegra_channel_capture_setup(struct tegra_vi_channel *chan,
+ u8 portno)
{
u32 height = chan->format.height;
u32 width = chan->format.width;
u32 format = chan->fmtinfo->img_fmt;
u32 data_type = chan->fmtinfo->img_dt;
u32 word_count = (width * chan->fmtinfo->bit_width) / 8;
+ u32 bypass_pixel_transform = BIT(BYPASS_PXL_TRANSFORM_OFFSET);
- vi_csi_write(chan, TEGRA_VI_CSI_ERROR_STATUS, 0xffffffff);
- vi_csi_write(chan, TEGRA_VI_CSI_IMAGE_DEF,
- ((chan->pg_mode ? 0 : 1) << BYPASS_PXL_TRANSFORM_OFFSET) |
+ /*
+ * VI Pixel transformation unit converts source pixels data format
+ * into selected destination pixel format and aligns properly while
+ * interfacing with memory packer.
+ * This pixel transformation should be enabled for YUV and RGB
+ * formats and should be bypassed for RAW formats as RAW formats
+ * only support direct to memory.
+ */
+ if (chan->pg_mode || data_type == TEGRA_IMAGE_DT_YUV422_8 ||
+ data_type == TEGRA_IMAGE_DT_RGB888)
+ bypass_pixel_transform = 0;
+
+ /*
+ * For x8 source streaming, the source image is split onto two x4 ports
+ * with left half to first x4 port and right half to second x4 port.
+ * So, use split width and corresponding word count for each x4 port.
+ */
+ if (chan->numgangports > 1) {
+ width = width >> 1;
+ word_count = (width * chan->fmtinfo->bit_width) / 8;
+ }
+
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_ERROR_STATUS, 0xffffffff);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_IMAGE_DEF,
+ bypass_pixel_transform |
(format << IMAGE_DEF_FORMAT_OFFSET) |
IMAGE_DEF_DEST_MEM);
- vi_csi_write(chan, TEGRA_VI_CSI_IMAGE_DT, data_type);
- vi_csi_write(chan, TEGRA_VI_CSI_IMAGE_SIZE_WC, word_count);
- vi_csi_write(chan, TEGRA_VI_CSI_IMAGE_SIZE,
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_IMAGE_DT, data_type);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_IMAGE_SIZE_WC, word_count);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_IMAGE_SIZE,
(height << IMAGE_SIZE_HEIGHT_OFFSET) | width);
return 0;
}
-static void tegra_channel_vi_soft_reset(struct tegra_vi_channel *chan)
+static void tegra_channel_vi_soft_reset(struct tegra_vi_channel *chan,
+ u8 portno)
{
/* disable clock gating to enable continuous clock */
tegra_vi_write(chan, TEGRA_VI_CFG_CG_CTRL, 0);
@@ -199,15 +225,16 @@ static void tegra_channel_vi_soft_reset(struct tegra_vi_channel *chan)
* Soft reset memory client interface, pixel format logic, sensor
* control logic, and a shadow copy logic to bring VI to clean state.
*/
- vi_csi_write(chan, TEGRA_VI_CSI_SW_RESET, 0xf);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_SW_RESET, 0xf);
usleep_range(100, 200);
- vi_csi_write(chan, TEGRA_VI_CSI_SW_RESET, 0x0);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_SW_RESET, 0x0);
/* enable back VI clock gating */
tegra_vi_write(chan, TEGRA_VI_CFG_CG_CTRL, VI_CG_2ND_LEVEL_EN);
}
-static void tegra_channel_capture_error_recover(struct tegra_vi_channel *chan)
+static void tegra_channel_capture_error_recover(struct tegra_vi_channel *chan,
+ u8 portno)
{
struct v4l2_subdev *subdev;
u32 val;
@@ -219,9 +246,9 @@ static void tegra_channel_capture_error_recover(struct tegra_vi_channel *chan)
* events which can cause CSI and VI hardware hang.
* This helps to have a clean capture for next frame.
*/
- val = vi_csi_read(chan, TEGRA_VI_CSI_ERROR_STATUS);
+ val = vi_csi_read(chan, portno, TEGRA_VI_CSI_ERROR_STATUS);
dev_dbg(&chan->video.dev, "TEGRA_VI_CSI_ERROR_STATUS 0x%08x\n", val);
- vi_csi_write(chan, TEGRA_VI_CSI_ERROR_STATUS, val);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_ERROR_STATUS, val);
val = tegra_vi_read(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR);
dev_dbg(&chan->video.dev,
@@ -229,8 +256,8 @@ static void tegra_channel_capture_error_recover(struct tegra_vi_channel *chan)
tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR, val);
/* recover VI by issuing software reset and re-setup for capture */
- tegra_channel_vi_soft_reset(chan);
- tegra_channel_capture_setup(chan);
+ tegra_channel_vi_soft_reset(chan, portno);
+ tegra_channel_capture_setup(chan, portno);
/* recover CSI block */
subdev = tegra_channel_get_remote_csi_subdev(chan);
@@ -269,67 +296,114 @@ static void release_buffer(struct tegra_vi_channel *chan,
vb2_buffer_done(&vb->vb2_buf, state);
}
-static int tegra_channel_capture_frame(struct tegra_vi_channel *chan,
- struct tegra_channel_buffer *buf)
+static void tegra_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
+ u8 portno, u32 buf_offset,
+ struct tegra_channel_buffer *buf)
{
- u32 thresh, value, frame_start, mw_ack_done;
- int bytes_per_line = chan->format.bytesperline;
- int err;
+ int bytesperline = chan->format.bytesperline;
+ u32 sizeimage = chan->format.sizeimage;
/* program buffer address by using surface 0 */
- vi_csi_write(chan, TEGRA_VI_CSI_SURFACE0_OFFSET_MSB,
- (u64)buf->addr >> 32);
- vi_csi_write(chan, TEGRA_VI_CSI_SURFACE0_OFFSET_LSB, buf->addr);
- vi_csi_write(chan, TEGRA_VI_CSI_SURFACE0_STRIDE, bytes_per_line);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_SURFACE0_OFFSET_MSB,
+ ((u64)buf->addr + buf_offset) >> 32);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_SURFACE0_OFFSET_LSB,
+ buf->addr + buf_offset);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_SURFACE0_STRIDE, bytesperline);
+ if (chan->fmtinfo->fourcc != V4L2_PIX_FMT_NV16)
+ return;
/*
- * Tegra VI block interacts with host1x syncpt for synchronizing
- * programmed condition of capture state and hardware operation.
- * Frame start and Memory write acknowledge syncpts has their own
- * FIFO of depth 2.
- *
- * Syncpoint trigger conditions set through VI_INCR_SYNCPT register
- * are added to HW syncpt FIFO and when the HW triggers, syncpt
- * condition is removed from the FIFO and counter at syncpoint index
- * will be incremented by the hardware and software can wait for
- * counter to reach threshold to synchronize capturing frame with the
- * hardware capture events.
+ * Program surface 1 for UV plane with offset sizeimage from Y plane.
*/
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_SURFACE1_OFFSET_MSB,
+ (((u64)buf->addr + sizeimage / 2) + buf_offset) >> 32);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_SURFACE1_OFFSET_LSB,
+ buf->addr + sizeimage / 2 + buf_offset);
+ vi_csi_write(chan, portno, TEGRA_VI_CSI_SURFACE1_STRIDE, bytesperline);
+}
- /* increase channel syncpoint threshold for FRAME_START */
- thresh = host1x_syncpt_incr_max(chan->frame_start_sp, 1);
+static int tegra_channel_capture_frame(struct tegra_vi_channel *chan,
+ struct tegra_channel_buffer *buf)
+{
+ u32 thresh, value, frame_start, mw_ack_done;
+ u32 fs_thresh[GANG_PORTS_MAX];
+ u8 *portnos = chan->portnos;
+ int gang_bpl = (chan->format.width >> 1) * chan->fmtinfo->bpp;
+ u32 buf_offset;
+ bool capture_timedout = false;
+ int err, i;
+
+ for (i = 0; i < chan->numgangports; i++) {
+ /*
+ * Align buffers side-by-side for all consecutive x4 ports
+ * in gang ports using bytes per line based on source split
+ * width.
+ */
+ buf_offset = i * roundup(gang_bpl, SURFACE_ALIGN_BYTES);
+ tegra_channel_vi_buffer_setup(chan, portnos[i], buf_offset,
+ buf);
- /* Program FRAME_START trigger condition syncpt request */
- frame_start = VI_CSI_PP_FRAME_START(chan->portno);
- value = VI_CFG_VI_INCR_SYNCPT_COND(frame_start) |
- host1x_syncpt_id(chan->frame_start_sp);
- tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, value);
+ /*
+ * Tegra VI block interacts with host1x syncpt to synchronize
+ * programmed condition and hardware operation for capture.
+ * Frame start and Memory write acknowledge syncpts has their
+ * own FIFO of depth 2.
+ *
+ * Syncpoint trigger conditions set through VI_INCR_SYNCPT
+ * register are added to HW syncpt FIFO and when HW triggers,
+ * syncpt condition is removed from the FIFO and counter at
+ * syncpoint index will be incremented by the hardware and
+ * software can wait for counter to reach threshold to
+ * synchronize capturing frame with hardware capture events.
+ */
- /* increase channel syncpoint threshold for MW_ACK_DONE */
- buf->mw_ack_sp_thresh = host1x_syncpt_incr_max(chan->mw_ack_sp, 1);
+ /* increase channel syncpoint threshold for FRAME_START */
+ thresh = host1x_syncpt_incr_max(chan->frame_start_sp[i], 1);
+ fs_thresh[i] = thresh;
+
+ /* Program FRAME_START trigger condition syncpt request */
+ frame_start = VI_CSI_PP_FRAME_START(portnos[i]);
+ value = VI_CFG_VI_INCR_SYNCPT_COND(frame_start) |
+ host1x_syncpt_id(chan->frame_start_sp[i]);
+ tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, value);
+
+ /* increase channel syncpoint threshold for MW_ACK_DONE */
+ thresh = host1x_syncpt_incr_max(chan->mw_ack_sp[i], 1);
+ buf->mw_ack_sp_thresh[i] = thresh;
+
+ /* Program MW_ACK_DONE trigger condition syncpt request */
+ mw_ack_done = VI_CSI_MW_ACK_DONE(portnos[i]);
+ value = VI_CFG_VI_INCR_SYNCPT_COND(mw_ack_done) |
+ host1x_syncpt_id(chan->mw_ack_sp[i]);
+ tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, value);
+ }
- /* Program MW_ACK_DONE trigger condition syncpt request */
- mw_ack_done = VI_CSI_MW_ACK_DONE(chan->portno);
- value = VI_CFG_VI_INCR_SYNCPT_COND(mw_ack_done) |
- host1x_syncpt_id(chan->mw_ack_sp);
- tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, value);
+ /* enable single shot capture after all ganged ports are ready */
+ for (i = 0; i < chan->numgangports; i++)
+ vi_csi_write(chan, portnos[i], TEGRA_VI_CSI_SINGLE_SHOT,
+ SINGLE_SHOT_CAPTURE);
- /* enable single shot capture */
- vi_csi_write(chan, TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE);
+ for (i = 0; i < chan->numgangports; i++) {
+ /*
+ * Wait for syncpt counter to reach frame start event threshold
+ */
+ err = host1x_syncpt_wait(chan->frame_start_sp[i], fs_thresh[i],
+ TEGRA_VI_SYNCPT_WAIT_TIMEOUT, &value);
+ if (err) {
+ capture_timedout = true;
+ /* increment syncpoint counter for timedout events */
+ host1x_syncpt_incr(chan->frame_start_sp[i]);
+ spin_lock(&chan->sp_incr_lock[i]);
+ host1x_syncpt_incr(chan->mw_ack_sp[i]);
+ spin_unlock(&chan->sp_incr_lock[i]);
+ /* clear errors and recover */
+ tegra_channel_capture_error_recover(chan, portnos[i]);
+ }
+ }
- /* wait for syncpt counter to reach frame start event threshold */
- err = host1x_syncpt_wait(chan->frame_start_sp, thresh,
- TEGRA_VI_SYNCPT_WAIT_TIMEOUT, &value);
- if (err) {
+ if (capture_timedout) {
dev_err_ratelimited(&chan->video.dev,
"frame start syncpt timeout: %d\n", err);
- /* increment syncpoint counter for timedout events */
- host1x_syncpt_incr(chan->frame_start_sp);
- spin_lock(&chan->sp_incr_lock);
- host1x_syncpt_incr(chan->mw_ack_sp);
- spin_unlock(&chan->sp_incr_lock);
- /* clear errors and recover */
- tegra_channel_capture_error_recover(chan);
release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
return err;
}
@@ -350,21 +424,29 @@ static void tegra_channel_capture_done(struct tegra_vi_channel *chan,
{
enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
u32 value;
- int ret;
+ bool capture_timedout = false;
+ int ret, i;
- /* wait for syncpt counter to reach MW_ACK_DONE event threshold */
- ret = host1x_syncpt_wait(chan->mw_ack_sp, buf->mw_ack_sp_thresh,
- TEGRA_VI_SYNCPT_WAIT_TIMEOUT, &value);
- if (ret) {
- dev_err_ratelimited(&chan->video.dev,
- "MW_ACK_DONE syncpt timeout: %d\n", ret);
- state = VB2_BUF_STATE_ERROR;
- /* increment syncpoint counter for timedout event */
- spin_lock(&chan->sp_incr_lock);
- host1x_syncpt_incr(chan->mw_ack_sp);
- spin_unlock(&chan->sp_incr_lock);
+ for (i = 0; i < chan->numgangports; i++) {
+ /*
+ * Wait for syncpt counter to reach MW_ACK_DONE event threshold
+ */
+ ret = host1x_syncpt_wait(chan->mw_ack_sp[i],
+ buf->mw_ack_sp_thresh[i],
+ TEGRA_VI_SYNCPT_WAIT_TIMEOUT, &value);
+ if (ret) {
+ capture_timedout = true;
+ state = VB2_BUF_STATE_ERROR;
+ /* increment syncpoint counter for timedout event */
+ spin_lock(&chan->sp_incr_lock[i]);
+ host1x_syncpt_incr(chan->mw_ack_sp[i]);
+ spin_unlock(&chan->sp_incr_lock[i]);
+ }
}
+ if (capture_timedout)
+ dev_err_ratelimited(&chan->video.dev,
+ "MW_ACK_DONE syncpt timeout: %d\n", ret);
release_buffer(chan, buf, state);
}
@@ -372,6 +454,7 @@ static int chan_capture_kthread_start(void *data)
{
struct tegra_vi_channel *chan = data;
struct tegra_channel_buffer *buf;
+ unsigned int retries = 0;
int err = 0;
while (1) {
@@ -401,8 +484,15 @@ static int chan_capture_kthread_start(void *data)
spin_unlock(&chan->start_lock);
err = tegra_channel_capture_frame(chan, buf);
- if (err)
+ if (!err) {
+ retries = 0;
+ continue;
+ }
+
+ if (retries++ > chan->syncpt_timeout_retry)
vb2_queue_error(&chan->queue);
+ else
+ err = 0;
}
return 0;
@@ -437,14 +527,12 @@ static int tegra210_vi_start_streaming(struct vb2_queue *vq, u32 count)
struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
struct media_pipeline *pipe = &chan->video.pipe;
u32 val;
- int ret;
+ u8 *portnos = chan->portnos;
+ int ret, i;
tegra_vi_write(chan, TEGRA_VI_CFG_CG_CTRL, VI_CG_2ND_LEVEL_EN);
- /* clear errors */
- val = vi_csi_read(chan, TEGRA_VI_CSI_ERROR_STATUS);
- vi_csi_write(chan, TEGRA_VI_CSI_ERROR_STATUS, val);
-
+ /* clear syncpt errors */
val = tegra_vi_read(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR);
tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR, val);
@@ -463,7 +551,14 @@ static int tegra210_vi_start_streaming(struct vb2_queue *vq, u32 count)
if (ret < 0)
goto error_pipeline_start;
- tegra_channel_capture_setup(chan);
+ /* clear csi errors and do capture setup for all ports in gang mode */
+ for (i = 0; i < chan->numgangports; i++) {
+ val = vi_csi_read(chan, portnos[i], TEGRA_VI_CSI_ERROR_STATUS);
+ vi_csi_write(chan, portnos[i], TEGRA_VI_CSI_ERROR_STATUS, val);
+
+ tegra_channel_capture_setup(chan, portnos[i]);
+ }
+
ret = tegra_channel_set_stream(chan, true);
if (ret < 0)
goto error_set_stream;
@@ -606,19 +701,19 @@ static const struct tegra_video_format tegra210_video_formats[] = {
TEGRA210_VIDEO_FMT(RAW12, 12, SGBRG12_1X12, 2, T_R16_I, SGBRG12),
TEGRA210_VIDEO_FMT(RAW12, 12, SBGGR12_1X12, 2, T_R16_I, SBGGR12),
/* RGB888 */
- TEGRA210_VIDEO_FMT(RGB888, 24, RGB888_1X24, 4, T_A8R8G8B8, RGB24),
+ TEGRA210_VIDEO_FMT(RGB888, 24, RGB888_1X24, 4, T_A8R8G8B8, XBGR32),
TEGRA210_VIDEO_FMT(RGB888, 24, RGB888_1X32_PADHI, 4, T_A8B8G8R8,
- XBGR32),
+ RGBX32),
/* YUV422 */
- TEGRA210_VIDEO_FMT(YUV422_8, 16, UYVY8_1X16, 2, T_U8_Y8__V8_Y8, UYVY),
- TEGRA210_VIDEO_FMT(YUV422_8, 16, VYUY8_1X16, 2, T_V8_Y8__U8_Y8, VYUY),
- TEGRA210_VIDEO_FMT(YUV422_8, 16, YUYV8_1X16, 2, T_Y8_U8__Y8_V8, YUYV),
- TEGRA210_VIDEO_FMT(YUV422_8, 16, YVYU8_1X16, 2, T_Y8_V8__Y8_U8, YVYU),
+ TEGRA210_VIDEO_FMT(YUV422_8, 16, UYVY8_1X16, 2, T_U8_Y8__V8_Y8, YVYU),
+ TEGRA210_VIDEO_FMT(YUV422_8, 16, VYUY8_1X16, 2, T_V8_Y8__U8_Y8, YUYV),
+ TEGRA210_VIDEO_FMT(YUV422_8, 16, YUYV8_1X16, 2, T_Y8_U8__Y8_V8, VYUY),
+ TEGRA210_VIDEO_FMT(YUV422_8, 16, YVYU8_1X16, 2, T_Y8_V8__Y8_U8, UYVY),
TEGRA210_VIDEO_FMT(YUV422_8, 16, UYVY8_1X16, 1, T_Y8__V8U8_N422, NV16),
- TEGRA210_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 2, T_U8_Y8__V8_Y8, UYVY),
- TEGRA210_VIDEO_FMT(YUV422_8, 16, VYUY8_2X8, 2, T_V8_Y8__U8_Y8, VYUY),
- TEGRA210_VIDEO_FMT(YUV422_8, 16, YUYV8_2X8, 2, T_Y8_U8__Y8_V8, YUYV),
- TEGRA210_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 2, T_Y8_V8__Y8_U8, YVYU),
+ TEGRA210_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 2, T_U8_Y8__V8_Y8, YVYU),
+ TEGRA210_VIDEO_FMT(YUV422_8, 16, VYUY8_2X8, 2, T_V8_Y8__U8_Y8, YUYV),
+ TEGRA210_VIDEO_FMT(YUV422_8, 16, YUYV8_2X8, 2, T_Y8_U8__Y8_V8, VYUY),
+ TEGRA210_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 2, T_Y8_V8__Y8_U8, UYVY),
};
/* Tegra210 VI operations */
@@ -717,10 +812,10 @@ static void tpg_write(struct tegra_csi *csi, u8 portno, unsigned int addr,
/*
* Tegra210 CSI operations
*/
-static void tegra210_csi_error_recover(struct tegra_csi_channel *csi_chan)
+static void tegra210_csi_port_recover(struct tegra_csi_channel *csi_chan,
+ u8 portno)
{
struct tegra_csi *csi = csi_chan->csi;
- unsigned int portno = csi_chan->csi_port_num;
u32 val;
/*
@@ -769,16 +864,26 @@ static void tegra210_csi_error_recover(struct tegra_csi_channel *csi_chan)
}
}
-static int tegra210_csi_start_streaming(struct tegra_csi_channel *csi_chan)
+static void tegra210_csi_error_recover(struct tegra_csi_channel *csi_chan)
+{
+ u8 *portnos = csi_chan->csi_port_nums;
+ int i;
+
+ for (i = 0; i < csi_chan->numgangports; i++)
+ tegra210_csi_port_recover(csi_chan, portnos[i]);
+}
+
+static int
+tegra210_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
+ u8 portno)
{
struct tegra_csi *csi = csi_chan->csi;
- unsigned int portno = csi_chan->csi_port_num;
u8 clk_settle_time = 0;
u8 ths_settle_time = 10;
u32 val;
if (!csi_chan->pg_mode)
- tegra_csi_calc_settle_time(csi_chan, &clk_settle_time,
+ tegra_csi_calc_settle_time(csi_chan, portno, &clk_settle_time,
&ths_settle_time);
csi_write(csi, portno, TEGRA_CSI_CLKEN_OVERRIDE, 0);
@@ -877,10 +982,10 @@ static int tegra210_csi_start_streaming(struct tegra_csi_channel *csi_chan)
return 0;
}
-static void tegra210_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
+static void
+tegra210_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
{
struct tegra_csi *csi = csi_chan->csi;
- unsigned int portno = csi_chan->csi_port_num;
u32 val;
val = pp_read(csi, portno, TEGRA_CSI_PIXEL_PARSER_STATUS);
@@ -918,6 +1023,35 @@ static void tegra210_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
}
}
+static int tegra210_csi_start_streaming(struct tegra_csi_channel *csi_chan)
+{
+ u8 *portnos = csi_chan->csi_port_nums;
+ int ret, i;
+
+ for (i = 0; i < csi_chan->numgangports; i++) {
+ ret = tegra210_csi_port_start_streaming(csi_chan, portnos[i]);
+ if (ret)
+ goto stream_start_fail;
+ }
+
+ return 0;
+
+stream_start_fail:
+ for (i = i - 1; i >= 0; i--)
+ tegra210_csi_port_stop_streaming(csi_chan, portnos[i]);
+
+ return ret;
+}
+
+static void tegra210_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
+{
+ u8 *portnos = csi_chan->csi_port_nums;
+ int i;
+
+ for (i = 0; i < csi_chan->numgangports; i++)
+ tegra210_csi_port_stop_streaming(csi_chan, portnos[i]);
+}
+
/*
* Tegra210 CSI TPG frame rate table with horizontal and vertical
* blanking intervals for corresponding format and resolution.
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 560d8b368124..7a09061cda57 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <media/v4l2-dv-timings.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-fwnode.h>
@@ -29,7 +30,6 @@
#include "vi.h"
#include "video.h"
-#define SURFACE_ALIGN_BYTES 64
#define MAX_CID_CONTROLS 1
static const struct tegra_video_format tegra_default_format = {
@@ -484,6 +484,8 @@ static void tegra_channel_fmt_align(struct tegra_vi_channel *chan,
pix->bytesperline = clamp(bpl, min_bpl, max_bpl);
pix->sizeimage = pix->bytesperline * pix->height;
+ if (pix->pixelformat == V4L2_PIX_FMT_NV16)
+ pix->sizeimage *= 2;
}
static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
@@ -533,11 +535,18 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
fse.code = fmtinfo->code;
ret = v4l2_subdev_call(subdev, pad, enum_frame_size, pad_cfg, &fse);
if (ret) {
- ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel);
- if (ret)
- return -EINVAL;
- pad_cfg->try_crop.width = sdsel.r.width;
- pad_cfg->try_crop.height = sdsel.r.height;
+ if (!v4l2_subdev_has_op(subdev, pad, get_selection)) {
+ pad_cfg->try_crop.width = 0;
+ pad_cfg->try_crop.height = 0;
+ } else {
+ ret = v4l2_subdev_call(subdev, pad, get_selection,
+ NULL, &sdsel);
+ if (ret)
+ return -EINVAL;
+
+ pad_cfg->try_crop.width = sdsel.r.width;
+ pad_cfg->try_crop.height = sdsel.r.height;
+ }
} else {
pad_cfg->try_crop.width = fse.max_width;
pad_cfg->try_crop.height = fse.max_height;
@@ -563,6 +572,14 @@ static int tegra_channel_try_format(struct file *file, void *fh,
return __tegra_channel_try_format(chan, &format->fmt.pix);
}
+static void tegra_channel_update_gangports(struct tegra_vi_channel *chan)
+{
+ if (chan->format.width <= 1920)
+ chan->numgangports = 1;
+ else
+ chan->numgangports = chan->totalports;
+}
+
static int tegra_channel_set_format(struct file *file, void *fh,
struct v4l2_format *format)
{
@@ -596,6 +613,7 @@ static int tegra_channel_set_format(struct file *file, void *fh,
chan->format = *pix;
chan->fmtinfo = fmtinfo;
+ tegra_channel_update_gangports(chan);
return 0;
}
@@ -628,10 +646,23 @@ static int tegra_channel_set_subdev_active_fmt(struct tegra_vi_channel *chan)
chan->format.sizeimage = chan->format.bytesperline *
chan->format.height;
tegra_channel_fmt_align(chan, &chan->format, chan->fmtinfo->bpp);
+ tegra_channel_update_gangports(chan);
return 0;
}
+static int
+tegra_channel_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return v4l2_event_subscribe(fh, sub, 4, NULL);
+ }
+
+ return v4l2_ctrl_subscribe_event(fh, sub);
+}
+
static int tegra_channel_g_selection(struct file *file, void *priv,
struct v4l2_selection *sel)
{
@@ -711,6 +742,133 @@ static int tegra_channel_s_selection(struct file *file, void *fh,
return ret;
}
+static int tegra_channel_g_edid(struct file *file, void *fh,
+ struct v4l2_edid *edid)
+{
+ struct tegra_vi_channel *chan = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+
+ subdev = tegra_channel_get_remote_source_subdev(chan);
+ if (!v4l2_subdev_has_op(subdev, pad, get_edid))
+ return -ENOTTY;
+
+ return v4l2_subdev_call(subdev, pad, get_edid, edid);
+}
+
+static int tegra_channel_s_edid(struct file *file, void *fh,
+ struct v4l2_edid *edid)
+{
+ struct tegra_vi_channel *chan = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+
+ subdev = tegra_channel_get_remote_source_subdev(chan);
+ if (!v4l2_subdev_has_op(subdev, pad, set_edid))
+ return -ENOTTY;
+
+ return v4l2_subdev_call(subdev, pad, set_edid, edid);
+}
+
+static int tegra_channel_g_dv_timings(struct file *file, void *fh,
+ struct v4l2_dv_timings *timings)
+{
+ struct tegra_vi_channel *chan = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+
+ subdev = tegra_channel_get_remote_source_subdev(chan);
+ if (!v4l2_subdev_has_op(subdev, video, g_dv_timings))
+ return -ENOTTY;
+
+ return v4l2_device_call_until_err(chan->video.v4l2_dev, 0,
+ video, g_dv_timings, timings);
+}
+
+static int tegra_channel_s_dv_timings(struct file *file, void *fh,
+ struct v4l2_dv_timings *timings)
+{
+ struct tegra_vi_channel *chan = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+ struct v4l2_bt_timings *bt = &timings->bt;
+ struct v4l2_dv_timings curr_timings;
+ int ret;
+
+ subdev = tegra_channel_get_remote_source_subdev(chan);
+ if (!v4l2_subdev_has_op(subdev, video, s_dv_timings))
+ return -ENOTTY;
+
+ ret = tegra_channel_g_dv_timings(file, fh, &curr_timings);
+ if (ret)
+ return ret;
+
+ if (v4l2_match_dv_timings(timings, &curr_timings, 0, false))
+ return 0;
+
+ if (vb2_is_busy(&chan->queue))
+ return -EBUSY;
+
+ ret = v4l2_device_call_until_err(chan->video.v4l2_dev, 0,
+ video, s_dv_timings, timings);
+ if (ret)
+ return ret;
+
+ chan->format.width = bt->width;
+ chan->format.height = bt->height;
+ chan->format.bytesperline = bt->width * chan->fmtinfo->bpp;
+ chan->format.sizeimage = chan->format.bytesperline * bt->height;
+ tegra_channel_fmt_align(chan, &chan->format, chan->fmtinfo->bpp);
+ tegra_channel_update_gangports(chan);
+
+ return 0;
+}
+
+static int tegra_channel_query_dv_timings(struct file *file, void *fh,
+ struct v4l2_dv_timings *timings)
+{
+ struct tegra_vi_channel *chan = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+
+ subdev = tegra_channel_get_remote_source_subdev(chan);
+ if (!v4l2_subdev_has_op(subdev, video, query_dv_timings))
+ return -ENOTTY;
+
+ return v4l2_device_call_until_err(chan->video.v4l2_dev, 0,
+ video, query_dv_timings, timings);
+}
+
+static int tegra_channel_enum_dv_timings(struct file *file, void *fh,
+ struct v4l2_enum_dv_timings *timings)
+{
+ struct tegra_vi_channel *chan = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+
+ subdev = tegra_channel_get_remote_source_subdev(chan);
+ if (!v4l2_subdev_has_op(subdev, pad, enum_dv_timings))
+ return -ENOTTY;
+
+ return v4l2_subdev_call(subdev, pad, enum_dv_timings, timings);
+}
+
+static int tegra_channel_dv_timings_cap(struct file *file, void *fh,
+ struct v4l2_dv_timings_cap *cap)
+{
+ struct tegra_vi_channel *chan = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+
+ subdev = tegra_channel_get_remote_source_subdev(chan);
+ if (!v4l2_subdev_has_op(subdev, pad, dv_timings_cap))
+ return -ENOTTY;
+
+ return v4l2_subdev_call(subdev, pad, dv_timings_cap, cap);
+}
+
+static int tegra_channel_log_status(struct file *file, void *fh)
+{
+ struct tegra_vi_channel *chan = video_drvdata(file);
+
+ v4l2_device_call_all(chan->video.v4l2_dev, 0, core, log_status);
+
+ return 0;
+}
+
static int tegra_channel_enum_input(struct file *file, void *fh,
struct v4l2_input *inp)
{
@@ -723,6 +881,8 @@ static int tegra_channel_enum_input(struct file *file, void *fh,
inp->type = V4L2_INPUT_TYPE_CAMERA;
subdev = tegra_channel_get_remote_source_subdev(chan);
strscpy(inp->name, subdev->name, sizeof(inp->name));
+ if (v4l2_subdev_has_op(subdev, pad, dv_timings_cap))
+ inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
return 0;
}
@@ -766,10 +926,18 @@ static const struct v4l2_ioctl_ops tegra_channel_ioctl_ops = {
.vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_subscribe_event = tegra_channel_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
.vidioc_g_selection = tegra_channel_g_selection,
.vidioc_s_selection = tegra_channel_s_selection,
+ .vidioc_g_edid = tegra_channel_g_edid,
+ .vidioc_s_edid = tegra_channel_s_edid,
+ .vidioc_g_dv_timings = tegra_channel_g_dv_timings,
+ .vidioc_s_dv_timings = tegra_channel_s_dv_timings,
+ .vidioc_query_dv_timings = tegra_channel_query_dv_timings,
+ .vidioc_enum_dv_timings = tegra_channel_enum_dv_timings,
+ .vidioc_dv_timings_cap = tegra_channel_dv_timings_cap,
+ .vidioc_log_status = tegra_channel_log_status,
};
/*
@@ -788,7 +956,6 @@ static const struct v4l2_file_operations tegra_channel_fops = {
/*
* V4L2 control operations
*/
-#if IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)
static int vi_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct tegra_vi_channel *chan = container_of(ctrl->handler,
@@ -800,6 +967,9 @@ static int vi_s_ctrl(struct v4l2_ctrl *ctrl)
/* pattern change takes effect on next stream */
chan->pg_mode = ctrl->val + 1;
break;
+ case V4L2_CID_TEGRA_SYNCPT_TIMEOUT_RETRY:
+ chan->syncpt_timeout_retry = ctrl->val;
+ break;
default:
return -EINVAL;
}
@@ -811,10 +981,22 @@ static const struct v4l2_ctrl_ops vi_ctrl_ops = {
.s_ctrl = vi_s_ctrl,
};
+#if IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)
static const char *const vi_pattern_strings[] = {
"Black/White Direct Mode",
"Color Patch Mode",
};
+#else
+static const struct v4l2_ctrl_config syncpt_timeout_ctrl = {
+ .ops = &vi_ctrl_ops,
+ .id = V4L2_CID_TEGRA_SYNCPT_TIMEOUT_RETRY,
+ .name = "Syncpt timeout retry",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 10000,
+ .step = 1,
+ .def = 5,
+};
#endif
static int tegra_channel_setup_ctrl_handler(struct tegra_vi_channel *chan)
@@ -836,6 +1018,16 @@ static int tegra_channel_setup_ctrl_handler(struct tegra_vi_channel *chan)
#else
struct v4l2_subdev *subdev;
+ /* custom control */
+ v4l2_ctrl_new_custom(&chan->ctrl_handler, &syncpt_timeout_ctrl, NULL);
+ if (chan->ctrl_handler.error) {
+ dev_err(chan->vi->dev, "failed to add %s ctrl handler: %d\n",
+ syncpt_timeout_ctrl.name,
+ chan->ctrl_handler.error);
+ v4l2_ctrl_handler_free(&chan->ctrl_handler);
+ return chan->ctrl_handler.error;
+ }
+
subdev = tegra_channel_get_remote_source_subdev(chan);
if (!subdev)
return -ENODEV;
@@ -934,12 +1126,21 @@ static int vi_fmts_bitmap_init(struct tegra_vi_channel *chan)
return 0;
}
+static void tegra_channel_host1x_syncpts_free(struct tegra_vi_channel *chan)
+{
+ int i;
+
+ for (i = 0; i < chan->numgangports; i++) {
+ host1x_syncpt_free(chan->mw_ack_sp[i]);
+ host1x_syncpt_free(chan->frame_start_sp[i]);
+ }
+}
+
static void tegra_channel_cleanup(struct tegra_vi_channel *chan)
{
v4l2_ctrl_handler_free(&chan->ctrl_handler);
media_entity_cleanup(&chan->video.entity);
- host1x_syncpt_free(chan->mw_ack_sp);
- host1x_syncpt_free(chan->frame_start_sp);
+ tegra_channel_host1x_syncpts_free(chan);
mutex_destroy(&chan->video_lock);
}
@@ -957,11 +1158,46 @@ void tegra_channels_cleanup(struct tegra_vi *vi)
}
}
+static int tegra_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
+{
+ struct tegra_vi *vi = chan->vi;
+ unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
+ struct host1x_syncpt *fs_sp;
+ struct host1x_syncpt *mw_sp;
+ int ret, i;
+
+ for (i = 0; i < chan->numgangports; i++) {
+ fs_sp = host1x_syncpt_request(&vi->client, flags);
+ if (!fs_sp) {
+ dev_err(vi->dev, "failed to request frame start syncpoint\n");
+ ret = -ENOMEM;
+ goto free_syncpts;
+ }
+
+ mw_sp = host1x_syncpt_request(&vi->client, flags);
+ if (!mw_sp) {
+ dev_err(vi->dev, "failed to request memory ack syncpoint\n");
+ host1x_syncpt_free(fs_sp);
+ ret = -ENOMEM;
+ goto free_syncpts;
+ }
+
+ chan->frame_start_sp[i] = fs_sp;
+ chan->mw_ack_sp[i] = mw_sp;
+ spin_lock_init(&chan->sp_incr_lock[i]);
+ }
+
+ return 0;
+
+free_syncpts:
+ tegra_channel_host1x_syncpts_free(chan);
+ return ret;
+}
+
static int tegra_channel_init(struct tegra_vi_channel *chan)
{
struct tegra_vi *vi = chan->vi;
struct tegra_video_device *vid = dev_get_drvdata(vi->client.host);
- unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
int ret;
mutex_init(&chan->video_lock);
@@ -969,7 +1205,6 @@ static int tegra_channel_init(struct tegra_vi_channel *chan)
INIT_LIST_HEAD(&chan->done);
spin_lock_init(&chan->start_lock);
spin_lock_init(&chan->done_lock);
- spin_lock_init(&chan->sp_incr_lock);
init_waitqueue_head(&chan->start_wait);
init_waitqueue_head(&chan->done_wait);
@@ -984,18 +1219,9 @@ static int tegra_channel_init(struct tegra_vi_channel *chan)
chan->format.sizeimage = chan->format.bytesperline * TEGRA_DEF_HEIGHT;
tegra_channel_fmt_align(chan, &chan->format, chan->fmtinfo->bpp);
- chan->frame_start_sp = host1x_syncpt_request(&vi->client, flags);
- if (!chan->frame_start_sp) {
- dev_err(vi->dev, "failed to request frame start syncpoint\n");
- return -ENOMEM;
- }
-
- chan->mw_ack_sp = host1x_syncpt_request(&vi->client, flags);
- if (!chan->mw_ack_sp) {
- dev_err(vi->dev, "failed to request memory ack syncpoint\n");
- ret = -ENOMEM;
- goto free_fs_syncpt;
- }
+ ret = tegra_channel_host1x_syncpt_init(chan);
+ if (ret)
+ return ret;
/* initialize the media entity */
chan->pad.flags = MEDIA_PAD_FL_SINK;
@@ -1003,7 +1229,7 @@ static int tegra_channel_init(struct tegra_vi_channel *chan)
if (ret < 0) {
dev_err(vi->dev,
"failed to initialize media entity: %d\n", ret);
- goto free_mw_ack_syncpt;
+ goto free_syncpts;
}
ret = v4l2_ctrl_handler_init(&chan->ctrl_handler, MAX_CID_CONTROLS);
@@ -1019,7 +1245,7 @@ static int tegra_channel_init(struct tegra_vi_channel *chan)
chan->video.release = video_device_release_empty;
chan->video.queue = &chan->queue;
snprintf(chan->video.name, sizeof(chan->video.name), "%s-%s-%u",
- dev_name(vi->dev), "output", chan->portno);
+ dev_name(vi->dev), "output", chan->portnos[0]);
chan->video.vfl_type = VFL_TYPE_VIDEO;
chan->video.vfl_dir = VFL_DIR_RX;
chan->video.ioctl_ops = &tegra_channel_ioctl_ops;
@@ -1055,17 +1281,16 @@ free_v4l2_ctrl_hdl:
v4l2_ctrl_handler_free(&chan->ctrl_handler);
cleanup_media:
media_entity_cleanup(&chan->video.entity);
-free_mw_ack_syncpt:
- host1x_syncpt_free(chan->mw_ack_sp);
-free_fs_syncpt:
- host1x_syncpt_free(chan->frame_start_sp);
+free_syncpts:
+ tegra_channel_host1x_syncpts_free(chan);
return ret;
}
static int tegra_vi_channel_alloc(struct tegra_vi *vi, unsigned int port_num,
- struct device_node *node)
+ struct device_node *node, unsigned int lanes)
{
struct tegra_vi_channel *chan;
+ unsigned int i;
/*
* Do not use devm_kzalloc as memory is freed immediately
@@ -1078,7 +1303,20 @@ static int tegra_vi_channel_alloc(struct tegra_vi *vi, unsigned int port_num,
return -ENOMEM;
chan->vi = vi;
- chan->portno = port_num;
+ chan->portnos[0] = port_num;
+ /*
+ * For data lanes more than maximum csi lanes per brick, multiple of
+ * x4 ports are used simultaneously for capture.
+ */
+ if (lanes <= CSI_LANES_PER_BRICK)
+ chan->totalports = 1;
+ else
+ chan->totalports = lanes / CSI_LANES_PER_BRICK;
+ chan->numgangports = chan->totalports;
+
+ for (i = 1; i < chan->totalports; i++)
+ chan->portnos[i] = chan->portnos[0] + i * CSI_PORTS_PER_BRICK;
+
chan->of_node = node;
list_add_tail(&chan->list, &vi->vi_chans);
@@ -1092,7 +1330,8 @@ static int tegra_vi_tpg_channels_alloc(struct tegra_vi *vi)
int ret;
for (port_num = 0; port_num < nchannels; port_num++) {
- ret = tegra_vi_channel_alloc(vi, port_num, vi->dev->of_node);
+ ret = tegra_vi_channel_alloc(vi, port_num,
+ vi->dev->of_node, 2);
if (ret < 0)
return ret;
}
@@ -1107,6 +1346,9 @@ static int tegra_vi_channels_alloc(struct tegra_vi *vi)
struct device_node *ports;
struct device_node *port;
unsigned int port_num;
+ struct device_node *parent;
+ struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
+ unsigned int lanes;
int ret = 0;
ports = of_get_child_by_name(node, "ports");
@@ -1133,8 +1375,21 @@ static int tegra_vi_channels_alloc(struct tegra_vi *vi)
if (!ep)
continue;
+ parent = of_graph_get_remote_port_parent(ep);
+ of_node_put(ep);
+ if (!parent)
+ continue;
+
+ ep = of_graph_get_endpoint_by_regs(parent, 0, 0);
+ of_node_put(parent);
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep),
+ &v4l2_ep);
of_node_put(ep);
- ret = tegra_vi_channel_alloc(vi, port_num, port);
+ if (ret)
+ continue;
+
+ lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
+ ret = tegra_vi_channel_alloc(vi, port_num, port, lanes);
if (ret < 0) {
of_node_put(port);
goto cleanup;
@@ -1156,7 +1411,7 @@ static int tegra_vi_channels_init(struct tegra_vi *vi)
if (ret < 0) {
dev_err(vi->dev,
"failed to initialize channel-%d: %d\n",
- chan->portno, ret);
+ chan->portnos[0], ret);
goto cleanup;
}
}
@@ -1478,6 +1733,9 @@ static int tegra_vi_graph_notify_complete(struct v4l2_async_notifier *notifier)
v4l2_set_subdev_hostdata(subdev, chan);
+ subdev = tegra_channel_get_remote_source_subdev(chan);
+ v4l2_set_subdev_hostdata(subdev, chan);
+
return 0;
unregister_video:
@@ -1530,7 +1788,7 @@ static int tegra_vi_graph_parse_one(struct tegra_vi_channel *chan,
struct tegra_vi *vi = chan->vi;
struct fwnode_handle *ep = NULL;
struct fwnode_handle *remote = NULL;
- struct v4l2_async_subdev *asd;
+ struct tegra_vi_graph_entity *tvge;
struct device_node *node = NULL;
int ret;
@@ -1554,10 +1812,10 @@ static int tegra_vi_graph_parse_one(struct tegra_vi_channel *chan,
continue;
}
- asd = v4l2_async_notifier_add_fwnode_subdev(&chan->notifier,
- remote, sizeof(struct tegra_vi_graph_entity));
- if (IS_ERR(asd)) {
- ret = PTR_ERR(asd);
+ tvge = v4l2_async_notifier_add_fwnode_subdev(&chan->notifier,
+ remote, struct tegra_vi_graph_entity);
+ if (IS_ERR(tvge)) {
+ ret = PTR_ERR(tvge);
dev_err(vi->dev,
"failed to add subdev to notifier: %d\n", ret);
fwnode_handle_put(remote);
@@ -1600,7 +1858,8 @@ static int tegra_vi_graph_init(struct tegra_vi *vi)
* next channels.
*/
list_for_each_entry(chan, &vi->vi_chans, list) {
- remote = fwnode_graph_get_remote_node(fwnode, chan->portno, 0);
+ remote = fwnode_graph_get_remote_node(fwnode, chan->portnos[0],
+ 0);
if (!remote)
continue;
@@ -1615,7 +1874,7 @@ static int tegra_vi_graph_init(struct tegra_vi *vi)
if (ret < 0) {
dev_err(vi->dev,
"failed to register channel %d notifier: %d\n",
- chan->portno, ret);
+ chan->portnos[0], ret);
v4l2_async_notifier_cleanup(&chan->notifier);
}
}
@@ -1666,11 +1925,14 @@ static int tegra_vi_init(struct host1x_client *client)
if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)) {
ret = tegra_vi_graph_init(vi);
if (ret < 0)
- goto free_chans;
+ goto cleanup_chans;
}
return 0;
+cleanup_chans:
+ list_for_each_entry(chan, &vi->vi_chans, list)
+ tegra_channel_cleanup(chan);
free_chans:
list_for_each_entry_safe(chan, tmp, &vi->vi_chans, list) {
list_del(&chan->list);
diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
index 7d6b7a6d0a45..a68e2c02c7b0 100644
--- a/drivers/staging/media/tegra-video/vi.h
+++ b/drivers/staging/media/tegra-video/vi.h
@@ -21,6 +21,10 @@
#include <media/v4l2-subdev.h>
#include <media/videobuf2-v4l2.h>
+#include "csi.h"
+
+#define V4L2_CID_TEGRA_SYNCPT_TIMEOUT_RETRY (V4L2_CTRL_CLASS_CAMERA | 0x1001)
+
#define TEGRA_MIN_WIDTH 32U
#define TEGRA_MAX_WIDTH 32768U
#define TEGRA_MIN_HEIGHT 32U
@@ -31,6 +35,7 @@
#define TEGRA_IMAGE_FORMAT_DEF 32
#define MAX_FORMAT_NUM 64
+#define SURFACE_ALIGN_BYTES 64
enum tegra_vi_pg_mode {
TEGRA_VI_PG_DISABLED = 0,
@@ -151,10 +156,13 @@ struct tegra_vi_graph_entity {
* @done: list of capture done queued buffers
* @done_lock: protects the capture done queue list
*
- * @portno: VI channel port number
+ * @portnos: VI channel port numbers
+ * @totalports: total number of ports used for this channel
+ * @numgangports: number of ports combined together as a gang for capture
* @of_node: device node of VI channel
*
* @ctrl_handler: V4L2 control handler of this video channel
+ * @syncpt_timeout_retry: syncpt timeout retry count for the capture
* @fmts_bitmap: a bitmap for supported formats matching v4l2 subdev formats
* @tpg_fmts_bitmap: a bitmap for supported TPG formats
* @pg_mode: test pattern generator mode (disabled/direct/patch)
@@ -168,10 +176,10 @@ struct tegra_vi_channel {
struct media_pad pad;
struct tegra_vi *vi;
- struct host1x_syncpt *frame_start_sp;
- struct host1x_syncpt *mw_ack_sp;
+ struct host1x_syncpt *frame_start_sp[GANG_PORTS_MAX];
+ struct host1x_syncpt *mw_ack_sp[GANG_PORTS_MAX];
/* protects the cpu syncpoint increment */
- spinlock_t sp_incr_lock;
+ spinlock_t sp_incr_lock[GANG_PORTS_MAX];
struct task_struct *kthread_start_capture;
wait_queue_head_t start_wait;
@@ -190,10 +198,13 @@ struct tegra_vi_channel {
/* protects the capture done queue list */
spinlock_t done_lock;
- unsigned char portno;
+ unsigned char portnos[GANG_PORTS_MAX];
+ u8 totalports;
+ u8 numgangports;
struct device_node *of_node;
struct v4l2_ctrl_handler ctrl_handler;
+ unsigned int syncpt_timeout_retry;
DECLARE_BITMAP(fmts_bitmap, MAX_FORMAT_NUM);
DECLARE_BITMAP(tpg_fmts_bitmap, MAX_FORMAT_NUM);
enum tegra_vi_pg_mode pg_mode;
@@ -216,7 +227,7 @@ struct tegra_channel_buffer {
struct list_head queue;
struct tegra_vi_channel *chan;
dma_addr_t addr;
- u32 mw_ack_sp_thresh;
+ u32 mw_ack_sp_thresh[GANG_PORTS_MAX];
};
/*
diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
index e50bd70575f3..d966b319553f 100644
--- a/drivers/staging/media/tegra-video/video.c
+++ b/drivers/staging/media/tegra-video/video.c
@@ -7,6 +7,8 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <media/v4l2-event.h>
+
#include "video.h"
static void tegra_v4l2_dev_release(struct v4l2_device *v4l2_dev)
@@ -24,6 +26,21 @@ static void tegra_v4l2_dev_release(struct v4l2_device *v4l2_dev)
kfree(vid);
}
+static void tegra_v4l2_dev_notify(struct v4l2_subdev *sd,
+ unsigned int notification, void *arg)
+{
+ struct tegra_vi_channel *chan;
+ const struct v4l2_event *ev = arg;
+
+ if (notification != V4L2_DEVICE_NOTIFY_EVENT)
+ return;
+
+ chan = v4l2_get_subdev_hostdata(sd);
+ v4l2_event_queue(&chan->video, arg);
+ if (ev->type == V4L2_EVENT_SOURCE_CHANGE && vb2_is_streaming(&chan->queue))
+ vb2_queue_error(&chan->queue);
+}
+
static int host1x_video_probe(struct host1x_device *dev)
{
struct tegra_video_device *vid;
@@ -49,6 +66,7 @@ static int host1x_video_probe(struct host1x_device *dev)
vid->v4l2_dev.mdev = &vid->media_dev;
vid->v4l2_dev.release = tegra_v4l2_dev_release;
+ vid->v4l2_dev.notify = tegra_v4l2_dev_notify;
ret = v4l2_device_register(&dev->dev, &vid->v4l2_dev);
if (ret < 0) {
dev_err(&dev->dev,
diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c
index d9f8b21edf6a..e8902f824d6c 100644
--- a/drivers/staging/media/zoran/zoran_driver.c
+++ b/drivers/staging/media/zoran/zoran_driver.c
@@ -1020,7 +1020,7 @@ int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq)
vq->buf_struct_size = sizeof(struct zr_buffer);
vq->ops = &zr_video_qops;
vq->mem_ops = &vb2_dma_contig_memops;
- vq->gfp_flags = GFP_DMA32,
+ vq->gfp_flags = GFP_DMA32;
vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
vq->min_buffers_needed = 9;
vq->lock = &zr->lock;