162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Video for Linux Two 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * A generic video device interface for the LINUX operating system 662306a36Sopenharmony_ci * using a set of device structures/vectors for low level operations. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This file replaces the videodev.c file that comes with the 962306a36Sopenharmony_ci * regular kernel distribution. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Author: Bill Dirks <bill@thedirks.org> 1262306a36Sopenharmony_ci * based on code by Alan Cox, <alan@cymru.net> 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * Video capture interface for Linux 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * A generic video device interface for the LINUX operating system 1962306a36Sopenharmony_ci * using a set of device structures/vectors for low level operations. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * Author: Alan Cox, <alan@lxorguk.ukuu.org.uk> 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Fixes: 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Video4linux 1/2 integration by Justin Schoeman 2862306a36Sopenharmony_ci * <justin@suntiger.ee.up.ac.za> 2962306a36Sopenharmony_ci * 2.4 PROCFS support ported from 2.4 kernels by 3062306a36Sopenharmony_ci * Iñaki García Etxebarria <garetxe@euskalnet.net> 3162306a36Sopenharmony_ci * Makefile fix by "W. Michael Petullo" <mike@flyn.org> 3262306a36Sopenharmony_ci * 2.4 devfs support ported from 2.4 kernels by 3362306a36Sopenharmony_ci * Dan Merillat <dan@merillat.org> 3462306a36Sopenharmony_ci * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman) 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <linux/module.h> 3862306a36Sopenharmony_ci#include <linux/types.h> 3962306a36Sopenharmony_ci#include <linux/kernel.h> 4062306a36Sopenharmony_ci#include <linux/mm.h> 4162306a36Sopenharmony_ci#include <linux/string.h> 4262306a36Sopenharmony_ci#include <linux/errno.h> 4362306a36Sopenharmony_ci#include <linux/uaccess.h> 4462306a36Sopenharmony_ci#include <asm/io.h> 4562306a36Sopenharmony_ci#include <asm/div64.h> 4662306a36Sopenharmony_ci#include <media/v4l2-common.h> 4762306a36Sopenharmony_ci#include <media/v4l2-device.h> 4862306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#include <linux/videodev2.h> 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * V 4 L 2 D R I V E R H E L P E R A P I 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* 5962306a36Sopenharmony_ci * Video Standard Operations (contributed by Michael Schimek) 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Helper functions for control handling */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Fill in a struct v4l2_queryctrl */ 6562306a36Sopenharmony_ciint v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _step, s32 _def) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci const char *name; 6862306a36Sopenharmony_ci s64 min = _min; 6962306a36Sopenharmony_ci s64 max = _max; 7062306a36Sopenharmony_ci u64 step = _step; 7162306a36Sopenharmony_ci s64 def = _def; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type, 7462306a36Sopenharmony_ci &min, &max, &step, &def, &qctrl->flags); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (name == NULL) 7762306a36Sopenharmony_ci return -EINVAL; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci qctrl->minimum = min; 8062306a36Sopenharmony_ci qctrl->maximum = max; 8162306a36Sopenharmony_ci qctrl->step = step; 8262306a36Sopenharmony_ci qctrl->default_value = def; 8362306a36Sopenharmony_ci qctrl->reserved[0] = qctrl->reserved[1] = 0; 8462306a36Sopenharmony_ci strscpy(qctrl->name, name, sizeof(qctrl->name)); 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ciEXPORT_SYMBOL(v4l2_ctrl_query_fill); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* Clamp x to be between min and max, aligned to a multiple of 2^align. min 9062306a36Sopenharmony_ci * and max don't have to be aligned, but there must be at least one valid 9162306a36Sopenharmony_ci * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples 9262306a36Sopenharmony_ci * of 16 between 17 and 31. */ 9362306a36Sopenharmony_cistatic unsigned int clamp_align(unsigned int x, unsigned int min, 9462306a36Sopenharmony_ci unsigned int max, unsigned int align) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci /* Bits that must be zero to be aligned */ 9762306a36Sopenharmony_ci unsigned int mask = ~((1 << align) - 1); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* Clamp to aligned min and max */ 10062306a36Sopenharmony_ci x = clamp(x, (min + ~mask) & mask, max & mask); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* Round to nearest aligned value */ 10362306a36Sopenharmony_ci if (align) 10462306a36Sopenharmony_ci x = (x + (1 << (align - 1))) & mask; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return x; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic unsigned int clamp_roundup(unsigned int x, unsigned int min, 11062306a36Sopenharmony_ci unsigned int max, unsigned int alignment) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci x = clamp(x, min, max); 11362306a36Sopenharmony_ci if (alignment) 11462306a36Sopenharmony_ci x = round_up(x, alignment); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return x; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_civoid v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, 12062306a36Sopenharmony_ci unsigned int walign, 12162306a36Sopenharmony_ci u32 *h, unsigned int hmin, unsigned int hmax, 12262306a36Sopenharmony_ci unsigned int halign, unsigned int salign) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci *w = clamp_align(*w, wmin, wmax, walign); 12562306a36Sopenharmony_ci *h = clamp_align(*h, hmin, hmax, halign); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* Usually we don't need to align the size and are done now. */ 12862306a36Sopenharmony_ci if (!salign) 12962306a36Sopenharmony_ci return; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* How much alignment do we have? */ 13262306a36Sopenharmony_ci walign = __ffs(*w); 13362306a36Sopenharmony_ci halign = __ffs(*h); 13462306a36Sopenharmony_ci /* Enough to satisfy the image alignment? */ 13562306a36Sopenharmony_ci if (walign + halign < salign) { 13662306a36Sopenharmony_ci /* Max walign where there is still a valid width */ 13762306a36Sopenharmony_ci unsigned int wmaxa = __fls(wmax ^ (wmin - 1)); 13862306a36Sopenharmony_ci /* Max halign where there is still a valid height */ 13962306a36Sopenharmony_ci unsigned int hmaxa = __fls(hmax ^ (hmin - 1)); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* up the smaller alignment until we have enough */ 14262306a36Sopenharmony_ci do { 14362306a36Sopenharmony_ci if (halign >= hmaxa || 14462306a36Sopenharmony_ci (walign <= halign && walign < wmaxa)) { 14562306a36Sopenharmony_ci *w = clamp_align(*w, wmin, wmax, walign + 1); 14662306a36Sopenharmony_ci walign = __ffs(*w); 14762306a36Sopenharmony_ci } else { 14862306a36Sopenharmony_ci *h = clamp_align(*h, hmin, hmax, halign + 1); 14962306a36Sopenharmony_ci halign = __ffs(*h); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci } while (halign + walign < salign); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l_bound_align_image); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciconst void * 15762306a36Sopenharmony_ci__v4l2_find_nearest_size(const void *array, size_t array_size, 15862306a36Sopenharmony_ci size_t entry_size, size_t width_offset, 15962306a36Sopenharmony_ci size_t height_offset, s32 width, s32 height) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci u32 error, min_error = U32_MAX; 16262306a36Sopenharmony_ci const void *best = NULL; 16362306a36Sopenharmony_ci unsigned int i; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (!array) 16662306a36Sopenharmony_ci return NULL; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci for (i = 0; i < array_size; i++, array += entry_size) { 16962306a36Sopenharmony_ci const u32 *entry_width = array + width_offset; 17062306a36Sopenharmony_ci const u32 *entry_height = array + height_offset; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci error = abs(*entry_width - width) + abs(*entry_height - height); 17362306a36Sopenharmony_ci if (error > min_error) 17462306a36Sopenharmony_ci continue; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci min_error = error; 17762306a36Sopenharmony_ci best = array; 17862306a36Sopenharmony_ci if (!error) 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return best; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__v4l2_find_nearest_size); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ciint v4l2_g_parm_cap(struct video_device *vdev, 18762306a36Sopenharmony_ci struct v4l2_subdev *sd, struct v4l2_streamparm *a) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct v4l2_subdev_frame_interval ival = { 0 }; 19062306a36Sopenharmony_ci int ret; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && 19362306a36Sopenharmony_ci a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 19462306a36Sopenharmony_ci return -EINVAL; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (vdev->device_caps & V4L2_CAP_READWRITE) 19762306a36Sopenharmony_ci a->parm.capture.readbuffers = 2; 19862306a36Sopenharmony_ci if (v4l2_subdev_has_op(sd, video, g_frame_interval)) 19962306a36Sopenharmony_ci a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 20062306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival); 20162306a36Sopenharmony_ci if (!ret) 20262306a36Sopenharmony_ci a->parm.capture.timeperframe = ival.interval; 20362306a36Sopenharmony_ci return ret; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_g_parm_cap); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ciint v4l2_s_parm_cap(struct video_device *vdev, 20862306a36Sopenharmony_ci struct v4l2_subdev *sd, struct v4l2_streamparm *a) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct v4l2_subdev_frame_interval ival = { 21162306a36Sopenharmony_ci .interval = a->parm.capture.timeperframe 21262306a36Sopenharmony_ci }; 21362306a36Sopenharmony_ci int ret; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && 21662306a36Sopenharmony_ci a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 21762306a36Sopenharmony_ci return -EINVAL; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci memset(&a->parm, 0, sizeof(a->parm)); 22062306a36Sopenharmony_ci if (vdev->device_caps & V4L2_CAP_READWRITE) 22162306a36Sopenharmony_ci a->parm.capture.readbuffers = 2; 22262306a36Sopenharmony_ci else 22362306a36Sopenharmony_ci a->parm.capture.readbuffers = 0; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (v4l2_subdev_has_op(sd, video, g_frame_interval)) 22662306a36Sopenharmony_ci a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 22762306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival); 22862306a36Sopenharmony_ci if (!ret) 22962306a36Sopenharmony_ci a->parm.capture.timeperframe = ival.interval; 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_s_parm_cap); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciconst struct v4l2_format_info *v4l2_format_info(u32 format) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci static const struct v4l2_format_info formats[] = { 23762306a36Sopenharmony_ci /* RGB formats */ 23862306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_BGR24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 23962306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_RGB24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24062306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_HSV24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24162306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_BGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24262306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_XBGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24362306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_BGRX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24462306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_RGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24562306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_XRGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24662306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_RGBX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24762306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_HSV32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24862306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_ARGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 24962306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_RGBA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 25062306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_ABGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 25162306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_BGRA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 25262306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 25362306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 25462306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 25562306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 25662306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* YUV packed formats */ 25962306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YUYV, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 26062306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YVYU, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 26162306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_UYVY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 26262306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_VYUY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 26362306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_Y212, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 26462306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV48_12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 26562306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_MT2110T, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2, 26662306a36Sopenharmony_ci .block_w = { 16, 8, 0, 0 }, .block_h = { 32, 16, 0, 0 }}, 26762306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_MT2110R, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2, 26862306a36Sopenharmony_ci .block_w = { 16, 8, 0, 0 }, .block_h = { 32, 16, 0, 0 }}, 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* YUV planar formats */ 27162306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 27262306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV21, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 27362306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV16, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 27462306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV61, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 27562306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 27662306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 27762306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 27862306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_P012, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 4, .vdiv = 4 }, 28162306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 4, .vdiv = 4 }, 28262306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV411P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 4, .vdiv = 1 }, 28362306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV420, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 28462306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU420, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 28562306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV422P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 28662306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_GREY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* Tiled YUV formats */ 28962306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV12_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 29062306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV15_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2, 29162306a36Sopenharmony_ci .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 }}, 29262306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_P010_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* YUV planar formats, non contiguous variant */ 29562306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 29662306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 29762306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV422M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 29862306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU422M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 29962306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YUV444M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 30062306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_YVU444M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV12M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 30362306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV21M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 30462306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV16M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 30562306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_NV61M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, 30662306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_P012M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* Bayer RGB formats */ 30962306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31062306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31162306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31262306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31362306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31462306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31562306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31662306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31762306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31862306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 31962306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32062306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32162306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32262306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32362306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32462306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32562306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SBGGR12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32662306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGBRG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32762306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SGRBG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32862306a36Sopenharmony_ci { .format = V4L2_PIX_FMT_SRGGB12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, 32962306a36Sopenharmony_ci }; 33062306a36Sopenharmony_ci unsigned int i; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(formats); ++i) 33362306a36Sopenharmony_ci if (formats[i].format == format) 33462306a36Sopenharmony_ci return &formats[i]; 33562306a36Sopenharmony_ci return NULL; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ciEXPORT_SYMBOL(v4l2_format_info); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic inline unsigned int v4l2_format_block_width(const struct v4l2_format_info *info, int plane) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci if (!info->block_w[plane]) 34262306a36Sopenharmony_ci return 1; 34362306a36Sopenharmony_ci return info->block_w[plane]; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic inline unsigned int v4l2_format_block_height(const struct v4l2_format_info *info, int plane) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci if (!info->block_h[plane]) 34962306a36Sopenharmony_ci return 1; 35062306a36Sopenharmony_ci return info->block_h[plane]; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_civoid v4l2_apply_frmsize_constraints(u32 *width, u32 *height, 35462306a36Sopenharmony_ci const struct v4l2_frmsize_stepwise *frmsize) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci if (!frmsize) 35762306a36Sopenharmony_ci return; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* 36062306a36Sopenharmony_ci * Clamp width/height to meet min/max constraints and round it up to 36162306a36Sopenharmony_ci * macroblock alignment. 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci *width = clamp_roundup(*width, frmsize->min_width, frmsize->max_width, 36462306a36Sopenharmony_ci frmsize->step_width); 36562306a36Sopenharmony_ci *height = clamp_roundup(*height, frmsize->min_height, frmsize->max_height, 36662306a36Sopenharmony_ci frmsize->step_height); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ciint v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, 37162306a36Sopenharmony_ci u32 pixelformat, u32 width, u32 height) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci const struct v4l2_format_info *info; 37462306a36Sopenharmony_ci struct v4l2_plane_pix_format *plane; 37562306a36Sopenharmony_ci int i; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci info = v4l2_format_info(pixelformat); 37862306a36Sopenharmony_ci if (!info) 37962306a36Sopenharmony_ci return -EINVAL; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci pixfmt->width = width; 38262306a36Sopenharmony_ci pixfmt->height = height; 38362306a36Sopenharmony_ci pixfmt->pixelformat = pixelformat; 38462306a36Sopenharmony_ci pixfmt->num_planes = info->mem_planes; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (info->mem_planes == 1) { 38762306a36Sopenharmony_ci plane = &pixfmt->plane_fmt[0]; 38862306a36Sopenharmony_ci plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0] / info->bpp_div[0]; 38962306a36Sopenharmony_ci plane->sizeimage = 0; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci for (i = 0; i < info->comp_planes; i++) { 39262306a36Sopenharmony_ci unsigned int hdiv = (i == 0) ? 1 : info->hdiv; 39362306a36Sopenharmony_ci unsigned int vdiv = (i == 0) ? 1 : info->vdiv; 39462306a36Sopenharmony_ci unsigned int aligned_width; 39562306a36Sopenharmony_ci unsigned int aligned_height; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); 39862306a36Sopenharmony_ci aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci plane->sizeimage += info->bpp[i] * 40162306a36Sopenharmony_ci DIV_ROUND_UP(aligned_width, hdiv) * 40262306a36Sopenharmony_ci DIV_ROUND_UP(aligned_height, vdiv) / info->bpp_div[i]; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci } else { 40562306a36Sopenharmony_ci for (i = 0; i < info->comp_planes; i++) { 40662306a36Sopenharmony_ci unsigned int hdiv = (i == 0) ? 1 : info->hdiv; 40762306a36Sopenharmony_ci unsigned int vdiv = (i == 0) ? 1 : info->vdiv; 40862306a36Sopenharmony_ci unsigned int aligned_width; 40962306a36Sopenharmony_ci unsigned int aligned_height; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); 41262306a36Sopenharmony_ci aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci plane = &pixfmt->plane_fmt[i]; 41562306a36Sopenharmony_ci plane->bytesperline = 41662306a36Sopenharmony_ci info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv) / info->bpp_div[i]; 41762306a36Sopenharmony_ci plane->sizeimage = 41862306a36Sopenharmony_ci plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ciint v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, 42662306a36Sopenharmony_ci u32 width, u32 height) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci const struct v4l2_format_info *info; 42962306a36Sopenharmony_ci int i; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci info = v4l2_format_info(pixelformat); 43262306a36Sopenharmony_ci if (!info) 43362306a36Sopenharmony_ci return -EINVAL; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Single planar API cannot be used for multi plane formats. */ 43662306a36Sopenharmony_ci if (info->mem_planes > 1) 43762306a36Sopenharmony_ci return -EINVAL; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci pixfmt->width = width; 44062306a36Sopenharmony_ci pixfmt->height = height; 44162306a36Sopenharmony_ci pixfmt->pixelformat = pixelformat; 44262306a36Sopenharmony_ci pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0] / info->bpp_div[0]; 44362306a36Sopenharmony_ci pixfmt->sizeimage = 0; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci for (i = 0; i < info->comp_planes; i++) { 44662306a36Sopenharmony_ci unsigned int hdiv = (i == 0) ? 1 : info->hdiv; 44762306a36Sopenharmony_ci unsigned int vdiv = (i == 0) ? 1 : info->vdiv; 44862306a36Sopenharmony_ci unsigned int aligned_width; 44962306a36Sopenharmony_ci unsigned int aligned_height; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); 45262306a36Sopenharmony_ci aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci pixfmt->sizeimage += info->bpp[i] * 45562306a36Sopenharmony_ci DIV_ROUND_UP(aligned_width, hdiv) * 45662306a36Sopenharmony_ci DIV_ROUND_UP(aligned_height, vdiv) / info->bpp_div[i]; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cis64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul, 46362306a36Sopenharmony_ci unsigned int div) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct v4l2_ctrl *ctrl; 46662306a36Sopenharmony_ci s64 freq; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci ctrl = v4l2_ctrl_find(handler, V4L2_CID_LINK_FREQ); 46962306a36Sopenharmony_ci if (ctrl) { 47062306a36Sopenharmony_ci struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ }; 47162306a36Sopenharmony_ci int ret; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci qm.index = v4l2_ctrl_g_ctrl(ctrl); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ret = v4l2_querymenu(handler, &qm); 47662306a36Sopenharmony_ci if (ret) 47762306a36Sopenharmony_ci return -ENOENT; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci freq = qm.value; 48062306a36Sopenharmony_ci } else { 48162306a36Sopenharmony_ci if (!mul || !div) 48262306a36Sopenharmony_ci return -ENOENT; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci ctrl = v4l2_ctrl_find(handler, V4L2_CID_PIXEL_RATE); 48562306a36Sopenharmony_ci if (!ctrl) 48662306a36Sopenharmony_ci return -ENOENT; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci freq = div_u64(v4l2_ctrl_g_ctrl_int64(ctrl) * mul, div); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci pr_warn("%s: Link frequency estimated using pixel rate: result might be inaccurate\n", 49162306a36Sopenharmony_ci __func__); 49262306a36Sopenharmony_ci pr_warn("%s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver\n", 49362306a36Sopenharmony_ci __func__); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return freq > 0 ? freq : -EINVAL; 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_get_link_freq); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/* 50162306a36Sopenharmony_ci * Simplify a fraction using a simple continued fraction decomposition. The 50262306a36Sopenharmony_ci * idea here is to convert fractions such as 333333/10000000 to 1/30 using 50362306a36Sopenharmony_ci * 32 bit arithmetic only. The algorithm is not perfect and relies upon two 50462306a36Sopenharmony_ci * arbitrary parameters to remove non-significative terms from the simple 50562306a36Sopenharmony_ci * continued fraction decomposition. Using 8 and 333 for n_terms and threshold 50662306a36Sopenharmony_ci * respectively seems to give nice results. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_civoid v4l2_simplify_fraction(u32 *numerator, u32 *denominator, 50962306a36Sopenharmony_ci unsigned int n_terms, unsigned int threshold) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci u32 *an; 51262306a36Sopenharmony_ci u32 x, y, r; 51362306a36Sopenharmony_ci unsigned int i, n; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL); 51662306a36Sopenharmony_ci if (an == NULL) 51762306a36Sopenharmony_ci return; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* 52062306a36Sopenharmony_ci * Convert the fraction to a simple continued fraction. See 52162306a36Sopenharmony_ci * https://en.wikipedia.org/wiki/Continued_fraction 52262306a36Sopenharmony_ci * Stop if the current term is bigger than or equal to the given 52362306a36Sopenharmony_ci * threshold. 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci x = *numerator; 52662306a36Sopenharmony_ci y = *denominator; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci for (n = 0; n < n_terms && y != 0; ++n) { 52962306a36Sopenharmony_ci an[n] = x / y; 53062306a36Sopenharmony_ci if (an[n] >= threshold) { 53162306a36Sopenharmony_ci if (n < 2) 53262306a36Sopenharmony_ci n++; 53362306a36Sopenharmony_ci break; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci r = x - an[n] * y; 53762306a36Sopenharmony_ci x = y; 53862306a36Sopenharmony_ci y = r; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* Expand the simple continued fraction back to an integer fraction. */ 54262306a36Sopenharmony_ci x = 0; 54362306a36Sopenharmony_ci y = 1; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci for (i = n; i > 0; --i) { 54662306a36Sopenharmony_ci r = y; 54762306a36Sopenharmony_ci y = an[i-1] * y + x; 54862306a36Sopenharmony_ci x = r; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci *numerator = y; 55262306a36Sopenharmony_ci *denominator = x; 55362306a36Sopenharmony_ci kfree(an); 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_simplify_fraction); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci/* 55862306a36Sopenharmony_ci * Convert a fraction to a frame interval in 100ns multiples. The idea here is 55962306a36Sopenharmony_ci * to compute numerator / denominator * 10000000 using 32 bit fixed point 56062306a36Sopenharmony_ci * arithmetic only. 56162306a36Sopenharmony_ci */ 56262306a36Sopenharmony_ciu32 v4l2_fraction_to_interval(u32 numerator, u32 denominator) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci u32 multiplier; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Saturate the result if the operation would overflow. */ 56762306a36Sopenharmony_ci if (denominator == 0 || 56862306a36Sopenharmony_ci numerator/denominator >= ((u32)-1)/10000000) 56962306a36Sopenharmony_ci return (u32)-1; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* 57262306a36Sopenharmony_ci * Divide both the denominator and the multiplier by two until 57362306a36Sopenharmony_ci * numerator * multiplier doesn't overflow. If anyone knows a better 57462306a36Sopenharmony_ci * algorithm please let me know. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_ci multiplier = 10000000; 57762306a36Sopenharmony_ci while (numerator > ((u32)-1)/multiplier) { 57862306a36Sopenharmony_ci multiplier /= 2; 57962306a36Sopenharmony_ci denominator /= 2; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return denominator ? numerator * multiplier / denominator : 0; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_fraction_to_interval); 585