162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * camss-video.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Qualcomm MSM Camera Subsystem - V4L2 device node 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. 862306a36Sopenharmony_ci * Copyright (C) 2015-2018 Linaro Ltd. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <media/media-entity.h> 1262306a36Sopenharmony_ci#include <media/v4l2-dev.h> 1362306a36Sopenharmony_ci#include <media/v4l2-device.h> 1462306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 1562306a36Sopenharmony_ci#include <media/v4l2-mc.h> 1662306a36Sopenharmony_ci#include <media/videobuf2-dma-sg.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "camss-video.h" 1962306a36Sopenharmony_ci#include "camss.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define CAMSS_FRAME_MIN_WIDTH 1 2262306a36Sopenharmony_ci#define CAMSS_FRAME_MAX_WIDTH 8191 2362306a36Sopenharmony_ci#define CAMSS_FRAME_MIN_HEIGHT 1 2462306a36Sopenharmony_ci#define CAMSS_FRAME_MAX_HEIGHT_RDI 8191 2562306a36Sopenharmony_ci#define CAMSS_FRAME_MAX_HEIGHT_PIX 4096 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct fract { 2862306a36Sopenharmony_ci u8 numerator; 2962306a36Sopenharmony_ci u8 denominator; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * struct camss_format_info - ISP media bus format information 3462306a36Sopenharmony_ci * @code: V4L2 media bus format code 3562306a36Sopenharmony_ci * @pixelformat: V4L2 pixel format FCC identifier 3662306a36Sopenharmony_ci * @planes: Number of planes 3762306a36Sopenharmony_ci * @hsub: Horizontal subsampling (for each plane) 3862306a36Sopenharmony_ci * @vsub: Vertical subsampling (for each plane) 3962306a36Sopenharmony_ci * @bpp: Bits per pixel when stored in memory (for each plane) 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_cistruct camss_format_info { 4262306a36Sopenharmony_ci u32 code; 4362306a36Sopenharmony_ci u32 pixelformat; 4462306a36Sopenharmony_ci u8 planes; 4562306a36Sopenharmony_ci struct fract hsub[3]; 4662306a36Sopenharmony_ci struct fract vsub[3]; 4762306a36Sopenharmony_ci unsigned int bpp[3]; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic const struct camss_format_info formats_rdi_8x16[] = { 5162306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 5262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 5362306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 5462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 5562306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 5662306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 5762306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 5862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 5962306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, 6062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 6162306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, 6262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 6362306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, 6462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 6562306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, 6662306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 6762306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, 6862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 6962306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, 7062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 7162306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, 7262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 7362306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, 7462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 7562306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, 7662306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 7762306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, 7862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 7962306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, 8062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 8162306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, 8262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 8362306a36Sopenharmony_ci { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, 8462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic const struct camss_format_info formats_rdi_8x96[] = { 8862306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 8962306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 9062306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 9162306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 9262306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 9362306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 9462306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 9562306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 9662306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, 9762306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 9862306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, 9962306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 10062306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, 10162306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 10262306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, 10362306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 10462306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, 10562306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 10662306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, 10762306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 10862306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, 10962306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 11062306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, 11162306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 11262306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1, 11362306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 11462306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, 11562306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 11662306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, 11762306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 11862306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, 11962306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 12062306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, 12162306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 12262306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1, 12362306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 12462306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1, 12562306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 12662306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1, 12762306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 12862306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1, 12962306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 13062306a36Sopenharmony_ci { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, 13162306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 13262306a36Sopenharmony_ci { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1, 13362306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic const struct camss_format_info formats_rdi_845[] = { 13762306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 13862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 13962306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 14062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 14162306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 14262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 14362306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 14462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 14562306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, 14662306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 14762306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, 14862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 14962306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, 15062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 15162306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, 15262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 15362306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, 15462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 15562306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, 15662306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 15762306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, 15862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 15962306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, 16062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 16162306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1, 16262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 16362306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, 16462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 16562306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, 16662306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 16762306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, 16862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 16962306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, 17062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 17162306a36Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1, 17262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 17362306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1, 17462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 17562306a36Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1, 17662306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 17762306a36Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1, 17862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 17962306a36Sopenharmony_ci { MEDIA_BUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 1, 18062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 18162306a36Sopenharmony_ci { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, 18262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 18362306a36Sopenharmony_ci { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1, 18462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 18562306a36Sopenharmony_ci}; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic const struct camss_format_info formats_pix_8x16[] = { 18862306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, 18962306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 19062306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, 19162306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 19262306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 19362306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 19462306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 19562306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 19662306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1, 19762306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 19862306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1, 19962306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 20062306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 20162306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 20262306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 20362306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 20462306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, 20562306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 20662306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, 20762306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 20862306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, 20962306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 21062306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, 21162306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 21262306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, 21362306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 21462306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, 21562306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 21662306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, 21762306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 21862306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, 21962306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 22062306a36Sopenharmony_ci}; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic const struct camss_format_info formats_pix_8x96[] = { 22362306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, 22462306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 22562306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, 22662306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 22762306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 22862306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 22962306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 23062306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 23162306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1, 23262306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 23362306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1, 23462306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 23562306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 23662306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 23762306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 23862306a36Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 23962306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, 24062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 24162306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, 24262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 24362306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, 24462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 24562306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, 24662306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 24762306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, 24862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 24962306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, 25062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 25162306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, 25262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 25362306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, 25462306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 25562306a36Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 25662306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 25762306a36Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 25862306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 25962306a36Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 26062306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 26162306a36Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 26262306a36Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 26362306a36Sopenharmony_ci}; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 26662306a36Sopenharmony_ci * Helper functions 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int video_find_format(u32 code, u32 pixelformat, 27062306a36Sopenharmony_ci const struct camss_format_info *formats, 27162306a36Sopenharmony_ci unsigned int nformats) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci int i; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci for (i = 0; i < nformats; i++) { 27662306a36Sopenharmony_ci if (formats[i].code == code && 27762306a36Sopenharmony_ci formats[i].pixelformat == pixelformat) 27862306a36Sopenharmony_ci return i; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci for (i = 0; i < nformats; i++) 28262306a36Sopenharmony_ci if (formats[i].code == code) 28362306a36Sopenharmony_ci return i; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci WARN_ON(1); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return -EINVAL; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci/* 29162306a36Sopenharmony_ci * video_mbus_to_pix_mp - Convert v4l2_mbus_framefmt to v4l2_pix_format_mplane 29262306a36Sopenharmony_ci * @mbus: v4l2_mbus_framefmt format (input) 29362306a36Sopenharmony_ci * @pix: v4l2_pix_format_mplane format (output) 29462306a36Sopenharmony_ci * @f: a pointer to formats array element to be used for the conversion 29562306a36Sopenharmony_ci * @alignment: bytesperline alignment value 29662306a36Sopenharmony_ci * 29762306a36Sopenharmony_ci * Fill the output pix structure with information from the input mbus format. 29862306a36Sopenharmony_ci * 29962306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_cistatic int video_mbus_to_pix_mp(const struct v4l2_mbus_framefmt *mbus, 30262306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix, 30362306a36Sopenharmony_ci const struct camss_format_info *f, 30462306a36Sopenharmony_ci unsigned int alignment) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci unsigned int i; 30762306a36Sopenharmony_ci u32 bytesperline; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci memset(pix, 0, sizeof(*pix)); 31062306a36Sopenharmony_ci v4l2_fill_pix_format_mplane(pix, mbus); 31162306a36Sopenharmony_ci pix->pixelformat = f->pixelformat; 31262306a36Sopenharmony_ci pix->num_planes = f->planes; 31362306a36Sopenharmony_ci for (i = 0; i < pix->num_planes; i++) { 31462306a36Sopenharmony_ci bytesperline = pix->width / f->hsub[i].numerator * 31562306a36Sopenharmony_ci f->hsub[i].denominator * f->bpp[i] / 8; 31662306a36Sopenharmony_ci bytesperline = ALIGN(bytesperline, alignment); 31762306a36Sopenharmony_ci pix->plane_fmt[i].bytesperline = bytesperline; 31862306a36Sopenharmony_ci pix->plane_fmt[i].sizeimage = pix->height / 31962306a36Sopenharmony_ci f->vsub[i].numerator * f->vsub[i].denominator * 32062306a36Sopenharmony_ci bytesperline; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic struct v4l2_subdev *video_remote_subdev(struct camss_video *video, 32762306a36Sopenharmony_ci u32 *pad) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct media_pad *remote; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci remote = media_pad_remote_pad_first(&video->pad); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) 33462306a36Sopenharmony_ci return NULL; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (pad) 33762306a36Sopenharmony_ci *pad = remote->index; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return media_entity_to_v4l2_subdev(remote->entity); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int video_get_subdev_format(struct camss_video *video, 34362306a36Sopenharmony_ci struct v4l2_format *format) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct v4l2_subdev_format fmt = { 34662306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 34762306a36Sopenharmony_ci }; 34862306a36Sopenharmony_ci struct v4l2_subdev *subdev; 34962306a36Sopenharmony_ci u32 pad; 35062306a36Sopenharmony_ci int ret; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci subdev = video_remote_subdev(video, &pad); 35362306a36Sopenharmony_ci if (subdev == NULL) 35462306a36Sopenharmony_ci return -EPIPE; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci fmt.pad = pad; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); 35962306a36Sopenharmony_ci if (ret) 36062306a36Sopenharmony_ci return ret; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci ret = video_find_format(fmt.format.code, 36362306a36Sopenharmony_ci format->fmt.pix_mp.pixelformat, 36462306a36Sopenharmony_ci video->formats, video->nformats); 36562306a36Sopenharmony_ci if (ret < 0) 36662306a36Sopenharmony_ci return ret; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci format->type = video->type; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp, 37162306a36Sopenharmony_ci &video->formats[ret], video->bpl_alignment); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 37562306a36Sopenharmony_ci * Video queue operations 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic int video_queue_setup(struct vb2_queue *q, 37962306a36Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 38062306a36Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(q); 38362306a36Sopenharmony_ci const struct v4l2_pix_format_mplane *format = 38462306a36Sopenharmony_ci &video->active_fmt.fmt.pix_mp; 38562306a36Sopenharmony_ci unsigned int i; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (*num_planes) { 38862306a36Sopenharmony_ci if (*num_planes != format->num_planes) 38962306a36Sopenharmony_ci return -EINVAL; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci for (i = 0; i < *num_planes; i++) 39262306a36Sopenharmony_ci if (sizes[i] < format->plane_fmt[i].sizeimage) 39362306a36Sopenharmony_ci return -EINVAL; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci return 0; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci *num_planes = format->num_planes; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci for (i = 0; i < *num_planes; i++) 40162306a36Sopenharmony_ci sizes[i] = format->plane_fmt[i].sizeimage; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int video_buf_init(struct vb2_buffer *vb) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 40962306a36Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); 41062306a36Sopenharmony_ci struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, 41162306a36Sopenharmony_ci vb); 41262306a36Sopenharmony_ci const struct v4l2_pix_format_mplane *format = 41362306a36Sopenharmony_ci &video->active_fmt.fmt.pix_mp; 41462306a36Sopenharmony_ci struct sg_table *sgt; 41562306a36Sopenharmony_ci unsigned int i; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci for (i = 0; i < format->num_planes; i++) { 41862306a36Sopenharmony_ci sgt = vb2_dma_sg_plane_desc(vb, i); 41962306a36Sopenharmony_ci if (!sgt) 42062306a36Sopenharmony_ci return -EFAULT; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci buffer->addr[i] = sg_dma_address(sgt->sgl); 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (format->pixelformat == V4L2_PIX_FMT_NV12 || 42662306a36Sopenharmony_ci format->pixelformat == V4L2_PIX_FMT_NV21 || 42762306a36Sopenharmony_ci format->pixelformat == V4L2_PIX_FMT_NV16 || 42862306a36Sopenharmony_ci format->pixelformat == V4L2_PIX_FMT_NV61) 42962306a36Sopenharmony_ci buffer->addr[1] = buffer->addr[0] + 43062306a36Sopenharmony_ci format->plane_fmt[0].bytesperline * 43162306a36Sopenharmony_ci format->height; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return 0; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int video_buf_prepare(struct vb2_buffer *vb) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 43962306a36Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); 44062306a36Sopenharmony_ci const struct v4l2_pix_format_mplane *format = 44162306a36Sopenharmony_ci &video->active_fmt.fmt.pix_mp; 44262306a36Sopenharmony_ci unsigned int i; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci for (i = 0; i < format->num_planes; i++) { 44562306a36Sopenharmony_ci if (format->plane_fmt[i].sizeimage > vb2_plane_size(vb, i)) 44662306a36Sopenharmony_ci return -EINVAL; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci vb2_set_plane_payload(vb, i, format->plane_fmt[i].sizeimage); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void video_buf_queue(struct vb2_buffer *vb) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 45962306a36Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); 46062306a36Sopenharmony_ci struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, 46162306a36Sopenharmony_ci vb); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci video->ops->queue_buffer(video, buffer); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int video_check_format(struct camss_video *video) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix = &video->active_fmt.fmt.pix_mp; 46962306a36Sopenharmony_ci struct v4l2_format format; 47062306a36Sopenharmony_ci struct v4l2_pix_format_mplane *sd_pix = &format.fmt.pix_mp; 47162306a36Sopenharmony_ci int ret; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci sd_pix->pixelformat = pix->pixelformat; 47462306a36Sopenharmony_ci ret = video_get_subdev_format(video, &format); 47562306a36Sopenharmony_ci if (ret < 0) 47662306a36Sopenharmony_ci return ret; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (pix->pixelformat != sd_pix->pixelformat || 47962306a36Sopenharmony_ci pix->height != sd_pix->height || 48062306a36Sopenharmony_ci pix->width != sd_pix->width || 48162306a36Sopenharmony_ci pix->num_planes != sd_pix->num_planes || 48262306a36Sopenharmony_ci pix->field != format.fmt.pix_mp.field) 48362306a36Sopenharmony_ci return -EPIPE; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int video_start_streaming(struct vb2_queue *q, unsigned int count) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(q); 49162306a36Sopenharmony_ci struct video_device *vdev = &video->vdev; 49262306a36Sopenharmony_ci struct media_entity *entity; 49362306a36Sopenharmony_ci struct media_pad *pad; 49462306a36Sopenharmony_ci struct v4l2_subdev *subdev; 49562306a36Sopenharmony_ci int ret; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci ret = video_device_pipeline_alloc_start(vdev); 49862306a36Sopenharmony_ci if (ret < 0) { 49962306a36Sopenharmony_ci dev_err(video->camss->dev, "Failed to start media pipeline: %d\n", ret); 50062306a36Sopenharmony_ci goto flush_buffers; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci ret = video_check_format(video); 50462306a36Sopenharmony_ci if (ret < 0) 50562306a36Sopenharmony_ci goto error; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci entity = &vdev->entity; 50862306a36Sopenharmony_ci while (1) { 50962306a36Sopenharmony_ci pad = &entity->pads[0]; 51062306a36Sopenharmony_ci if (!(pad->flags & MEDIA_PAD_FL_SINK)) 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci pad = media_pad_remote_pad_first(pad); 51462306a36Sopenharmony_ci if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci entity = pad->entity; 51862306a36Sopenharmony_ci subdev = media_entity_to_v4l2_subdev(entity); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci ret = v4l2_subdev_call(subdev, video, s_stream, 1); 52162306a36Sopenharmony_ci if (ret < 0 && ret != -ENOIOCTLCMD) 52262306a36Sopenharmony_ci goto error; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cierror: 52862306a36Sopenharmony_ci video_device_pipeline_stop(vdev); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ciflush_buffers: 53162306a36Sopenharmony_ci video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return ret; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic void video_stop_streaming(struct vb2_queue *q) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(q); 53962306a36Sopenharmony_ci struct video_device *vdev = &video->vdev; 54062306a36Sopenharmony_ci struct media_entity *entity; 54162306a36Sopenharmony_ci struct media_pad *pad; 54262306a36Sopenharmony_ci struct v4l2_subdev *subdev; 54362306a36Sopenharmony_ci int ret; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci entity = &vdev->entity; 54662306a36Sopenharmony_ci while (1) { 54762306a36Sopenharmony_ci pad = &entity->pads[0]; 54862306a36Sopenharmony_ci if (!(pad->flags & MEDIA_PAD_FL_SINK)) 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci pad = media_pad_remote_pad_first(pad); 55262306a36Sopenharmony_ci if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci entity = pad->entity; 55662306a36Sopenharmony_ci subdev = media_entity_to_v4l2_subdev(entity); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci ret = v4l2_subdev_call(subdev, video, s_stream, 0); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (entity->use_count > 1) { 56162306a36Sopenharmony_ci /* Don't stop if other instances of the pipeline are still running */ 56262306a36Sopenharmony_ci dev_dbg(video->camss->dev, "Video pipeline still used, don't stop streaming.\n"); 56362306a36Sopenharmony_ci return; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (ret) { 56762306a36Sopenharmony_ci dev_err(video->camss->dev, "Video pipeline stop failed: %d\n", ret); 56862306a36Sopenharmony_ci return; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci video_device_pipeline_stop(vdev); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic const struct vb2_ops msm_video_vb2_q_ops = { 57862306a36Sopenharmony_ci .queue_setup = video_queue_setup, 57962306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 58062306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 58162306a36Sopenharmony_ci .buf_init = video_buf_init, 58262306a36Sopenharmony_ci .buf_prepare = video_buf_prepare, 58362306a36Sopenharmony_ci .buf_queue = video_buf_queue, 58462306a36Sopenharmony_ci .start_streaming = video_start_streaming, 58562306a36Sopenharmony_ci .stop_streaming = video_stop_streaming, 58662306a36Sopenharmony_ci}; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 58962306a36Sopenharmony_ci * V4L2 ioctls 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic int video_querycap(struct file *file, void *fh, 59362306a36Sopenharmony_ci struct v4l2_capability *cap) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci strscpy(cap->driver, "qcom-camss", sizeof(cap->driver)); 59662306a36Sopenharmony_ci strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card)); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct camss_video *video = video_drvdata(file); 60462306a36Sopenharmony_ci int i, j, k; 60562306a36Sopenharmony_ci u32 mcode = f->mbus_code; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (f->type != video->type) 60862306a36Sopenharmony_ci return -EINVAL; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (f->index >= video->nformats) 61162306a36Sopenharmony_ci return -EINVAL; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* 61462306a36Sopenharmony_ci * Find index "i" of "k"th unique pixelformat in formats array. 61562306a36Sopenharmony_ci * 61662306a36Sopenharmony_ci * If f->mbus_code passed to video_enum_fmt() is not zero, a device 61762306a36Sopenharmony_ci * with V4L2_CAP_IO_MC capability restricts enumeration to only the 61862306a36Sopenharmony_ci * pixel formats that can be produced from that media bus code. 61962306a36Sopenharmony_ci * This is implemented by skipping video->formats[] entries with 62062306a36Sopenharmony_ci * code != f->mbus_code (if f->mbus_code is not zero). 62162306a36Sopenharmony_ci * If the f->mbus_code passed to video_enum_fmt() is not supported, 62262306a36Sopenharmony_ci * -EINVAL is returned. 62362306a36Sopenharmony_ci * If f->mbus_code is zero, all the pixel formats are enumerated. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci k = -1; 62662306a36Sopenharmony_ci for (i = 0; i < video->nformats; i++) { 62762306a36Sopenharmony_ci if (mcode != 0 && video->formats[i].code != mcode) 62862306a36Sopenharmony_ci continue; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci for (j = 0; j < i; j++) { 63162306a36Sopenharmony_ci if (mcode != 0 && video->formats[j].code != mcode) 63262306a36Sopenharmony_ci continue; 63362306a36Sopenharmony_ci if (video->formats[i].pixelformat == 63462306a36Sopenharmony_ci video->formats[j].pixelformat) 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (j == i) 63962306a36Sopenharmony_ci k++; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (k == f->index) 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (k == -1 || k < f->index) 64662306a36Sopenharmony_ci /* 64762306a36Sopenharmony_ci * All the unique pixel formats matching the arguments 64862306a36Sopenharmony_ci * have been enumerated (k >= 0 and f->index > 0), or 64962306a36Sopenharmony_ci * no pixel formats match the non-zero f->mbus_code (k == -1). 65062306a36Sopenharmony_ci */ 65162306a36Sopenharmony_ci return -EINVAL; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci f->pixelformat = video->formats[i].pixelformat; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return 0; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic int video_enum_framesizes(struct file *file, void *fh, 65962306a36Sopenharmony_ci struct v4l2_frmsizeenum *fsize) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct camss_video *video = video_drvdata(file); 66262306a36Sopenharmony_ci int i; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (fsize->index) 66562306a36Sopenharmony_ci return -EINVAL; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* Only accept pixel format present in the formats[] table */ 66862306a36Sopenharmony_ci for (i = 0; i < video->nformats; i++) { 66962306a36Sopenharmony_ci if (video->formats[i].pixelformat == fsize->pixel_format) 67062306a36Sopenharmony_ci break; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (i == video->nformats) 67462306a36Sopenharmony_ci return -EINVAL; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; 67762306a36Sopenharmony_ci fsize->stepwise.min_width = CAMSS_FRAME_MIN_WIDTH; 67862306a36Sopenharmony_ci fsize->stepwise.max_width = CAMSS_FRAME_MAX_WIDTH; 67962306a36Sopenharmony_ci fsize->stepwise.min_height = CAMSS_FRAME_MIN_HEIGHT; 68062306a36Sopenharmony_ci fsize->stepwise.max_height = (video->line_based) ? 68162306a36Sopenharmony_ci CAMSS_FRAME_MAX_HEIGHT_PIX : CAMSS_FRAME_MAX_HEIGHT_RDI; 68262306a36Sopenharmony_ci fsize->stepwise.step_width = 1; 68362306a36Sopenharmony_ci fsize->stepwise.step_height = 1; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci return 0; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct camss_video *video = video_drvdata(file); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci *f = video->active_fmt; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci return 0; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic int __video_try_fmt(struct camss_video *video, struct v4l2_format *f) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp; 70062306a36Sopenharmony_ci const struct camss_format_info *fi; 70162306a36Sopenharmony_ci struct v4l2_plane_pix_format *p; 70262306a36Sopenharmony_ci u32 bytesperline[3] = { 0 }; 70362306a36Sopenharmony_ci u32 sizeimage[3] = { 0 }; 70462306a36Sopenharmony_ci u32 width, height; 70562306a36Sopenharmony_ci u32 bpl, lines; 70662306a36Sopenharmony_ci int i, j; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci pix_mp = &f->fmt.pix_mp; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (video->line_based) 71162306a36Sopenharmony_ci for (i = 0; i < pix_mp->num_planes && i < 3; i++) { 71262306a36Sopenharmony_ci p = &pix_mp->plane_fmt[i]; 71362306a36Sopenharmony_ci bytesperline[i] = clamp_t(u32, p->bytesperline, 71462306a36Sopenharmony_ci 1, 65528); 71562306a36Sopenharmony_ci sizeimage[i] = clamp_t(u32, p->sizeimage, 71662306a36Sopenharmony_ci bytesperline[i], 71762306a36Sopenharmony_ci bytesperline[i] * CAMSS_FRAME_MAX_HEIGHT_PIX); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci for (j = 0; j < video->nformats; j++) 72162306a36Sopenharmony_ci if (pix_mp->pixelformat == video->formats[j].pixelformat) 72262306a36Sopenharmony_ci break; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (j == video->nformats) 72562306a36Sopenharmony_ci j = 0; /* default format */ 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci fi = &video->formats[j]; 72862306a36Sopenharmony_ci width = pix_mp->width; 72962306a36Sopenharmony_ci height = pix_mp->height; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci memset(pix_mp, 0, sizeof(*pix_mp)); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci pix_mp->pixelformat = fi->pixelformat; 73462306a36Sopenharmony_ci pix_mp->width = clamp_t(u32, width, 1, CAMSS_FRAME_MAX_WIDTH); 73562306a36Sopenharmony_ci pix_mp->height = clamp_t(u32, height, 1, CAMSS_FRAME_MAX_HEIGHT_RDI); 73662306a36Sopenharmony_ci pix_mp->num_planes = fi->planes; 73762306a36Sopenharmony_ci for (i = 0; i < pix_mp->num_planes; i++) { 73862306a36Sopenharmony_ci bpl = pix_mp->width / fi->hsub[i].numerator * 73962306a36Sopenharmony_ci fi->hsub[i].denominator * fi->bpp[i] / 8; 74062306a36Sopenharmony_ci bpl = ALIGN(bpl, video->bpl_alignment); 74162306a36Sopenharmony_ci pix_mp->plane_fmt[i].bytesperline = bpl; 74262306a36Sopenharmony_ci pix_mp->plane_fmt[i].sizeimage = pix_mp->height / 74362306a36Sopenharmony_ci fi->vsub[i].numerator * fi->vsub[i].denominator * bpl; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci pix_mp->field = V4L2_FIELD_NONE; 74762306a36Sopenharmony_ci pix_mp->colorspace = V4L2_COLORSPACE_SRGB; 74862306a36Sopenharmony_ci pix_mp->flags = 0; 74962306a36Sopenharmony_ci pix_mp->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix_mp->colorspace); 75062306a36Sopenharmony_ci pix_mp->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, 75162306a36Sopenharmony_ci pix_mp->colorspace, pix_mp->ycbcr_enc); 75262306a36Sopenharmony_ci pix_mp->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix_mp->colorspace); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (video->line_based) 75562306a36Sopenharmony_ci for (i = 0; i < pix_mp->num_planes; i++) { 75662306a36Sopenharmony_ci p = &pix_mp->plane_fmt[i]; 75762306a36Sopenharmony_ci p->bytesperline = clamp_t(u32, p->bytesperline, 75862306a36Sopenharmony_ci 1, 65528); 75962306a36Sopenharmony_ci p->sizeimage = clamp_t(u32, p->sizeimage, 76062306a36Sopenharmony_ci p->bytesperline, 76162306a36Sopenharmony_ci p->bytesperline * CAMSS_FRAME_MAX_HEIGHT_PIX); 76262306a36Sopenharmony_ci lines = p->sizeimage / p->bytesperline; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (p->bytesperline < bytesperline[i]) 76562306a36Sopenharmony_ci p->bytesperline = ALIGN(bytesperline[i], 8); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (p->sizeimage < p->bytesperline * lines) 76862306a36Sopenharmony_ci p->sizeimage = p->bytesperline * lines; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (p->sizeimage < sizeimage[i]) 77162306a36Sopenharmony_ci p->sizeimage = sizeimage[i]; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return 0; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct camss_video *video = video_drvdata(file); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return __video_try_fmt(video, f); 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct camss_video *video = video_drvdata(file); 78762306a36Sopenharmony_ci int ret; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (vb2_is_busy(&video->vb2_q)) 79062306a36Sopenharmony_ci return -EBUSY; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci ret = __video_try_fmt(video, f); 79362306a36Sopenharmony_ci if (ret < 0) 79462306a36Sopenharmony_ci return ret; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci video->active_fmt = *f; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic int video_enum_input(struct file *file, void *fh, 80262306a36Sopenharmony_ci struct v4l2_input *input) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci if (input->index > 0) 80562306a36Sopenharmony_ci return -EINVAL; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci strscpy(input->name, "camera", sizeof(input->name)); 80862306a36Sopenharmony_ci input->type = V4L2_INPUT_TYPE_CAMERA; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci return 0; 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic int video_g_input(struct file *file, void *fh, unsigned int *input) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci *input = 0; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return 0; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic int video_s_input(struct file *file, void *fh, unsigned int input) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci return input == 0 ? 0 : -EINVAL; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { 82662306a36Sopenharmony_ci .vidioc_querycap = video_querycap, 82762306a36Sopenharmony_ci .vidioc_enum_fmt_vid_cap = video_enum_fmt, 82862306a36Sopenharmony_ci .vidioc_enum_framesizes = video_enum_framesizes, 82962306a36Sopenharmony_ci .vidioc_g_fmt_vid_cap_mplane = video_g_fmt, 83062306a36Sopenharmony_ci .vidioc_s_fmt_vid_cap_mplane = video_s_fmt, 83162306a36Sopenharmony_ci .vidioc_try_fmt_vid_cap_mplane = video_try_fmt, 83262306a36Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 83362306a36Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 83462306a36Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 83562306a36Sopenharmony_ci .vidioc_expbuf = vb2_ioctl_expbuf, 83662306a36Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 83762306a36Sopenharmony_ci .vidioc_create_bufs = vb2_ioctl_create_bufs, 83862306a36Sopenharmony_ci .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 83962306a36Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 84062306a36Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 84162306a36Sopenharmony_ci .vidioc_enum_input = video_enum_input, 84262306a36Sopenharmony_ci .vidioc_g_input = video_g_input, 84362306a36Sopenharmony_ci .vidioc_s_input = video_s_input, 84462306a36Sopenharmony_ci}; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 84762306a36Sopenharmony_ci * V4L2 file operations 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int video_open(struct file *file) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct video_device *vdev = video_devdata(file); 85362306a36Sopenharmony_ci struct camss_video *video = video_drvdata(file); 85462306a36Sopenharmony_ci struct v4l2_fh *vfh; 85562306a36Sopenharmony_ci int ret; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci mutex_lock(&video->lock); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); 86062306a36Sopenharmony_ci if (vfh == NULL) { 86162306a36Sopenharmony_ci ret = -ENOMEM; 86262306a36Sopenharmony_ci goto error_alloc; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci v4l2_fh_init(vfh, vdev); 86662306a36Sopenharmony_ci v4l2_fh_add(vfh); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci file->private_data = vfh; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci ret = v4l2_pipeline_pm_get(&vdev->entity); 87162306a36Sopenharmony_ci if (ret < 0) { 87262306a36Sopenharmony_ci dev_err(video->camss->dev, "Failed to power up pipeline: %d\n", 87362306a36Sopenharmony_ci ret); 87462306a36Sopenharmony_ci goto error_pm_use; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci mutex_unlock(&video->lock); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci return 0; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cierror_pm_use: 88262306a36Sopenharmony_ci v4l2_fh_release(file); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cierror_alloc: 88562306a36Sopenharmony_ci mutex_unlock(&video->lock); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return ret; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic int video_release(struct file *file) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci struct video_device *vdev = video_devdata(file); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci vb2_fop_release(file); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci v4l2_pipeline_pm_put(&vdev->entity); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci file->private_data = NULL; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return 0; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic const struct v4l2_file_operations msm_vid_fops = { 90462306a36Sopenharmony_ci .owner = THIS_MODULE, 90562306a36Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 90662306a36Sopenharmony_ci .open = video_open, 90762306a36Sopenharmony_ci .release = video_release, 90862306a36Sopenharmony_ci .poll = vb2_fop_poll, 90962306a36Sopenharmony_ci .mmap = vb2_fop_mmap, 91062306a36Sopenharmony_ci .read = vb2_fop_read, 91162306a36Sopenharmony_ci}; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 91462306a36Sopenharmony_ci * CAMSS video core 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistatic void msm_video_release(struct video_device *vdev) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci struct camss_video *video = video_get_drvdata(vdev); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci media_entity_cleanup(&vdev->entity); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci mutex_destroy(&video->q_lock); 92462306a36Sopenharmony_ci mutex_destroy(&video->lock); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (atomic_dec_and_test(&video->camss->ref_count)) 92762306a36Sopenharmony_ci camss_delete(video->camss); 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci/* 93162306a36Sopenharmony_ci * msm_video_init_format - Helper function to initialize format 93262306a36Sopenharmony_ci * @video: struct camss_video 93362306a36Sopenharmony_ci * 93462306a36Sopenharmony_ci * Initialize pad format with default value. 93562306a36Sopenharmony_ci * 93662306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_cistatic int msm_video_init_format(struct camss_video *video) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci int ret; 94162306a36Sopenharmony_ci struct v4l2_format format = { 94262306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 94362306a36Sopenharmony_ci .fmt.pix_mp = { 94462306a36Sopenharmony_ci .width = 1920, 94562306a36Sopenharmony_ci .height = 1080, 94662306a36Sopenharmony_ci .pixelformat = video->formats[0].pixelformat, 94762306a36Sopenharmony_ci }, 94862306a36Sopenharmony_ci }; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci ret = __video_try_fmt(video, &format); 95162306a36Sopenharmony_ci if (ret < 0) 95262306a36Sopenharmony_ci return ret; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci video->active_fmt = format; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return 0; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci/* 96062306a36Sopenharmony_ci * msm_video_register - Register a video device node 96162306a36Sopenharmony_ci * @video: struct camss_video 96262306a36Sopenharmony_ci * @v4l2_dev: V4L2 device 96362306a36Sopenharmony_ci * @name: name to be used for the video device node 96462306a36Sopenharmony_ci * 96562306a36Sopenharmony_ci * Initialize and register a video device node to a V4L2 device. Also 96662306a36Sopenharmony_ci * initialize the vb2 queue. 96762306a36Sopenharmony_ci * 96862306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 96962306a36Sopenharmony_ci */ 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ciint msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, 97262306a36Sopenharmony_ci const char *name, int is_pix) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci struct media_pad *pad = &video->pad; 97562306a36Sopenharmony_ci struct video_device *vdev; 97662306a36Sopenharmony_ci struct vb2_queue *q; 97762306a36Sopenharmony_ci int ret; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci vdev = &video->vdev; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci mutex_init(&video->q_lock); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci q = &video->vb2_q; 98462306a36Sopenharmony_ci q->drv_priv = video; 98562306a36Sopenharmony_ci q->mem_ops = &vb2_dma_sg_memops; 98662306a36Sopenharmony_ci q->ops = &msm_video_vb2_q_ops; 98762306a36Sopenharmony_ci q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 98862306a36Sopenharmony_ci q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ; 98962306a36Sopenharmony_ci q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 99062306a36Sopenharmony_ci q->buf_struct_size = sizeof(struct camss_buffer); 99162306a36Sopenharmony_ci q->dev = video->camss->dev; 99262306a36Sopenharmony_ci q->lock = &video->q_lock; 99362306a36Sopenharmony_ci ret = vb2_queue_init(q); 99462306a36Sopenharmony_ci if (ret < 0) { 99562306a36Sopenharmony_ci dev_err(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret); 99662306a36Sopenharmony_ci goto error_vb2_init; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci pad->flags = MEDIA_PAD_FL_SINK; 100062306a36Sopenharmony_ci ret = media_entity_pads_init(&vdev->entity, 1, pad); 100162306a36Sopenharmony_ci if (ret < 0) { 100262306a36Sopenharmony_ci dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n", 100362306a36Sopenharmony_ci ret); 100462306a36Sopenharmony_ci goto error_vb2_init; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci mutex_init(&video->lock); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (video->camss->version == CAMSS_8x16) { 101062306a36Sopenharmony_ci if (is_pix) { 101162306a36Sopenharmony_ci video->formats = formats_pix_8x16; 101262306a36Sopenharmony_ci video->nformats = ARRAY_SIZE(formats_pix_8x16); 101362306a36Sopenharmony_ci } else { 101462306a36Sopenharmony_ci video->formats = formats_rdi_8x16; 101562306a36Sopenharmony_ci video->nformats = ARRAY_SIZE(formats_rdi_8x16); 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci } else if (video->camss->version == CAMSS_8x96 || 101862306a36Sopenharmony_ci video->camss->version == CAMSS_660) { 101962306a36Sopenharmony_ci if (is_pix) { 102062306a36Sopenharmony_ci video->formats = formats_pix_8x96; 102162306a36Sopenharmony_ci video->nformats = ARRAY_SIZE(formats_pix_8x96); 102262306a36Sopenharmony_ci } else { 102362306a36Sopenharmony_ci video->formats = formats_rdi_8x96; 102462306a36Sopenharmony_ci video->nformats = ARRAY_SIZE(formats_rdi_8x96); 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci } else if (video->camss->version == CAMSS_845 || 102762306a36Sopenharmony_ci video->camss->version == CAMSS_8250) { 102862306a36Sopenharmony_ci video->formats = formats_rdi_845; 102962306a36Sopenharmony_ci video->nformats = ARRAY_SIZE(formats_rdi_845); 103062306a36Sopenharmony_ci } else { 103162306a36Sopenharmony_ci ret = -EINVAL; 103262306a36Sopenharmony_ci goto error_video_register; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci ret = msm_video_init_format(video); 103662306a36Sopenharmony_ci if (ret < 0) { 103762306a36Sopenharmony_ci dev_err(v4l2_dev->dev, "Failed to init format: %d\n", ret); 103862306a36Sopenharmony_ci goto error_video_register; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci vdev->fops = &msm_vid_fops; 104262306a36Sopenharmony_ci vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING 104362306a36Sopenharmony_ci | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC; 104462306a36Sopenharmony_ci vdev->ioctl_ops = &msm_vid_ioctl_ops; 104562306a36Sopenharmony_ci vdev->release = msm_video_release; 104662306a36Sopenharmony_ci vdev->v4l2_dev = v4l2_dev; 104762306a36Sopenharmony_ci vdev->vfl_dir = VFL_DIR_RX; 104862306a36Sopenharmony_ci vdev->queue = &video->vb2_q; 104962306a36Sopenharmony_ci vdev->lock = &video->lock; 105062306a36Sopenharmony_ci strscpy(vdev->name, name, sizeof(vdev->name)); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 105362306a36Sopenharmony_ci if (ret < 0) { 105462306a36Sopenharmony_ci dev_err(v4l2_dev->dev, "Failed to register video device: %d\n", 105562306a36Sopenharmony_ci ret); 105662306a36Sopenharmony_ci goto error_video_register; 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci video_set_drvdata(vdev, video); 106062306a36Sopenharmony_ci atomic_inc(&video->camss->ref_count); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cierror_video_register: 106562306a36Sopenharmony_ci media_entity_cleanup(&vdev->entity); 106662306a36Sopenharmony_ci mutex_destroy(&video->lock); 106762306a36Sopenharmony_cierror_vb2_init: 106862306a36Sopenharmony_ci mutex_destroy(&video->q_lock); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci return ret; 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_civoid msm_video_unregister(struct camss_video *video) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci atomic_inc(&video->camss->ref_count); 107662306a36Sopenharmony_ci vb2_video_unregister_device(&video->vdev); 107762306a36Sopenharmony_ci atomic_dec(&video->camss->ref_count); 107862306a36Sopenharmony_ci} 1079