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