18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Video for Linux Two 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * A generic video device interface for the LINUX operating system 68c2ecf20Sopenharmony_ci * using a set of device structures/vectors for low level operations. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file replaces the videodev.c file that comes with the 98c2ecf20Sopenharmony_ci * regular kernel distribution. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Author: Bill Dirks <bill@thedirks.org> 128c2ecf20Sopenharmony_ci * based on code by Alan Cox, <alan@cymru.net> 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * Video capture interface for Linux 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * A generic video device interface for the LINUX operating system 198c2ecf20Sopenharmony_ci * using a set of device structures/vectors for low level operations. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Author: Alan Cox, <alan@lxorguk.ukuu.org.uk> 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Fixes: 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * Video4linux 1/2 integration by Justin Schoeman 288c2ecf20Sopenharmony_ci * <justin@suntiger.ee.up.ac.za> 298c2ecf20Sopenharmony_ci * 2.4 PROCFS support ported from 2.4 kernels by 308c2ecf20Sopenharmony_ci * Iñaki García Etxebarria <garetxe@euskalnet.net> 318c2ecf20Sopenharmony_ci * Makefile fix by "W. Michael Petullo" <mike@flyn.org> 328c2ecf20Sopenharmony_ci * 2.4 devfs support ported from 2.4 kernels by 338c2ecf20Sopenharmony_ci * Dan Merillat <dan@merillat.org> 348c2ecf20Sopenharmony_ci * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman) 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/module.h> 388c2ecf20Sopenharmony_ci#include <linux/types.h> 398c2ecf20Sopenharmony_ci#include <linux/kernel.h> 408c2ecf20Sopenharmony_ci#include <linux/mm.h> 418c2ecf20Sopenharmony_ci#include <linux/string.h> 428c2ecf20Sopenharmony_ci#include <linux/errno.h> 438c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 448c2ecf20Sopenharmony_ci#include <asm/io.h> 458c2ecf20Sopenharmony_ci#include <asm/div64.h> 468c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 478c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 488c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * V 4 L 2 D R I V E R H E L P E R A P I 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * Video Standard Operations (contributed by Michael Schimek) 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* Helper functions for control handling */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Fill in a struct v4l2_queryctrl */ 658c2ecf20Sopenharmony_ciint v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _step, s32 _def) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci const char *name; 688c2ecf20Sopenharmony_ci s64 min = _min; 698c2ecf20Sopenharmony_ci s64 max = _max; 708c2ecf20Sopenharmony_ci u64 step = _step; 718c2ecf20Sopenharmony_ci s64 def = _def; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type, 748c2ecf20Sopenharmony_ci &min, &max, &step, &def, &qctrl->flags); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (name == NULL) 778c2ecf20Sopenharmony_ci return -EINVAL; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci qctrl->minimum = min; 808c2ecf20Sopenharmony_ci qctrl->maximum = max; 818c2ecf20Sopenharmony_ci qctrl->step = step; 828c2ecf20Sopenharmony_ci qctrl->default_value = def; 838c2ecf20Sopenharmony_ci qctrl->reserved[0] = qctrl->reserved[1] = 0; 848c2ecf20Sopenharmony_ci strscpy(qctrl->name, name, sizeof(qctrl->name)); 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(v4l2_ctrl_query_fill); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* Clamp x to be between min and max, aligned to a multiple of 2^align. min 908c2ecf20Sopenharmony_ci * and max don't have to be aligned, but there must be at least one valid 918c2ecf20Sopenharmony_ci * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples 928c2ecf20Sopenharmony_ci * of 16 between 17 and 31. */ 938c2ecf20Sopenharmony_cistatic unsigned int clamp_align(unsigned int x, unsigned int min, 948c2ecf20Sopenharmony_ci unsigned int max, unsigned int align) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci /* Bits that must be zero to be aligned */ 978c2ecf20Sopenharmony_ci unsigned int mask = ~((1 << align) - 1); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* Clamp to aligned min and max */ 1008c2ecf20Sopenharmony_ci x = clamp(x, (min + ~mask) & mask, max & mask); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Round to nearest aligned value */ 1038c2ecf20Sopenharmony_ci if (align) 1048c2ecf20Sopenharmony_ci x = (x + (1 << (align - 1))) & mask; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return x; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic unsigned int clamp_roundup(unsigned int x, unsigned int min, 1108c2ecf20Sopenharmony_ci unsigned int max, unsigned int alignment) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci x = clamp(x, min, max); 1138c2ecf20Sopenharmony_ci if (alignment) 1148c2ecf20Sopenharmony_ci x = round_up(x, alignment); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return x; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, 1208c2ecf20Sopenharmony_ci unsigned int walign, 1218c2ecf20Sopenharmony_ci u32 *h, unsigned int hmin, unsigned int hmax, 1228c2ecf20Sopenharmony_ci unsigned int halign, unsigned int salign) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci *w = clamp_align(*w, wmin, wmax, walign); 1258c2ecf20Sopenharmony_ci *h = clamp_align(*h, hmin, hmax, halign); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* Usually we don't need to align the size and are done now. */ 1288c2ecf20Sopenharmony_ci if (!salign) 1298c2ecf20Sopenharmony_ci return; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* How much alignment do we have? */ 1328c2ecf20Sopenharmony_ci walign = __ffs(*w); 1338c2ecf20Sopenharmony_ci halign = __ffs(*h); 1348c2ecf20Sopenharmony_ci /* Enough to satisfy the image alignment? */ 1358c2ecf20Sopenharmony_ci if (walign + halign < salign) { 1368c2ecf20Sopenharmony_ci /* Max walign where there is still a valid width */ 1378c2ecf20Sopenharmony_ci unsigned int wmaxa = __fls(wmax ^ (wmin - 1)); 1388c2ecf20Sopenharmony_ci /* Max halign where there is still a valid height */ 1398c2ecf20Sopenharmony_ci unsigned int hmaxa = __fls(hmax ^ (hmin - 1)); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* up the smaller alignment until we have enough */ 1428c2ecf20Sopenharmony_ci do { 1438c2ecf20Sopenharmony_ci if (halign >= hmaxa || 1448c2ecf20Sopenharmony_ci (walign <= halign && walign < wmaxa)) { 1458c2ecf20Sopenharmony_ci *w = clamp_align(*w, wmin, wmax, walign + 1); 1468c2ecf20Sopenharmony_ci walign = __ffs(*w); 1478c2ecf20Sopenharmony_ci } else { 1488c2ecf20Sopenharmony_ci *h = clamp_align(*h, hmin, hmax, halign + 1); 1498c2ecf20Sopenharmony_ci halign = __ffs(*h); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci } while (halign + walign < salign); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l_bound_align_image); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ciconst void * 1578c2ecf20Sopenharmony_ci__v4l2_find_nearest_size(const void *array, size_t array_size, 1588c2ecf20Sopenharmony_ci size_t entry_size, size_t width_offset, 1598c2ecf20Sopenharmony_ci size_t height_offset, s32 width, s32 height) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci u32 error, min_error = U32_MAX; 1628c2ecf20Sopenharmony_ci const void *best = NULL; 1638c2ecf20Sopenharmony_ci unsigned int i; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (!array) 1668c2ecf20Sopenharmony_ci return NULL; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci for (i = 0; i < array_size; i++, array += entry_size) { 1698c2ecf20Sopenharmony_ci const u32 *entry_width = array + width_offset; 1708c2ecf20Sopenharmony_ci const u32 *entry_height = array + height_offset; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci error = abs(*entry_width - width) + abs(*entry_height - height); 1738c2ecf20Sopenharmony_ci if (error > min_error) 1748c2ecf20Sopenharmony_ci continue; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci min_error = error; 1778c2ecf20Sopenharmony_ci best = array; 1788c2ecf20Sopenharmony_ci if (!error) 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return best; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__v4l2_find_nearest_size); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ciint v4l2_g_parm_cap(struct video_device *vdev, 1878c2ecf20Sopenharmony_ci struct v4l2_subdev *sd, struct v4l2_streamparm *a) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_interval ival = { 0 }; 1908c2ecf20Sopenharmony_ci int ret; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && 1938c2ecf20Sopenharmony_ci a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 1948c2ecf20Sopenharmony_ci return -EINVAL; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (vdev->device_caps & V4L2_CAP_READWRITE) 1978c2ecf20Sopenharmony_ci a->parm.capture.readbuffers = 2; 1988c2ecf20Sopenharmony_ci if (v4l2_subdev_has_op(sd, video, g_frame_interval)) 1998c2ecf20Sopenharmony_ci a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 2008c2ecf20Sopenharmony_ci ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival); 2018c2ecf20Sopenharmony_ci if (!ret) 2028c2ecf20Sopenharmony_ci a->parm.capture.timeperframe = ival.interval; 2038c2ecf20Sopenharmony_ci return ret; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_g_parm_cap); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ciint v4l2_s_parm_cap(struct video_device *vdev, 2088c2ecf20Sopenharmony_ci struct v4l2_subdev *sd, struct v4l2_streamparm *a) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_interval ival = { 2118c2ecf20Sopenharmony_ci .interval = a->parm.capture.timeperframe 2128c2ecf20Sopenharmony_ci }; 2138c2ecf20Sopenharmony_ci int ret; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && 2168c2ecf20Sopenharmony_ci a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 2178c2ecf20Sopenharmony_ci return -EINVAL; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci memset(&a->parm, 0, sizeof(a->parm)); 2208c2ecf20Sopenharmony_ci if (vdev->device_caps & V4L2_CAP_READWRITE) 2218c2ecf20Sopenharmony_ci a->parm.capture.readbuffers = 2; 2228c2ecf20Sopenharmony_ci else 2238c2ecf20Sopenharmony_ci a->parm.capture.readbuffers = 0; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (v4l2_subdev_has_op(sd, video, g_frame_interval)) 2268c2ecf20Sopenharmony_ci a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 2278c2ecf20Sopenharmony_ci ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival); 2288c2ecf20Sopenharmony_ci if (!ret) 2298c2ecf20Sopenharmony_ci a->parm.capture.timeperframe = ival.interval; 2308c2ecf20Sopenharmony_ci return ret; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_s_parm_cap); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ciconst struct v4l2_format_info *v4l2_format_info(u32 format) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci static const struct v4l2_format_info formats[] = { 2378c2ecf20Sopenharmony_ci /* RGB formats */ 2388c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_BGR24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2398c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_RGB24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2408c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_HSV24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2418c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_BGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2428c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_XBGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2438c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_BGRX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2448c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_RGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2458c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_XRGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2468c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_RGBX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2478c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_HSV32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2488c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_ARGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2498c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_RGBA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2508c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_ABGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2518c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_BGRA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2528c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2538c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2548c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* YUV packed formats */ 2578c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YUYV, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, 2588c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YVYU, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, 2598c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_UYVY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, 2608c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_VYUY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* YUV planar formats */ 2638c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, 2648c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV21, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, 2658c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV16, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, 2668c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV61, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, 2678c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2688c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, 2718c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, 2728c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV411P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 }, 2738c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV420, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, 2748c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU420, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, 2758c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV422P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, 2768c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_GREY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* YUV planar formats, non contiguous variant */ 2798c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, 2808c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, 2818c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV422M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, 2828c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU422M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, 2838c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV444M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, 2848c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU444M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV12M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, 2878c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV21M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, 2888c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV16M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, 2898c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_NV61M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Bayer RGB formats */ 2928c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2938c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2948c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2958c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2968c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2978c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2988c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 2998c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3008c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3018c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3028c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3038c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3048c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3058c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3068c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3078c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3088c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3098c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3108c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3118c2ecf20Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, 3128c2ecf20Sopenharmony_ci }; 3138c2ecf20Sopenharmony_ci unsigned int i; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(formats); ++i) 3168c2ecf20Sopenharmony_ci if (formats[i].format == format) 3178c2ecf20Sopenharmony_ci return &formats[i]; 3188c2ecf20Sopenharmony_ci return NULL; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(v4l2_format_info); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic inline unsigned int v4l2_format_block_width(const struct v4l2_format_info *info, int plane) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci if (!info->block_w[plane]) 3258c2ecf20Sopenharmony_ci return 1; 3268c2ecf20Sopenharmony_ci return info->block_w[plane]; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic inline unsigned int v4l2_format_block_height(const struct v4l2_format_info *info, int plane) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci if (!info->block_h[plane]) 3328c2ecf20Sopenharmony_ci return 1; 3338c2ecf20Sopenharmony_ci return info->block_h[plane]; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_civoid v4l2_apply_frmsize_constraints(u32 *width, u32 *height, 3378c2ecf20Sopenharmony_ci const struct v4l2_frmsize_stepwise *frmsize) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci if (!frmsize) 3408c2ecf20Sopenharmony_ci return; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * Clamp width/height to meet min/max constraints and round it up to 3448c2ecf20Sopenharmony_ci * macroblock alignment. 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci *width = clamp_roundup(*width, frmsize->min_width, frmsize->max_width, 3478c2ecf20Sopenharmony_ci frmsize->step_width); 3488c2ecf20Sopenharmony_ci *height = clamp_roundup(*height, frmsize->min_height, frmsize->max_height, 3498c2ecf20Sopenharmony_ci frmsize->step_height); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ciint v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, 3548c2ecf20Sopenharmony_ci u32 pixelformat, u32 width, u32 height) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci const struct v4l2_format_info *info; 3578c2ecf20Sopenharmony_ci struct v4l2_plane_pix_format *plane; 3588c2ecf20Sopenharmony_ci int i; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci info = v4l2_format_info(pixelformat); 3618c2ecf20Sopenharmony_ci if (!info) 3628c2ecf20Sopenharmony_ci return -EINVAL; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci pixfmt->width = width; 3658c2ecf20Sopenharmony_ci pixfmt->height = height; 3668c2ecf20Sopenharmony_ci pixfmt->pixelformat = pixelformat; 3678c2ecf20Sopenharmony_ci pixfmt->num_planes = info->mem_planes; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (info->mem_planes == 1) { 3708c2ecf20Sopenharmony_ci plane = &pixfmt->plane_fmt[0]; 3718c2ecf20Sopenharmony_ci plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; 3728c2ecf20Sopenharmony_ci plane->sizeimage = 0; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci for (i = 0; i < info->comp_planes; i++) { 3758c2ecf20Sopenharmony_ci unsigned int hdiv = (i == 0) ? 1 : info->hdiv; 3768c2ecf20Sopenharmony_ci unsigned int vdiv = (i == 0) ? 1 : info->vdiv; 3778c2ecf20Sopenharmony_ci unsigned int aligned_width; 3788c2ecf20Sopenharmony_ci unsigned int aligned_height; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); 3818c2ecf20Sopenharmony_ci aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci plane->sizeimage += info->bpp[i] * 3848c2ecf20Sopenharmony_ci DIV_ROUND_UP(aligned_width, hdiv) * 3858c2ecf20Sopenharmony_ci DIV_ROUND_UP(aligned_height, vdiv); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci } else { 3888c2ecf20Sopenharmony_ci for (i = 0; i < info->comp_planes; i++) { 3898c2ecf20Sopenharmony_ci unsigned int hdiv = (i == 0) ? 1 : info->hdiv; 3908c2ecf20Sopenharmony_ci unsigned int vdiv = (i == 0) ? 1 : info->vdiv; 3918c2ecf20Sopenharmony_ci unsigned int aligned_width; 3928c2ecf20Sopenharmony_ci unsigned int aligned_height; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); 3958c2ecf20Sopenharmony_ci aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci plane = &pixfmt->plane_fmt[i]; 3988c2ecf20Sopenharmony_ci plane->bytesperline = 3998c2ecf20Sopenharmony_ci info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv); 4008c2ecf20Sopenharmony_ci plane->sizeimage = 4018c2ecf20Sopenharmony_ci plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ciint v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, 4098c2ecf20Sopenharmony_ci u32 width, u32 height) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci const struct v4l2_format_info *info; 4128c2ecf20Sopenharmony_ci int i; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci info = v4l2_format_info(pixelformat); 4158c2ecf20Sopenharmony_ci if (!info) 4168c2ecf20Sopenharmony_ci return -EINVAL; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* Single planar API cannot be used for multi plane formats. */ 4198c2ecf20Sopenharmony_ci if (info->mem_planes > 1) 4208c2ecf20Sopenharmony_ci return -EINVAL; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci pixfmt->width = width; 4238c2ecf20Sopenharmony_ci pixfmt->height = height; 4248c2ecf20Sopenharmony_ci pixfmt->pixelformat = pixelformat; 4258c2ecf20Sopenharmony_ci pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; 4268c2ecf20Sopenharmony_ci pixfmt->sizeimage = 0; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci for (i = 0; i < info->comp_planes; i++) { 4298c2ecf20Sopenharmony_ci unsigned int hdiv = (i == 0) ? 1 : info->hdiv; 4308c2ecf20Sopenharmony_ci unsigned int vdiv = (i == 0) ? 1 : info->vdiv; 4318c2ecf20Sopenharmony_ci unsigned int aligned_width; 4328c2ecf20Sopenharmony_ci unsigned int aligned_height; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); 4358c2ecf20Sopenharmony_ci aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci pixfmt->sizeimage += info->bpp[i] * 4388c2ecf20Sopenharmony_ci DIV_ROUND_UP(aligned_width, hdiv) * 4398c2ecf20Sopenharmony_ci DIV_ROUND_UP(aligned_height, vdiv); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); 444