diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-21 14:10:36 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-21 14:10:36 -0800 |
commit | de1617578849acab8e16c9ffdce39b91fb50639d (patch) | |
tree | 913a330d92a5ce327a48531f58c78b0d72a109a7 /drivers/staging | |
parent | 66f73fb3facd42d0a7c899d7f4c712332b28499a (diff) | |
parent | 8f202f8e9ff38e29694a4bc0a519b4e03c1726ee (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')
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(¶m, 0, sizeof(param)); - fill_create_channel_param(channel, ¶m); - allegro_alloc_buffer(dev, blob, sizeof(struct create_channel_param)); - param.version = dev->fw_info->mailbox_version; - size = allegro_encode_config_blob(blob->vaddr, ¶m); - - 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(¶m, 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; |