18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * camss-video.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Qualcomm MSM Camera Subsystem - V4L2 device node 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. 88c2ecf20Sopenharmony_ci * Copyright (C) 2015-2018 Linaro Ltd. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <media/media-entity.h> 128c2ecf20Sopenharmony_ci#include <media/v4l2-dev.h> 138c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 148c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 158c2ecf20Sopenharmony_ci#include <media/v4l2-mc.h> 168c2ecf20Sopenharmony_ci#include <media/videobuf2-dma-sg.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "camss-video.h" 198c2ecf20Sopenharmony_ci#include "camss.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define CAMSS_FRAME_MIN_WIDTH 1 228c2ecf20Sopenharmony_ci#define CAMSS_FRAME_MAX_WIDTH 8191 238c2ecf20Sopenharmony_ci#define CAMSS_FRAME_MIN_HEIGHT 1 248c2ecf20Sopenharmony_ci#define CAMSS_FRAME_MAX_HEIGHT_RDI 8191 258c2ecf20Sopenharmony_ci#define CAMSS_FRAME_MAX_HEIGHT_PIX 4096 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct fract { 288c2ecf20Sopenharmony_ci u8 numerator; 298c2ecf20Sopenharmony_ci u8 denominator; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * struct camss_format_info - ISP media bus format information 348c2ecf20Sopenharmony_ci * @code: V4L2 media bus format code 358c2ecf20Sopenharmony_ci * @pixelformat: V4L2 pixel format FCC identifier 368c2ecf20Sopenharmony_ci * @planes: Number of planes 378c2ecf20Sopenharmony_ci * @hsub: Horizontal subsampling (for each plane) 388c2ecf20Sopenharmony_ci * @vsub: Vertical subsampling (for each plane) 398c2ecf20Sopenharmony_ci * @bpp: Bits per pixel when stored in memory (for each plane) 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistruct camss_format_info { 428c2ecf20Sopenharmony_ci u32 code; 438c2ecf20Sopenharmony_ci u32 pixelformat; 448c2ecf20Sopenharmony_ci u8 planes; 458c2ecf20Sopenharmony_ci struct fract hsub[3]; 468c2ecf20Sopenharmony_ci struct fract vsub[3]; 478c2ecf20Sopenharmony_ci unsigned int bpp[3]; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const struct camss_format_info formats_rdi_8x16[] = { 518c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 528c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 538c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 548c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 558c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 568c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 578c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 588c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 598c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, 608c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 618c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, 628c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 638c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, 648c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 658c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, 668c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 678c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, 688c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 698c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, 708c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 718c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, 728c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 738c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, 748c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 758c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, 768c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 778c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, 788c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 798c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, 808c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 818c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, 828c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 838c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, 848c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic const struct camss_format_info formats_rdi_8x96[] = { 888c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 898c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 908c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 918c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 928c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 938c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 948c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 958c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 968c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, 978c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 988c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, 998c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 1008c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, 1018c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 1028c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, 1038c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 1048c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, 1058c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 1068c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, 1078c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 1088c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, 1098c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 1108c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, 1118c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 1128c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1, 1138c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 1148c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, 1158c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 1168c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, 1178c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 1188c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, 1198c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 1208c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, 1218c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 1228c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1, 1238c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 1248c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1, 1258c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 1268c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1, 1278c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 1288c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1, 1298c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 1308c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, 1318c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 1328c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1, 1338c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic const struct camss_format_info formats_pix_8x16[] = { 1378c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, 1388c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1398c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, 1408c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1418c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 1428c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1438c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 1448c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1458c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1, 1468c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1478c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1, 1488c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1498c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 1508c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1518c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 1528c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1538c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, 1548c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1558c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, 1568c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1578c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, 1588c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1598c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, 1608c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1618c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, 1628c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1638c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, 1648c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1658c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, 1668c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1678c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, 1688c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic const struct camss_format_info formats_pix_8x96[] = { 1728c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, 1738c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1748c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, 1758c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1768c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 1778c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1788c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 1798c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1808c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1, 1818c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1828c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1, 1838c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1848c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 1858c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1868c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 1878c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 1888c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, 1898c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1908c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, 1918c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1928c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, 1938c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1948c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, 1958c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1968c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, 1978c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 1988c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, 1998c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 2008c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, 2018c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 2028c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, 2038c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 2048c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 2058c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 2068c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 2078c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 2088c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 2098c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 2108c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 2118c2ecf20Sopenharmony_ci { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 2128c2ecf20Sopenharmony_ci}; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 2158c2ecf20Sopenharmony_ci * Helper functions 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int video_find_format(u32 code, u32 pixelformat, 2198c2ecf20Sopenharmony_ci const struct camss_format_info *formats, 2208c2ecf20Sopenharmony_ci unsigned int nformats) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci int i; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = 0; i < nformats; i++) { 2258c2ecf20Sopenharmony_ci if (formats[i].code == code && 2268c2ecf20Sopenharmony_ci formats[i].pixelformat == pixelformat) 2278c2ecf20Sopenharmony_ci return i; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci for (i = 0; i < nformats; i++) 2318c2ecf20Sopenharmony_ci if (formats[i].code == code) 2328c2ecf20Sopenharmony_ci return i; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci WARN_ON(1); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return -EINVAL; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* 2408c2ecf20Sopenharmony_ci * video_mbus_to_pix_mp - Convert v4l2_mbus_framefmt to v4l2_pix_format_mplane 2418c2ecf20Sopenharmony_ci * @mbus: v4l2_mbus_framefmt format (input) 2428c2ecf20Sopenharmony_ci * @pix: v4l2_pix_format_mplane format (output) 2438c2ecf20Sopenharmony_ci * @f: a pointer to formats array element to be used for the conversion 2448c2ecf20Sopenharmony_ci * @alignment: bytesperline alignment value 2458c2ecf20Sopenharmony_ci * 2468c2ecf20Sopenharmony_ci * Fill the output pix structure with information from the input mbus format. 2478c2ecf20Sopenharmony_ci * 2488c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_cistatic int video_mbus_to_pix_mp(const struct v4l2_mbus_framefmt *mbus, 2518c2ecf20Sopenharmony_ci struct v4l2_pix_format_mplane *pix, 2528c2ecf20Sopenharmony_ci const struct camss_format_info *f, 2538c2ecf20Sopenharmony_ci unsigned int alignment) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci unsigned int i; 2568c2ecf20Sopenharmony_ci u32 bytesperline; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci memset(pix, 0, sizeof(*pix)); 2598c2ecf20Sopenharmony_ci v4l2_fill_pix_format_mplane(pix, mbus); 2608c2ecf20Sopenharmony_ci pix->pixelformat = f->pixelformat; 2618c2ecf20Sopenharmony_ci pix->num_planes = f->planes; 2628c2ecf20Sopenharmony_ci for (i = 0; i < pix->num_planes; i++) { 2638c2ecf20Sopenharmony_ci bytesperline = pix->width / f->hsub[i].numerator * 2648c2ecf20Sopenharmony_ci f->hsub[i].denominator * f->bpp[i] / 8; 2658c2ecf20Sopenharmony_ci bytesperline = ALIGN(bytesperline, alignment); 2668c2ecf20Sopenharmony_ci pix->plane_fmt[i].bytesperline = bytesperline; 2678c2ecf20Sopenharmony_ci pix->plane_fmt[i].sizeimage = pix->height / 2688c2ecf20Sopenharmony_ci f->vsub[i].numerator * f->vsub[i].denominator * 2698c2ecf20Sopenharmony_ci bytesperline; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic struct v4l2_subdev *video_remote_subdev(struct camss_video *video, 2768c2ecf20Sopenharmony_ci u32 *pad) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct media_pad *remote; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci remote = media_entity_remote_pad(&video->pad); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) 2838c2ecf20Sopenharmony_ci return NULL; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (pad) 2868c2ecf20Sopenharmony_ci *pad = remote->index; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return media_entity_to_v4l2_subdev(remote->entity); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int video_get_subdev_format(struct camss_video *video, 2928c2ecf20Sopenharmony_ci struct v4l2_format *format) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct v4l2_subdev_format fmt; 2958c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev; 2968c2ecf20Sopenharmony_ci u32 pad; 2978c2ecf20Sopenharmony_ci int ret; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci subdev = video_remote_subdev(video, &pad); 3008c2ecf20Sopenharmony_ci if (subdev == NULL) 3018c2ecf20Sopenharmony_ci return -EPIPE; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci fmt.pad = pad; 3048c2ecf20Sopenharmony_ci fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); 3078c2ecf20Sopenharmony_ci if (ret) 3088c2ecf20Sopenharmony_ci return ret; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ret = video_find_format(fmt.format.code, 3118c2ecf20Sopenharmony_ci format->fmt.pix_mp.pixelformat, 3128c2ecf20Sopenharmony_ci video->formats, video->nformats); 3138c2ecf20Sopenharmony_ci if (ret < 0) 3148c2ecf20Sopenharmony_ci return ret; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci format->type = video->type; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp, 3198c2ecf20Sopenharmony_ci &video->formats[ret], video->bpl_alignment); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 3238c2ecf20Sopenharmony_ci * Video queue operations 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int video_queue_setup(struct vb2_queue *q, 3278c2ecf20Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 3288c2ecf20Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(q); 3318c2ecf20Sopenharmony_ci const struct v4l2_pix_format_mplane *format = 3328c2ecf20Sopenharmony_ci &video->active_fmt.fmt.pix_mp; 3338c2ecf20Sopenharmony_ci unsigned int i; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (*num_planes) { 3368c2ecf20Sopenharmony_ci if (*num_planes != format->num_planes) 3378c2ecf20Sopenharmony_ci return -EINVAL; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci for (i = 0; i < *num_planes; i++) 3408c2ecf20Sopenharmony_ci if (sizes[i] < format->plane_fmt[i].sizeimage) 3418c2ecf20Sopenharmony_ci return -EINVAL; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci *num_planes = format->num_planes; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci for (i = 0; i < *num_planes; i++) 3498c2ecf20Sopenharmony_ci sizes[i] = format->plane_fmt[i].sizeimage; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int video_buf_init(struct vb2_buffer *vb) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 3578c2ecf20Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); 3588c2ecf20Sopenharmony_ci struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, 3598c2ecf20Sopenharmony_ci vb); 3608c2ecf20Sopenharmony_ci const struct v4l2_pix_format_mplane *format = 3618c2ecf20Sopenharmony_ci &video->active_fmt.fmt.pix_mp; 3628c2ecf20Sopenharmony_ci struct sg_table *sgt; 3638c2ecf20Sopenharmony_ci unsigned int i; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci for (i = 0; i < format->num_planes; i++) { 3668c2ecf20Sopenharmony_ci sgt = vb2_dma_sg_plane_desc(vb, i); 3678c2ecf20Sopenharmony_ci if (!sgt) 3688c2ecf20Sopenharmony_ci return -EFAULT; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci buffer->addr[i] = sg_dma_address(sgt->sgl); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (format->pixelformat == V4L2_PIX_FMT_NV12 || 3748c2ecf20Sopenharmony_ci format->pixelformat == V4L2_PIX_FMT_NV21 || 3758c2ecf20Sopenharmony_ci format->pixelformat == V4L2_PIX_FMT_NV16 || 3768c2ecf20Sopenharmony_ci format->pixelformat == V4L2_PIX_FMT_NV61) 3778c2ecf20Sopenharmony_ci buffer->addr[1] = buffer->addr[0] + 3788c2ecf20Sopenharmony_ci format->plane_fmt[0].bytesperline * 3798c2ecf20Sopenharmony_ci format->height; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int video_buf_prepare(struct vb2_buffer *vb) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 3878c2ecf20Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); 3888c2ecf20Sopenharmony_ci const struct v4l2_pix_format_mplane *format = 3898c2ecf20Sopenharmony_ci &video->active_fmt.fmt.pix_mp; 3908c2ecf20Sopenharmony_ci unsigned int i; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci for (i = 0; i < format->num_planes; i++) { 3938c2ecf20Sopenharmony_ci if (format->plane_fmt[i].sizeimage > vb2_plane_size(vb, i)) 3948c2ecf20Sopenharmony_ci return -EINVAL; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci vb2_set_plane_payload(vb, i, format->plane_fmt[i].sizeimage); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic void video_buf_queue(struct vb2_buffer *vb) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 4078c2ecf20Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); 4088c2ecf20Sopenharmony_ci struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, 4098c2ecf20Sopenharmony_ci vb); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci video->ops->queue_buffer(video, buffer); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int video_check_format(struct camss_video *video) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct v4l2_pix_format_mplane *pix = &video->active_fmt.fmt.pix_mp; 4178c2ecf20Sopenharmony_ci struct v4l2_format format; 4188c2ecf20Sopenharmony_ci struct v4l2_pix_format_mplane *sd_pix = &format.fmt.pix_mp; 4198c2ecf20Sopenharmony_ci int ret; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci sd_pix->pixelformat = pix->pixelformat; 4228c2ecf20Sopenharmony_ci ret = video_get_subdev_format(video, &format); 4238c2ecf20Sopenharmony_ci if (ret < 0) 4248c2ecf20Sopenharmony_ci return ret; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (pix->pixelformat != sd_pix->pixelformat || 4278c2ecf20Sopenharmony_ci pix->height != sd_pix->height || 4288c2ecf20Sopenharmony_ci pix->width != sd_pix->width || 4298c2ecf20Sopenharmony_ci pix->num_planes != sd_pix->num_planes || 4308c2ecf20Sopenharmony_ci pix->field != format.fmt.pix_mp.field) 4318c2ecf20Sopenharmony_ci return -EPIPE; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return 0; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int video_start_streaming(struct vb2_queue *q, unsigned int count) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(q); 4398c2ecf20Sopenharmony_ci struct video_device *vdev = &video->vdev; 4408c2ecf20Sopenharmony_ci struct media_entity *entity; 4418c2ecf20Sopenharmony_ci struct media_pad *pad; 4428c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev; 4438c2ecf20Sopenharmony_ci int ret; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci ret = media_pipeline_start(&vdev->entity, &video->pipe); 4468c2ecf20Sopenharmony_ci if (ret < 0) 4478c2ecf20Sopenharmony_ci goto flush_buffers; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci ret = video_check_format(video); 4508c2ecf20Sopenharmony_ci if (ret < 0) 4518c2ecf20Sopenharmony_ci goto error; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci entity = &vdev->entity; 4548c2ecf20Sopenharmony_ci while (1) { 4558c2ecf20Sopenharmony_ci pad = &entity->pads[0]; 4568c2ecf20Sopenharmony_ci if (!(pad->flags & MEDIA_PAD_FL_SINK)) 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci pad = media_entity_remote_pad(pad); 4608c2ecf20Sopenharmony_ci if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci entity = pad->entity; 4648c2ecf20Sopenharmony_ci subdev = media_entity_to_v4l2_subdev(entity); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci ret = v4l2_subdev_call(subdev, video, s_stream, 1); 4678c2ecf20Sopenharmony_ci if (ret < 0 && ret != -ENOIOCTLCMD) 4688c2ecf20Sopenharmony_ci goto error; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cierror: 4748c2ecf20Sopenharmony_ci media_pipeline_stop(&vdev->entity); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ciflush_buffers: 4778c2ecf20Sopenharmony_ci video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return ret; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic void video_stop_streaming(struct vb2_queue *q) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct camss_video *video = vb2_get_drv_priv(q); 4858c2ecf20Sopenharmony_ci struct video_device *vdev = &video->vdev; 4868c2ecf20Sopenharmony_ci struct media_entity *entity; 4878c2ecf20Sopenharmony_ci struct media_pad *pad; 4888c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci entity = &vdev->entity; 4918c2ecf20Sopenharmony_ci while (1) { 4928c2ecf20Sopenharmony_ci pad = &entity->pads[0]; 4938c2ecf20Sopenharmony_ci if (!(pad->flags & MEDIA_PAD_FL_SINK)) 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci pad = media_entity_remote_pad(pad); 4978c2ecf20Sopenharmony_ci if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci entity = pad->entity; 5018c2ecf20Sopenharmony_ci subdev = media_entity_to_v4l2_subdev(entity); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci v4l2_subdev_call(subdev, video, s_stream, 0); 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci media_pipeline_stop(&vdev->entity); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic const struct vb2_ops msm_video_vb2_q_ops = { 5128c2ecf20Sopenharmony_ci .queue_setup = video_queue_setup, 5138c2ecf20Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 5148c2ecf20Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 5158c2ecf20Sopenharmony_ci .buf_init = video_buf_init, 5168c2ecf20Sopenharmony_ci .buf_prepare = video_buf_prepare, 5178c2ecf20Sopenharmony_ci .buf_queue = video_buf_queue, 5188c2ecf20Sopenharmony_ci .start_streaming = video_start_streaming, 5198c2ecf20Sopenharmony_ci .stop_streaming = video_stop_streaming, 5208c2ecf20Sopenharmony_ci}; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 5238c2ecf20Sopenharmony_ci * V4L2 ioctls 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int video_querycap(struct file *file, void *fh, 5278c2ecf20Sopenharmony_ci struct v4l2_capability *cap) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct camss_video *video = video_drvdata(file); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci strscpy(cap->driver, "qcom-camss", sizeof(cap->driver)); 5328c2ecf20Sopenharmony_ci strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card)); 5338c2ecf20Sopenharmony_ci snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", 5348c2ecf20Sopenharmony_ci dev_name(video->camss->dev)); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci/* 5408c2ecf20Sopenharmony_ci * Returns the index in the video->formats[] array of the element which 5418c2ecf20Sopenharmony_ci * has the "ndx"th unique value of pixelformat field. 5428c2ecf20Sopenharmony_ci * If not found (no more unique pixelformat's) returns -EINVAL. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_cistatic int video_get_unique_pixelformat_by_index(struct camss_video *video, 5458c2ecf20Sopenharmony_ci int ndx) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci int i, j, k; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* find index "i" of "k"th unique pixelformat in formats array */ 5508c2ecf20Sopenharmony_ci k = -1; 5518c2ecf20Sopenharmony_ci for (i = 0; i < video->nformats; i++) { 5528c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 5538c2ecf20Sopenharmony_ci if (video->formats[i].pixelformat == 5548c2ecf20Sopenharmony_ci video->formats[j].pixelformat) 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (j == i) 5598c2ecf20Sopenharmony_ci k++; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (k == ndx) 5628c2ecf20Sopenharmony_ci return i; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return -EINVAL; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci/* 5698c2ecf20Sopenharmony_ci * Returns the index in the video->formats[] array of the element which 5708c2ecf20Sopenharmony_ci * has code equal to mcode. 5718c2ecf20Sopenharmony_ci * If not found returns -EINVAL. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_cistatic int video_get_pixelformat_by_mbus_code(struct camss_video *video, 5748c2ecf20Sopenharmony_ci u32 mcode) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci int i; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci for (i = 0; i < video->nformats; i++) { 5798c2ecf20Sopenharmony_ci if (video->formats[i].code == mcode) 5808c2ecf20Sopenharmony_ci return i; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return -EINVAL; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct camss_video *video = video_drvdata(file); 5898c2ecf20Sopenharmony_ci int i; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (f->type != video->type) 5928c2ecf20Sopenharmony_ci return -EINVAL; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (f->index >= video->nformats) 5958c2ecf20Sopenharmony_ci return -EINVAL; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (f->mbus_code) { 5988c2ecf20Sopenharmony_ci /* Each entry in formats[] table has unique mbus_code */ 5998c2ecf20Sopenharmony_ci if (f->index > 0) 6008c2ecf20Sopenharmony_ci return -EINVAL; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci i = video_get_pixelformat_by_mbus_code(video, f->mbus_code); 6038c2ecf20Sopenharmony_ci } else { 6048c2ecf20Sopenharmony_ci i = video_get_unique_pixelformat_by_index(video, f->index); 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (i < 0) 6088c2ecf20Sopenharmony_ci return -EINVAL; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci f->pixelformat = video->formats[i].pixelformat; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return 0; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int video_enum_framesizes(struct file *file, void *fh, 6168c2ecf20Sopenharmony_ci struct v4l2_frmsizeenum *fsize) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct camss_video *video = video_drvdata(file); 6198c2ecf20Sopenharmony_ci int i; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (fsize->index) 6228c2ecf20Sopenharmony_ci return -EINVAL; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Only accept pixel format present in the formats[] table */ 6258c2ecf20Sopenharmony_ci for (i = 0; i < video->nformats; i++) { 6268c2ecf20Sopenharmony_ci if (video->formats[i].pixelformat == fsize->pixel_format) 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (i == video->nformats) 6318c2ecf20Sopenharmony_ci return -EINVAL; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; 6348c2ecf20Sopenharmony_ci fsize->stepwise.min_width = CAMSS_FRAME_MIN_WIDTH; 6358c2ecf20Sopenharmony_ci fsize->stepwise.max_width = CAMSS_FRAME_MAX_WIDTH; 6368c2ecf20Sopenharmony_ci fsize->stepwise.min_height = CAMSS_FRAME_MIN_HEIGHT; 6378c2ecf20Sopenharmony_ci fsize->stepwise.max_height = (video->line_based) ? 6388c2ecf20Sopenharmony_ci CAMSS_FRAME_MAX_HEIGHT_PIX : CAMSS_FRAME_MAX_HEIGHT_RDI; 6398c2ecf20Sopenharmony_ci fsize->stepwise.step_width = 1; 6408c2ecf20Sopenharmony_ci fsize->stepwise.step_height = 1; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci return 0; 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci struct camss_video *video = video_drvdata(file); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci *f = video->active_fmt; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci return 0; 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic int __video_try_fmt(struct camss_video *video, struct v4l2_format *f) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp; 6578c2ecf20Sopenharmony_ci const struct camss_format_info *fi; 6588c2ecf20Sopenharmony_ci struct v4l2_plane_pix_format *p; 6598c2ecf20Sopenharmony_ci u32 bytesperline[3] = { 0 }; 6608c2ecf20Sopenharmony_ci u32 sizeimage[3] = { 0 }; 6618c2ecf20Sopenharmony_ci u32 width, height; 6628c2ecf20Sopenharmony_ci u32 bpl, lines; 6638c2ecf20Sopenharmony_ci int i, j; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci pix_mp = &f->fmt.pix_mp; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (video->line_based) 6688c2ecf20Sopenharmony_ci for (i = 0; i < pix_mp->num_planes && i < 3; i++) { 6698c2ecf20Sopenharmony_ci p = &pix_mp->plane_fmt[i]; 6708c2ecf20Sopenharmony_ci bytesperline[i] = clamp_t(u32, p->bytesperline, 6718c2ecf20Sopenharmony_ci 1, 65528); 6728c2ecf20Sopenharmony_ci sizeimage[i] = clamp_t(u32, p->sizeimage, 6738c2ecf20Sopenharmony_ci bytesperline[i], 6748c2ecf20Sopenharmony_ci bytesperline[i] * CAMSS_FRAME_MAX_HEIGHT_PIX); 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci for (j = 0; j < video->nformats; j++) 6788c2ecf20Sopenharmony_ci if (pix_mp->pixelformat == video->formats[j].pixelformat) 6798c2ecf20Sopenharmony_ci break; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (j == video->nformats) 6828c2ecf20Sopenharmony_ci j = 0; /* default format */ 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci fi = &video->formats[j]; 6858c2ecf20Sopenharmony_ci width = pix_mp->width; 6868c2ecf20Sopenharmony_ci height = pix_mp->height; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci memset(pix_mp, 0, sizeof(*pix_mp)); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci pix_mp->pixelformat = fi->pixelformat; 6918c2ecf20Sopenharmony_ci pix_mp->width = clamp_t(u32, width, 1, CAMSS_FRAME_MAX_WIDTH); 6928c2ecf20Sopenharmony_ci pix_mp->height = clamp_t(u32, height, 1, CAMSS_FRAME_MAX_HEIGHT_RDI); 6938c2ecf20Sopenharmony_ci pix_mp->num_planes = fi->planes; 6948c2ecf20Sopenharmony_ci for (i = 0; i < pix_mp->num_planes; i++) { 6958c2ecf20Sopenharmony_ci bpl = pix_mp->width / fi->hsub[i].numerator * 6968c2ecf20Sopenharmony_ci fi->hsub[i].denominator * fi->bpp[i] / 8; 6978c2ecf20Sopenharmony_ci bpl = ALIGN(bpl, video->bpl_alignment); 6988c2ecf20Sopenharmony_ci pix_mp->plane_fmt[i].bytesperline = bpl; 6998c2ecf20Sopenharmony_ci pix_mp->plane_fmt[i].sizeimage = pix_mp->height / 7008c2ecf20Sopenharmony_ci fi->vsub[i].numerator * fi->vsub[i].denominator * bpl; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci pix_mp->field = V4L2_FIELD_NONE; 7048c2ecf20Sopenharmony_ci pix_mp->colorspace = V4L2_COLORSPACE_SRGB; 7058c2ecf20Sopenharmony_ci pix_mp->flags = 0; 7068c2ecf20Sopenharmony_ci pix_mp->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix_mp->colorspace); 7078c2ecf20Sopenharmony_ci pix_mp->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, 7088c2ecf20Sopenharmony_ci pix_mp->colorspace, pix_mp->ycbcr_enc); 7098c2ecf20Sopenharmony_ci pix_mp->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix_mp->colorspace); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (video->line_based) 7128c2ecf20Sopenharmony_ci for (i = 0; i < pix_mp->num_planes; i++) { 7138c2ecf20Sopenharmony_ci p = &pix_mp->plane_fmt[i]; 7148c2ecf20Sopenharmony_ci p->bytesperline = clamp_t(u32, p->bytesperline, 7158c2ecf20Sopenharmony_ci 1, 65528); 7168c2ecf20Sopenharmony_ci p->sizeimage = clamp_t(u32, p->sizeimage, 7178c2ecf20Sopenharmony_ci p->bytesperline, 7188c2ecf20Sopenharmony_ci p->bytesperline * CAMSS_FRAME_MAX_HEIGHT_PIX); 7198c2ecf20Sopenharmony_ci lines = p->sizeimage / p->bytesperline; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (p->bytesperline < bytesperline[i]) 7228c2ecf20Sopenharmony_ci p->bytesperline = ALIGN(bytesperline[i], 8); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (p->sizeimage < p->bytesperline * lines) 7258c2ecf20Sopenharmony_ci p->sizeimage = p->bytesperline * lines; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (p->sizeimage < sizeimage[i]) 7288c2ecf20Sopenharmony_ci p->sizeimage = sizeimage[i]; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct camss_video *video = video_drvdata(file); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return __video_try_fmt(video, f); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct camss_video *video = video_drvdata(file); 7448c2ecf20Sopenharmony_ci int ret; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (vb2_is_busy(&video->vb2_q)) 7478c2ecf20Sopenharmony_ci return -EBUSY; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci ret = __video_try_fmt(video, f); 7508c2ecf20Sopenharmony_ci if (ret < 0) 7518c2ecf20Sopenharmony_ci return ret; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci video->active_fmt = *f; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci return 0; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic int video_enum_input(struct file *file, void *fh, 7598c2ecf20Sopenharmony_ci struct v4l2_input *input) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci if (input->index > 0) 7628c2ecf20Sopenharmony_ci return -EINVAL; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci strscpy(input->name, "camera", sizeof(input->name)); 7658c2ecf20Sopenharmony_ci input->type = V4L2_INPUT_TYPE_CAMERA; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci return 0; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic int video_g_input(struct file *file, void *fh, unsigned int *input) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci *input = 0; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci return 0; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic int video_s_input(struct file *file, void *fh, unsigned int input) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci return input == 0 ? 0 : -EINVAL; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { 7838c2ecf20Sopenharmony_ci .vidioc_querycap = video_querycap, 7848c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap = video_enum_fmt, 7858c2ecf20Sopenharmony_ci .vidioc_enum_framesizes = video_enum_framesizes, 7868c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap_mplane = video_g_fmt, 7878c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap_mplane = video_s_fmt, 7888c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap_mplane = video_try_fmt, 7898c2ecf20Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 7908c2ecf20Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 7918c2ecf20Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 7928c2ecf20Sopenharmony_ci .vidioc_expbuf = vb2_ioctl_expbuf, 7938c2ecf20Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 7948c2ecf20Sopenharmony_ci .vidioc_create_bufs = vb2_ioctl_create_bufs, 7958c2ecf20Sopenharmony_ci .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 7968c2ecf20Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 7978c2ecf20Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 7988c2ecf20Sopenharmony_ci .vidioc_enum_input = video_enum_input, 7998c2ecf20Sopenharmony_ci .vidioc_g_input = video_g_input, 8008c2ecf20Sopenharmony_ci .vidioc_s_input = video_s_input, 8018c2ecf20Sopenharmony_ci}; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 8048c2ecf20Sopenharmony_ci * V4L2 file operations 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic int video_open(struct file *file) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct video_device *vdev = video_devdata(file); 8108c2ecf20Sopenharmony_ci struct camss_video *video = video_drvdata(file); 8118c2ecf20Sopenharmony_ci struct v4l2_fh *vfh; 8128c2ecf20Sopenharmony_ci int ret; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci mutex_lock(&video->lock); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); 8178c2ecf20Sopenharmony_ci if (vfh == NULL) { 8188c2ecf20Sopenharmony_ci ret = -ENOMEM; 8198c2ecf20Sopenharmony_ci goto error_alloc; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci v4l2_fh_init(vfh, vdev); 8238c2ecf20Sopenharmony_ci v4l2_fh_add(vfh); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci file->private_data = vfh; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci ret = v4l2_pipeline_pm_get(&vdev->entity); 8288c2ecf20Sopenharmony_ci if (ret < 0) { 8298c2ecf20Sopenharmony_ci dev_err(video->camss->dev, "Failed to power up pipeline: %d\n", 8308c2ecf20Sopenharmony_ci ret); 8318c2ecf20Sopenharmony_ci goto error_pm_use; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci mutex_unlock(&video->lock); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci return 0; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cierror_pm_use: 8398c2ecf20Sopenharmony_ci v4l2_fh_release(file); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cierror_alloc: 8428c2ecf20Sopenharmony_ci mutex_unlock(&video->lock); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return ret; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic int video_release(struct file *file) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct video_device *vdev = video_devdata(file); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci vb2_fop_release(file); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci v4l2_pipeline_pm_put(&vdev->entity); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci file->private_data = NULL; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return 0; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations msm_vid_fops = { 8618c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 8628c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 8638c2ecf20Sopenharmony_ci .open = video_open, 8648c2ecf20Sopenharmony_ci .release = video_release, 8658c2ecf20Sopenharmony_ci .poll = vb2_fop_poll, 8668c2ecf20Sopenharmony_ci .mmap = vb2_fop_mmap, 8678c2ecf20Sopenharmony_ci .read = vb2_fop_read, 8688c2ecf20Sopenharmony_ci}; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 8718c2ecf20Sopenharmony_ci * CAMSS video core 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic void msm_video_release(struct video_device *vdev) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci struct camss_video *video = video_get_drvdata(vdev); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci media_entity_cleanup(&vdev->entity); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci mutex_destroy(&video->q_lock); 8818c2ecf20Sopenharmony_ci mutex_destroy(&video->lock); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&video->camss->ref_count)) 8848c2ecf20Sopenharmony_ci camss_delete(video->camss); 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci/* 8888c2ecf20Sopenharmony_ci * msm_video_init_format - Helper function to initialize format 8898c2ecf20Sopenharmony_ci * @video: struct camss_video 8908c2ecf20Sopenharmony_ci * 8918c2ecf20Sopenharmony_ci * Initialize pad format with default value. 8928c2ecf20Sopenharmony_ci * 8938c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 8948c2ecf20Sopenharmony_ci */ 8958c2ecf20Sopenharmony_cistatic int msm_video_init_format(struct camss_video *video) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci int ret; 8988c2ecf20Sopenharmony_ci struct v4l2_format format = { 8998c2ecf20Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 9008c2ecf20Sopenharmony_ci .fmt.pix_mp = { 9018c2ecf20Sopenharmony_ci .width = 1920, 9028c2ecf20Sopenharmony_ci .height = 1080, 9038c2ecf20Sopenharmony_ci .pixelformat = video->formats[0].pixelformat, 9048c2ecf20Sopenharmony_ci }, 9058c2ecf20Sopenharmony_ci }; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci ret = __video_try_fmt(video, &format); 9088c2ecf20Sopenharmony_ci if (ret < 0) 9098c2ecf20Sopenharmony_ci return ret; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci video->active_fmt = format; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return 0; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci/* 9178c2ecf20Sopenharmony_ci * msm_video_register - Register a video device node 9188c2ecf20Sopenharmony_ci * @video: struct camss_video 9198c2ecf20Sopenharmony_ci * @v4l2_dev: V4L2 device 9208c2ecf20Sopenharmony_ci * @name: name to be used for the video device node 9218c2ecf20Sopenharmony_ci * 9228c2ecf20Sopenharmony_ci * Initialize and register a video device node to a V4L2 device. Also 9238c2ecf20Sopenharmony_ci * initialize the vb2 queue. 9248c2ecf20Sopenharmony_ci * 9258c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ciint msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, 9298c2ecf20Sopenharmony_ci const char *name, int is_pix) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct media_pad *pad = &video->pad; 9328c2ecf20Sopenharmony_ci struct video_device *vdev; 9338c2ecf20Sopenharmony_ci struct vb2_queue *q; 9348c2ecf20Sopenharmony_ci int ret; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci vdev = &video->vdev; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci mutex_init(&video->q_lock); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci q = &video->vb2_q; 9418c2ecf20Sopenharmony_ci q->drv_priv = video; 9428c2ecf20Sopenharmony_ci q->mem_ops = &vb2_dma_sg_memops; 9438c2ecf20Sopenharmony_ci q->ops = &msm_video_vb2_q_ops; 9448c2ecf20Sopenharmony_ci q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 9458c2ecf20Sopenharmony_ci q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ; 9468c2ecf20Sopenharmony_ci q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 9478c2ecf20Sopenharmony_ci q->buf_struct_size = sizeof(struct camss_buffer); 9488c2ecf20Sopenharmony_ci q->dev = video->camss->dev; 9498c2ecf20Sopenharmony_ci q->lock = &video->q_lock; 9508c2ecf20Sopenharmony_ci ret = vb2_queue_init(q); 9518c2ecf20Sopenharmony_ci if (ret < 0) { 9528c2ecf20Sopenharmony_ci dev_err(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret); 9538c2ecf20Sopenharmony_ci goto error_vb2_init; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci pad->flags = MEDIA_PAD_FL_SINK; 9578c2ecf20Sopenharmony_ci ret = media_entity_pads_init(&vdev->entity, 1, pad); 9588c2ecf20Sopenharmony_ci if (ret < 0) { 9598c2ecf20Sopenharmony_ci dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n", 9608c2ecf20Sopenharmony_ci ret); 9618c2ecf20Sopenharmony_ci goto error_vb2_init; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci mutex_init(&video->lock); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (video->camss->version == CAMSS_8x16) { 9678c2ecf20Sopenharmony_ci if (is_pix) { 9688c2ecf20Sopenharmony_ci video->formats = formats_pix_8x16; 9698c2ecf20Sopenharmony_ci video->nformats = ARRAY_SIZE(formats_pix_8x16); 9708c2ecf20Sopenharmony_ci } else { 9718c2ecf20Sopenharmony_ci video->formats = formats_rdi_8x16; 9728c2ecf20Sopenharmony_ci video->nformats = ARRAY_SIZE(formats_rdi_8x16); 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci } else if (video->camss->version == CAMSS_8x96) { 9758c2ecf20Sopenharmony_ci if (is_pix) { 9768c2ecf20Sopenharmony_ci video->formats = formats_pix_8x96; 9778c2ecf20Sopenharmony_ci video->nformats = ARRAY_SIZE(formats_pix_8x96); 9788c2ecf20Sopenharmony_ci } else { 9798c2ecf20Sopenharmony_ci video->formats = formats_rdi_8x96; 9808c2ecf20Sopenharmony_ci video->nformats = ARRAY_SIZE(formats_rdi_8x96); 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci } else { 9838c2ecf20Sopenharmony_ci ret = -EINVAL; 9848c2ecf20Sopenharmony_ci goto error_video_register; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci ret = msm_video_init_format(video); 9888c2ecf20Sopenharmony_ci if (ret < 0) { 9898c2ecf20Sopenharmony_ci dev_err(v4l2_dev->dev, "Failed to init format: %d\n", ret); 9908c2ecf20Sopenharmony_ci goto error_video_register; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci vdev->fops = &msm_vid_fops; 9948c2ecf20Sopenharmony_ci vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING 9958c2ecf20Sopenharmony_ci | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC; 9968c2ecf20Sopenharmony_ci vdev->ioctl_ops = &msm_vid_ioctl_ops; 9978c2ecf20Sopenharmony_ci vdev->release = msm_video_release; 9988c2ecf20Sopenharmony_ci vdev->v4l2_dev = v4l2_dev; 9998c2ecf20Sopenharmony_ci vdev->vfl_dir = VFL_DIR_RX; 10008c2ecf20Sopenharmony_ci vdev->queue = &video->vb2_q; 10018c2ecf20Sopenharmony_ci vdev->lock = &video->lock; 10028c2ecf20Sopenharmony_ci strscpy(vdev->name, name, sizeof(vdev->name)); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 10058c2ecf20Sopenharmony_ci if (ret < 0) { 10068c2ecf20Sopenharmony_ci dev_err(v4l2_dev->dev, "Failed to register video device: %d\n", 10078c2ecf20Sopenharmony_ci ret); 10088c2ecf20Sopenharmony_ci goto error_video_register; 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci video_set_drvdata(vdev, video); 10128c2ecf20Sopenharmony_ci atomic_inc(&video->camss->ref_count); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci return 0; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_cierror_video_register: 10178c2ecf20Sopenharmony_ci media_entity_cleanup(&vdev->entity); 10188c2ecf20Sopenharmony_ci mutex_destroy(&video->lock); 10198c2ecf20Sopenharmony_cierror_vb2_init: 10208c2ecf20Sopenharmony_ci mutex_destroy(&video->q_lock); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci return ret; 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_civoid msm_video_unregister(struct camss_video *video) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci atomic_inc(&video->camss->ref_count); 10288c2ecf20Sopenharmony_ci vb2_video_unregister_device(&video->vdev); 10298c2ecf20Sopenharmony_ci atomic_dec(&video->camss->ref_count); 10308c2ecf20Sopenharmony_ci} 1031