xref: /OK3568_Linux_fs/kernel/drivers/media/v4l2-core/v4l2-common.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *	Video for Linux Two
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *	A generic video device interface for the LINUX operating system
6*4882a593Smuzhiyun  *	using a set of device structures/vectors for low level operations.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *	This file replaces the videodev.c file that comes with the
9*4882a593Smuzhiyun  *	regular kernel distribution.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * Author:	Bill Dirks <bill@thedirks.org>
12*4882a593Smuzhiyun  *		based on code by Alan Cox, <alan@cymru.net>
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /*
16*4882a593Smuzhiyun  * Video capture interface for Linux
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  *	A generic video device interface for the LINUX operating system
19*4882a593Smuzhiyun  *	using a set of device structures/vectors for low level operations.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * Author:	Alan Cox, <alan@lxorguk.ukuu.org.uk>
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * Fixes:
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /*
27*4882a593Smuzhiyun  * Video4linux 1/2 integration by Justin Schoeman
28*4882a593Smuzhiyun  * <justin@suntiger.ee.up.ac.za>
29*4882a593Smuzhiyun  * 2.4 PROCFS support ported from 2.4 kernels by
30*4882a593Smuzhiyun  *  Iñaki García Etxebarria <garetxe@euskalnet.net>
31*4882a593Smuzhiyun  * Makefile fix by "W. Michael Petullo" <mike@flyn.org>
32*4882a593Smuzhiyun  * 2.4 devfs support ported from 2.4 kernels by
33*4882a593Smuzhiyun  *  Dan Merillat <dan@merillat.org>
34*4882a593Smuzhiyun  * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman)
35*4882a593Smuzhiyun  */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #include <linux/module.h>
38*4882a593Smuzhiyun #include <linux/types.h>
39*4882a593Smuzhiyun #include <linux/kernel.h>
40*4882a593Smuzhiyun #include <linux/mm.h>
41*4882a593Smuzhiyun #include <linux/string.h>
42*4882a593Smuzhiyun #include <linux/errno.h>
43*4882a593Smuzhiyun #include <linux/uaccess.h>
44*4882a593Smuzhiyun #include <asm/io.h>
45*4882a593Smuzhiyun #include <asm/div64.h>
46*4882a593Smuzhiyun #include <media/v4l2-common.h>
47*4882a593Smuzhiyun #include <media/v4l2-device.h>
48*4882a593Smuzhiyun #include <media/v4l2-ctrls.h>
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #include <linux/videodev2.h>
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun  *
54*4882a593Smuzhiyun  *	V 4 L 2   D R I V E R   H E L P E R   A P I
55*4882a593Smuzhiyun  *
56*4882a593Smuzhiyun  */
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun  *  Video Standard Operations (contributed by Michael Schimek)
60*4882a593Smuzhiyun  */
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /* Helper functions for control handling			     */
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun /* Fill in a struct v4l2_queryctrl */
v4l2_ctrl_query_fill(struct v4l2_queryctrl * qctrl,s32 _min,s32 _max,s32 _step,s32 _def)65*4882a593Smuzhiyun int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _step, s32 _def)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	const char *name;
68*4882a593Smuzhiyun 	s64 min = _min;
69*4882a593Smuzhiyun 	s64 max = _max;
70*4882a593Smuzhiyun 	u64 step = _step;
71*4882a593Smuzhiyun 	s64 def = _def;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type,
74*4882a593Smuzhiyun 		       &min, &max, &step, &def, &qctrl->flags);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	if (name == NULL)
77*4882a593Smuzhiyun 		return -EINVAL;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	qctrl->minimum = min;
80*4882a593Smuzhiyun 	qctrl->maximum = max;
81*4882a593Smuzhiyun 	qctrl->step = step;
82*4882a593Smuzhiyun 	qctrl->default_value = def;
83*4882a593Smuzhiyun 	qctrl->reserved[0] = qctrl->reserved[1] = 0;
84*4882a593Smuzhiyun 	strscpy(qctrl->name, name, sizeof(qctrl->name));
85*4882a593Smuzhiyun 	return 0;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun EXPORT_SYMBOL(v4l2_ctrl_query_fill);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun /* Clamp x to be between min and max, aligned to a multiple of 2^align.  min
90*4882a593Smuzhiyun  * and max don't have to be aligned, but there must be at least one valid
91*4882a593Smuzhiyun  * value.  E.g., min=17,max=31,align=4 is not allowed as there are no multiples
92*4882a593Smuzhiyun  * of 16 between 17 and 31.  */
clamp_align(unsigned int x,unsigned int min,unsigned int max,unsigned int align)93*4882a593Smuzhiyun static unsigned int clamp_align(unsigned int x, unsigned int min,
94*4882a593Smuzhiyun 				unsigned int max, unsigned int align)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	/* Bits that must be zero to be aligned */
97*4882a593Smuzhiyun 	unsigned int mask = ~((1 << align) - 1);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	/* Clamp to aligned min and max */
100*4882a593Smuzhiyun 	x = clamp(x, (min + ~mask) & mask, max & mask);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	/* Round to nearest aligned value */
103*4882a593Smuzhiyun 	if (align)
104*4882a593Smuzhiyun 		x = (x + (1 << (align - 1))) & mask;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	return x;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
clamp_roundup(unsigned int x,unsigned int min,unsigned int max,unsigned int alignment)109*4882a593Smuzhiyun static unsigned int clamp_roundup(unsigned int x, unsigned int min,
110*4882a593Smuzhiyun 				   unsigned int max, unsigned int alignment)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	x = clamp(x, min, max);
113*4882a593Smuzhiyun 	if (alignment)
114*4882a593Smuzhiyun 		x = round_up(x, alignment);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	return x;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
v4l_bound_align_image(u32 * w,unsigned int wmin,unsigned int wmax,unsigned int walign,u32 * h,unsigned int hmin,unsigned int hmax,unsigned int halign,unsigned int salign)119*4882a593Smuzhiyun void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
120*4882a593Smuzhiyun 			   unsigned int walign,
121*4882a593Smuzhiyun 			   u32 *h, unsigned int hmin, unsigned int hmax,
122*4882a593Smuzhiyun 			   unsigned int halign, unsigned int salign)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	*w = clamp_align(*w, wmin, wmax, walign);
125*4882a593Smuzhiyun 	*h = clamp_align(*h, hmin, hmax, halign);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/* Usually we don't need to align the size and are done now. */
128*4882a593Smuzhiyun 	if (!salign)
129*4882a593Smuzhiyun 		return;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	/* How much alignment do we have? */
132*4882a593Smuzhiyun 	walign = __ffs(*w);
133*4882a593Smuzhiyun 	halign = __ffs(*h);
134*4882a593Smuzhiyun 	/* Enough to satisfy the image alignment? */
135*4882a593Smuzhiyun 	if (walign + halign < salign) {
136*4882a593Smuzhiyun 		/* Max walign where there is still a valid width */
137*4882a593Smuzhiyun 		unsigned int wmaxa = __fls(wmax ^ (wmin - 1));
138*4882a593Smuzhiyun 		/* Max halign where there is still a valid height */
139*4882a593Smuzhiyun 		unsigned int hmaxa = __fls(hmax ^ (hmin - 1));
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 		/* up the smaller alignment until we have enough */
142*4882a593Smuzhiyun 		do {
143*4882a593Smuzhiyun 			if (halign >= hmaxa ||
144*4882a593Smuzhiyun 			    (walign <= halign && walign < wmaxa)) {
145*4882a593Smuzhiyun 				*w = clamp_align(*w, wmin, wmax, walign + 1);
146*4882a593Smuzhiyun 				walign = __ffs(*w);
147*4882a593Smuzhiyun 			} else {
148*4882a593Smuzhiyun 				*h = clamp_align(*h, hmin, hmax, halign + 1);
149*4882a593Smuzhiyun 				halign = __ffs(*h);
150*4882a593Smuzhiyun 			}
151*4882a593Smuzhiyun 		} while (halign + walign < salign);
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(v4l_bound_align_image);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun const void *
__v4l2_find_nearest_size(const void * array,size_t array_size,size_t entry_size,size_t width_offset,size_t height_offset,s32 width,s32 height)157*4882a593Smuzhiyun __v4l2_find_nearest_size(const void *array, size_t array_size,
158*4882a593Smuzhiyun 			 size_t entry_size, size_t width_offset,
159*4882a593Smuzhiyun 			 size_t height_offset, s32 width, s32 height)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	u32 error, min_error = U32_MAX;
162*4882a593Smuzhiyun 	const void *best = NULL;
163*4882a593Smuzhiyun 	unsigned int i;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	if (!array)
166*4882a593Smuzhiyun 		return NULL;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	for (i = 0; i < array_size; i++, array += entry_size) {
169*4882a593Smuzhiyun 		const u32 *entry_width = array + width_offset;
170*4882a593Smuzhiyun 		const u32 *entry_height = array + height_offset;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 		error = abs(*entry_width - width) + abs(*entry_height - height);
173*4882a593Smuzhiyun 		if (error > min_error)
174*4882a593Smuzhiyun 			continue;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		min_error = error;
177*4882a593Smuzhiyun 		best = array;
178*4882a593Smuzhiyun 		if (!error)
179*4882a593Smuzhiyun 			break;
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	return best;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__v4l2_find_nearest_size);
185*4882a593Smuzhiyun 
v4l2_g_parm_cap(struct video_device * vdev,struct v4l2_subdev * sd,struct v4l2_streamparm * a)186*4882a593Smuzhiyun int v4l2_g_parm_cap(struct video_device *vdev,
187*4882a593Smuzhiyun 		    struct v4l2_subdev *sd, struct v4l2_streamparm *a)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	struct v4l2_subdev_frame_interval ival = { 0 };
190*4882a593Smuzhiyun 	int ret;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
193*4882a593Smuzhiyun 	    a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
194*4882a593Smuzhiyun 		return -EINVAL;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (vdev->device_caps & V4L2_CAP_READWRITE)
197*4882a593Smuzhiyun 		a->parm.capture.readbuffers = 2;
198*4882a593Smuzhiyun 	if (v4l2_subdev_has_op(sd, video, g_frame_interval))
199*4882a593Smuzhiyun 		a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
200*4882a593Smuzhiyun 	ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival);
201*4882a593Smuzhiyun 	if (!ret)
202*4882a593Smuzhiyun 		a->parm.capture.timeperframe = ival.interval;
203*4882a593Smuzhiyun 	return ret;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(v4l2_g_parm_cap);
206*4882a593Smuzhiyun 
v4l2_s_parm_cap(struct video_device * vdev,struct v4l2_subdev * sd,struct v4l2_streamparm * a)207*4882a593Smuzhiyun int v4l2_s_parm_cap(struct video_device *vdev,
208*4882a593Smuzhiyun 		    struct v4l2_subdev *sd, struct v4l2_streamparm *a)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	struct v4l2_subdev_frame_interval ival = {
211*4882a593Smuzhiyun 		.interval = a->parm.capture.timeperframe
212*4882a593Smuzhiyun 	};
213*4882a593Smuzhiyun 	int ret;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
216*4882a593Smuzhiyun 	    a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
217*4882a593Smuzhiyun 		return -EINVAL;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	memset(&a->parm, 0, sizeof(a->parm));
220*4882a593Smuzhiyun 	if (vdev->device_caps & V4L2_CAP_READWRITE)
221*4882a593Smuzhiyun 		a->parm.capture.readbuffers = 2;
222*4882a593Smuzhiyun 	else
223*4882a593Smuzhiyun 		a->parm.capture.readbuffers = 0;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	if (v4l2_subdev_has_op(sd, video, g_frame_interval))
226*4882a593Smuzhiyun 		a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
227*4882a593Smuzhiyun 	ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival);
228*4882a593Smuzhiyun 	if (!ret)
229*4882a593Smuzhiyun 		a->parm.capture.timeperframe = ival.interval;
230*4882a593Smuzhiyun 	return ret;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(v4l2_s_parm_cap);
233*4882a593Smuzhiyun 
v4l2_format_info(u32 format)234*4882a593Smuzhiyun const struct v4l2_format_info *v4l2_format_info(u32 format)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	static const struct v4l2_format_info formats[] = {
237*4882a593Smuzhiyun 		/* RGB formats */
238*4882a593Smuzhiyun 		{ .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 },
239*4882a593Smuzhiyun 		{ .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 },
240*4882a593Smuzhiyun 		{ .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 },
241*4882a593Smuzhiyun 		{ .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 },
242*4882a593Smuzhiyun 		{ .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 },
243*4882a593Smuzhiyun 		{ .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 },
244*4882a593Smuzhiyun 		{ .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 },
245*4882a593Smuzhiyun 		{ .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 },
246*4882a593Smuzhiyun 		{ .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 },
247*4882a593Smuzhiyun 		{ .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 },
248*4882a593Smuzhiyun 		{ .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 },
249*4882a593Smuzhiyun 		{ .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 },
250*4882a593Smuzhiyun 		{ .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 },
251*4882a593Smuzhiyun 		{ .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 },
252*4882a593Smuzhiyun 		{ .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 },
253*4882a593Smuzhiyun 		{ .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 },
254*4882a593Smuzhiyun 		{ .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 },
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 		/* YUV packed formats */
257*4882a593Smuzhiyun 		{ .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 },
258*4882a593Smuzhiyun 		{ .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 },
259*4882a593Smuzhiyun 		{ .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 },
260*4882a593Smuzhiyun 		{ .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 },
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 		/* YUV planar formats */
263*4882a593Smuzhiyun 		{ .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 },
264*4882a593Smuzhiyun 		{ .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 },
265*4882a593Smuzhiyun 		{ .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 },
266*4882a593Smuzhiyun 		{ .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 },
267*4882a593Smuzhiyun 		{ .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 },
268*4882a593Smuzhiyun 		{ .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 },
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 		{ .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 },
271*4882a593Smuzhiyun 		{ .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 },
272*4882a593Smuzhiyun 		{ .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 },
273*4882a593Smuzhiyun 		{ .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 },
274*4882a593Smuzhiyun 		{ .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 },
275*4882a593Smuzhiyun 		{ .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 },
276*4882a593Smuzhiyun 		{ .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 },
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		/* YUV planar formats, non contiguous variant */
279*4882a593Smuzhiyun 		{ .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 },
280*4882a593Smuzhiyun 		{ .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 },
281*4882a593Smuzhiyun 		{ .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 },
282*4882a593Smuzhiyun 		{ .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 },
283*4882a593Smuzhiyun 		{ .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 },
284*4882a593Smuzhiyun 		{ .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 },
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 		{ .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 },
287*4882a593Smuzhiyun 		{ .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 },
288*4882a593Smuzhiyun 		{ .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 },
289*4882a593Smuzhiyun 		{ .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 },
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 		/* Bayer RGB formats */
292*4882a593Smuzhiyun 		{ .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 },
293*4882a593Smuzhiyun 		{ .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 },
294*4882a593Smuzhiyun 		{ .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 },
295*4882a593Smuzhiyun 		{ .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 },
296*4882a593Smuzhiyun 		{ .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 },
297*4882a593Smuzhiyun 		{ .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 },
298*4882a593Smuzhiyun 		{ .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 },
299*4882a593Smuzhiyun 		{ .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 },
300*4882a593Smuzhiyun 		{ .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 },
301*4882a593Smuzhiyun 		{ .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 },
302*4882a593Smuzhiyun 		{ .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 },
303*4882a593Smuzhiyun 		{ .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 },
304*4882a593Smuzhiyun 		{ .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 },
305*4882a593Smuzhiyun 		{ .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 },
306*4882a593Smuzhiyun 		{ .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 },
307*4882a593Smuzhiyun 		{ .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 },
308*4882a593Smuzhiyun 		{ .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 },
309*4882a593Smuzhiyun 		{ .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 },
310*4882a593Smuzhiyun 		{ .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 },
311*4882a593Smuzhiyun 		{ .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 },
312*4882a593Smuzhiyun 	};
313*4882a593Smuzhiyun 	unsigned int i;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(formats); ++i)
316*4882a593Smuzhiyun 		if (formats[i].format == format)
317*4882a593Smuzhiyun 			return &formats[i];
318*4882a593Smuzhiyun 	return NULL;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun EXPORT_SYMBOL(v4l2_format_info);
321*4882a593Smuzhiyun 
v4l2_format_block_width(const struct v4l2_format_info * info,int plane)322*4882a593Smuzhiyun static inline unsigned int v4l2_format_block_width(const struct v4l2_format_info *info, int plane)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	if (!info->block_w[plane])
325*4882a593Smuzhiyun 		return 1;
326*4882a593Smuzhiyun 	return info->block_w[plane];
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
v4l2_format_block_height(const struct v4l2_format_info * info,int plane)329*4882a593Smuzhiyun static inline unsigned int v4l2_format_block_height(const struct v4l2_format_info *info, int plane)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	if (!info->block_h[plane])
332*4882a593Smuzhiyun 		return 1;
333*4882a593Smuzhiyun 	return info->block_h[plane];
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun 
v4l2_apply_frmsize_constraints(u32 * width,u32 * height,const struct v4l2_frmsize_stepwise * frmsize)336*4882a593Smuzhiyun void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
337*4882a593Smuzhiyun 				    const struct v4l2_frmsize_stepwise *frmsize)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun 	if (!frmsize)
340*4882a593Smuzhiyun 		return;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	/*
343*4882a593Smuzhiyun 	 * Clamp width/height to meet min/max constraints and round it up to
344*4882a593Smuzhiyun 	 * macroblock alignment.
345*4882a593Smuzhiyun 	 */
346*4882a593Smuzhiyun 	*width = clamp_roundup(*width, frmsize->min_width, frmsize->max_width,
347*4882a593Smuzhiyun 			       frmsize->step_width);
348*4882a593Smuzhiyun 	*height = clamp_roundup(*height, frmsize->min_height, frmsize->max_height,
349*4882a593Smuzhiyun 				frmsize->step_height);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints);
352*4882a593Smuzhiyun 
v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane * pixfmt,u32 pixelformat,u32 width,u32 height)353*4882a593Smuzhiyun int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
354*4882a593Smuzhiyun 			u32 pixelformat, u32 width, u32 height)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	const struct v4l2_format_info *info;
357*4882a593Smuzhiyun 	struct v4l2_plane_pix_format *plane;
358*4882a593Smuzhiyun 	int i;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	info = v4l2_format_info(pixelformat);
361*4882a593Smuzhiyun 	if (!info)
362*4882a593Smuzhiyun 		return -EINVAL;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	pixfmt->width = width;
365*4882a593Smuzhiyun 	pixfmt->height = height;
366*4882a593Smuzhiyun 	pixfmt->pixelformat = pixelformat;
367*4882a593Smuzhiyun 	pixfmt->num_planes = info->mem_planes;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	if (info->mem_planes == 1) {
370*4882a593Smuzhiyun 		plane = &pixfmt->plane_fmt[0];
371*4882a593Smuzhiyun 		plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
372*4882a593Smuzhiyun 		plane->sizeimage = 0;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 		for (i = 0; i < info->comp_planes; i++) {
375*4882a593Smuzhiyun 			unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
376*4882a593Smuzhiyun 			unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
377*4882a593Smuzhiyun 			unsigned int aligned_width;
378*4882a593Smuzhiyun 			unsigned int aligned_height;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 			aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
381*4882a593Smuzhiyun 			aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 			plane->sizeimage += info->bpp[i] *
384*4882a593Smuzhiyun 				DIV_ROUND_UP(aligned_width, hdiv) *
385*4882a593Smuzhiyun 				DIV_ROUND_UP(aligned_height, vdiv);
386*4882a593Smuzhiyun 		}
387*4882a593Smuzhiyun 	} else {
388*4882a593Smuzhiyun 		for (i = 0; i < info->comp_planes; i++) {
389*4882a593Smuzhiyun 			unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
390*4882a593Smuzhiyun 			unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
391*4882a593Smuzhiyun 			unsigned int aligned_width;
392*4882a593Smuzhiyun 			unsigned int aligned_height;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 			aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
395*4882a593Smuzhiyun 			aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 			plane = &pixfmt->plane_fmt[i];
398*4882a593Smuzhiyun 			plane->bytesperline =
399*4882a593Smuzhiyun 				info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv);
400*4882a593Smuzhiyun 			plane->sizeimage =
401*4882a593Smuzhiyun 				plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv);
402*4882a593Smuzhiyun 		}
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 	return 0;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp);
407*4882a593Smuzhiyun 
v4l2_fill_pixfmt(struct v4l2_pix_format * pixfmt,u32 pixelformat,u32 width,u32 height)408*4882a593Smuzhiyun int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
409*4882a593Smuzhiyun 		     u32 width, u32 height)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun 	const struct v4l2_format_info *info;
412*4882a593Smuzhiyun 	int i;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	info = v4l2_format_info(pixelformat);
415*4882a593Smuzhiyun 	if (!info)
416*4882a593Smuzhiyun 		return -EINVAL;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	/* Single planar API cannot be used for multi plane formats. */
419*4882a593Smuzhiyun 	if (info->mem_planes > 1)
420*4882a593Smuzhiyun 		return -EINVAL;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	pixfmt->width = width;
423*4882a593Smuzhiyun 	pixfmt->height = height;
424*4882a593Smuzhiyun 	pixfmt->pixelformat = pixelformat;
425*4882a593Smuzhiyun 	pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
426*4882a593Smuzhiyun 	pixfmt->sizeimage = 0;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	for (i = 0; i < info->comp_planes; i++) {
429*4882a593Smuzhiyun 		unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
430*4882a593Smuzhiyun 		unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
431*4882a593Smuzhiyun 		unsigned int aligned_width;
432*4882a593Smuzhiyun 		unsigned int aligned_height;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 		aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
435*4882a593Smuzhiyun 		aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 		pixfmt->sizeimage += info->bpp[i] *
438*4882a593Smuzhiyun 			DIV_ROUND_UP(aligned_width, hdiv) *
439*4882a593Smuzhiyun 			DIV_ROUND_UP(aligned_height, vdiv);
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun 	return 0;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
444