xref: /linux/drivers/media/platform/amd/isp4/isp4_video.c (revision 8c13415c8a4383447c21ec832b20b3b283f0e01a)
1*2ccf48afSBin Du // SPDX-License-Identifier: GPL-2.0+
2*2ccf48afSBin Du /*
3*2ccf48afSBin Du  * Copyright (C) 2025 Advanced Micro Devices, Inc.
4*2ccf48afSBin Du  */
5*2ccf48afSBin Du 
6*2ccf48afSBin Du #include <media/v4l2-ioctl.h>
7*2ccf48afSBin Du #include <media/v4l2-mc.h>
8*2ccf48afSBin Du #include <media/videobuf2-vmalloc.h>
9*2ccf48afSBin Du 
10*2ccf48afSBin Du #include "isp4_interface.h"
11*2ccf48afSBin Du #include "isp4_subdev.h"
12*2ccf48afSBin Du #include "isp4_video.h"
13*2ccf48afSBin Du 
14*2ccf48afSBin Du #define ISP4VID_ISP_DRV_NAME "amd_isp_capture"
15*2ccf48afSBin Du #define ISP4VID_MAX_PREVIEW_FPS 30
16*2ccf48afSBin Du #define ISP4VID_DEFAULT_FMT V4L2_PIX_FMT_NV12
17*2ccf48afSBin Du 
18*2ccf48afSBin Du #define ISP4VID_PAD_VIDEO_OUTPUT 0
19*2ccf48afSBin Du 
20*2ccf48afSBin Du /* time perframe default */
21*2ccf48afSBin Du #define ISP4VID_ISP_TPF_DEFAULT isp4vid_tpfs[0]
22*2ccf48afSBin Du 
23*2ccf48afSBin Du static const char *const isp4vid_video_dev_name = "Preview";
24*2ccf48afSBin Du 
25*2ccf48afSBin Du /* Sizes must be in increasing order */
26*2ccf48afSBin Du static const struct v4l2_frmsize_discrete isp4vid_frmsize[] = {
27*2ccf48afSBin Du 	{640, 360},
28*2ccf48afSBin Du 	{640, 480},
29*2ccf48afSBin Du 	{1280, 720},
30*2ccf48afSBin Du 	{1280, 960},
31*2ccf48afSBin Du 	{1920, 1080},
32*2ccf48afSBin Du 	{1920, 1440},
33*2ccf48afSBin Du 	{2560, 1440},
34*2ccf48afSBin Du 	{2880, 1620},
35*2ccf48afSBin Du 	{2880, 1624},
36*2ccf48afSBin Du 	{2888, 1808},
37*2ccf48afSBin Du };
38*2ccf48afSBin Du 
39*2ccf48afSBin Du static const u32 isp4vid_formats[] = {
40*2ccf48afSBin Du 	V4L2_PIX_FMT_NV12,
41*2ccf48afSBin Du 	V4L2_PIX_FMT_YUYV
42*2ccf48afSBin Du };
43*2ccf48afSBin Du 
44*2ccf48afSBin Du /* time perframe list */
45*2ccf48afSBin Du static const struct v4l2_fract isp4vid_tpfs[] = {
46*2ccf48afSBin Du 	{ 1, ISP4VID_MAX_PREVIEW_FPS }
47*2ccf48afSBin Du };
48*2ccf48afSBin Du 
49*2ccf48afSBin Du void isp4vid_handle_frame_done(struct isp4vid_dev *isp_vdev,
50*2ccf48afSBin Du 			       const struct isp4if_img_buf_info *img_buf)
51*2ccf48afSBin Du {
52*2ccf48afSBin Du 	struct isp4vid_capture_buffer *isp4vid_buf;
53*2ccf48afSBin Du 	void *vbuf;
54*2ccf48afSBin Du 
55*2ccf48afSBin Du 	scoped_guard(mutex, &isp_vdev->buf_list_lock) {
56*2ccf48afSBin Du 		isp4vid_buf = list_first_entry_or_null(&isp_vdev->buf_list,
57*2ccf48afSBin Du 						       typeof(*isp4vid_buf),
58*2ccf48afSBin Du 						       list);
59*2ccf48afSBin Du 		if (!isp4vid_buf)
60*2ccf48afSBin Du 			return;
61*2ccf48afSBin Du 
62*2ccf48afSBin Du 		vbuf = vb2_plane_vaddr(&isp4vid_buf->vb2.vb2_buf, 0);
63*2ccf48afSBin Du 
64*2ccf48afSBin Du 		if (vbuf != img_buf->planes[0].sys_addr) {
65*2ccf48afSBin Du 			dev_err(isp_vdev->dev, "Invalid vbuf\n");
66*2ccf48afSBin Du 			return;
67*2ccf48afSBin Du 		}
68*2ccf48afSBin Du 
69*2ccf48afSBin Du 		list_del(&isp4vid_buf->list);
70*2ccf48afSBin Du 	}
71*2ccf48afSBin Du 
72*2ccf48afSBin Du 	/* Fill the buffer */
73*2ccf48afSBin Du 	isp4vid_buf->vb2.vb2_buf.timestamp = ktime_get_ns();
74*2ccf48afSBin Du 	isp4vid_buf->vb2.sequence = isp_vdev->sequence++;
75*2ccf48afSBin Du 	isp4vid_buf->vb2.field = V4L2_FIELD_ANY;
76*2ccf48afSBin Du 
77*2ccf48afSBin Du 	vb2_set_plane_payload(&isp4vid_buf->vb2.vb2_buf,
78*2ccf48afSBin Du 			      0, isp_vdev->format.sizeimage);
79*2ccf48afSBin Du 
80*2ccf48afSBin Du 	vb2_buffer_done(&isp4vid_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE);
81*2ccf48afSBin Du 
82*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "call vb2_buffer_done(size=%u)\n",
83*2ccf48afSBin Du 		isp_vdev->format.sizeimage);
84*2ccf48afSBin Du }
85*2ccf48afSBin Du 
86*2ccf48afSBin Du static const struct v4l2_pix_format isp4vid_fmt_default = {
87*2ccf48afSBin Du 	.width = 1920,
88*2ccf48afSBin Du 	.height = 1080,
89*2ccf48afSBin Du 	.pixelformat = ISP4VID_DEFAULT_FMT,
90*2ccf48afSBin Du 	.field = V4L2_FIELD_NONE,
91*2ccf48afSBin Du 	.colorspace = V4L2_COLORSPACE_SRGB,
92*2ccf48afSBin Du };
93*2ccf48afSBin Du 
94*2ccf48afSBin Du static void isp4vid_capture_return_all_buffers(struct isp4vid_dev *isp_vdev,
95*2ccf48afSBin Du 					       enum vb2_buffer_state state)
96*2ccf48afSBin Du {
97*2ccf48afSBin Du 	struct isp4vid_capture_buffer *vbuf, *node;
98*2ccf48afSBin Du 
99*2ccf48afSBin Du 	scoped_guard(mutex, &isp_vdev->buf_list_lock) {
100*2ccf48afSBin Du 		list_for_each_entry_safe(vbuf, node, &isp_vdev->buf_list, list)
101*2ccf48afSBin Du 			vb2_buffer_done(&vbuf->vb2.vb2_buf, state);
102*2ccf48afSBin Du 		INIT_LIST_HEAD(&isp_vdev->buf_list);
103*2ccf48afSBin Du 	}
104*2ccf48afSBin Du 
105*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "call vb2_buffer_done(%d)\n", state);
106*2ccf48afSBin Du }
107*2ccf48afSBin Du 
108*2ccf48afSBin Du static int isp4vid_vdev_link_validate(struct media_link *link)
109*2ccf48afSBin Du {
110*2ccf48afSBin Du 	return 0;
111*2ccf48afSBin Du }
112*2ccf48afSBin Du 
113*2ccf48afSBin Du static const struct media_entity_operations isp4vid_vdev_ent_ops = {
114*2ccf48afSBin Du 	.link_validate = isp4vid_vdev_link_validate,
115*2ccf48afSBin Du };
116*2ccf48afSBin Du 
117*2ccf48afSBin Du static const struct v4l2_file_operations isp4vid_vdev_fops = {
118*2ccf48afSBin Du 	.owner = THIS_MODULE,
119*2ccf48afSBin Du 	.open = v4l2_fh_open,
120*2ccf48afSBin Du 	.release = vb2_fop_release,
121*2ccf48afSBin Du 	.read = vb2_fop_read,
122*2ccf48afSBin Du 	.poll = vb2_fop_poll,
123*2ccf48afSBin Du 	.unlocked_ioctl = video_ioctl2,
124*2ccf48afSBin Du 	.mmap = vb2_fop_mmap,
125*2ccf48afSBin Du };
126*2ccf48afSBin Du 
127*2ccf48afSBin Du static int isp4vid_ioctl_querycap(struct file *file, void *fh,
128*2ccf48afSBin Du 				  struct v4l2_capability *cap)
129*2ccf48afSBin Du {
130*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = video_drvdata(file);
131*2ccf48afSBin Du 
132*2ccf48afSBin Du 	strscpy(cap->driver, ISP4VID_ISP_DRV_NAME, sizeof(cap->driver));
133*2ccf48afSBin Du 	snprintf(cap->card, sizeof(cap->card), "%s", ISP4VID_ISP_DRV_NAME);
134*2ccf48afSBin Du 	cap->capabilities |= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
135*2ccf48afSBin Du 
136*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "%s|capabilities=0x%X\n", isp_vdev->vdev.name,
137*2ccf48afSBin Du 		cap->capabilities);
138*2ccf48afSBin Du 
139*2ccf48afSBin Du 	return 0;
140*2ccf48afSBin Du }
141*2ccf48afSBin Du 
142*2ccf48afSBin Du static int isp4vid_g_fmt_vid_cap(struct file *file, void *priv,
143*2ccf48afSBin Du 				 struct v4l2_format *f)
144*2ccf48afSBin Du {
145*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = video_drvdata(file);
146*2ccf48afSBin Du 
147*2ccf48afSBin Du 	f->fmt.pix = isp_vdev->format;
148*2ccf48afSBin Du 
149*2ccf48afSBin Du 	return 0;
150*2ccf48afSBin Du }
151*2ccf48afSBin Du 
152*2ccf48afSBin Du static int isp4vid_fill_buffer_size(struct v4l2_pix_format *fmt)
153*2ccf48afSBin Du {
154*2ccf48afSBin Du 	int ret = 0;
155*2ccf48afSBin Du 
156*2ccf48afSBin Du 	switch (fmt->pixelformat) {
157*2ccf48afSBin Du 	case V4L2_PIX_FMT_NV12:
158*2ccf48afSBin Du 		fmt->bytesperline = fmt->width;
159*2ccf48afSBin Du 		fmt->sizeimage = fmt->bytesperline * fmt->height * 3 / 2;
160*2ccf48afSBin Du 		break;
161*2ccf48afSBin Du 	case V4L2_PIX_FMT_YUYV:
162*2ccf48afSBin Du 		fmt->bytesperline = fmt->width * 2;
163*2ccf48afSBin Du 		fmt->sizeimage = fmt->bytesperline * fmt->height;
164*2ccf48afSBin Du 		break;
165*2ccf48afSBin Du 	default:
166*2ccf48afSBin Du 		ret = -EINVAL;
167*2ccf48afSBin Du 		break;
168*2ccf48afSBin Du 	}
169*2ccf48afSBin Du 
170*2ccf48afSBin Du 	return ret;
171*2ccf48afSBin Du }
172*2ccf48afSBin Du 
173*2ccf48afSBin Du static int isp4vid_try_fmt_vid_cap(struct file *file, void *priv,
174*2ccf48afSBin Du 				   struct v4l2_format *f)
175*2ccf48afSBin Du {
176*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = video_drvdata(file);
177*2ccf48afSBin Du 	struct v4l2_pix_format *format = &f->fmt.pix;
178*2ccf48afSBin Du 	const struct v4l2_frmsize_discrete *fsz;
179*2ccf48afSBin Du 	size_t i;
180*2ccf48afSBin Du 
181*2ccf48afSBin Du 	/*
182*2ccf48afSBin Du 	 * Check if the hardware supports the requested format, use the default
183*2ccf48afSBin Du 	 * format otherwise.
184*2ccf48afSBin Du 	 */
185*2ccf48afSBin Du 	for (i = 0; i < ARRAY_SIZE(isp4vid_formats); i++)
186*2ccf48afSBin Du 		if (isp4vid_formats[i] == format->pixelformat)
187*2ccf48afSBin Du 			break;
188*2ccf48afSBin Du 
189*2ccf48afSBin Du 	if (i == ARRAY_SIZE(isp4vid_formats))
190*2ccf48afSBin Du 		format->pixelformat = ISP4VID_DEFAULT_FMT;
191*2ccf48afSBin Du 
192*2ccf48afSBin Du 	switch (format->pixelformat) {
193*2ccf48afSBin Du 	case V4L2_PIX_FMT_NV12:
194*2ccf48afSBin Du 	case V4L2_PIX_FMT_YUYV:
195*2ccf48afSBin Du 		fsz = v4l2_find_nearest_size(isp4vid_frmsize,
196*2ccf48afSBin Du 					     ARRAY_SIZE(isp4vid_frmsize),
197*2ccf48afSBin Du 					     width, height, format->width,
198*2ccf48afSBin Du 					     format->height);
199*2ccf48afSBin Du 		format->width = fsz->width;
200*2ccf48afSBin Du 		format->height = fsz->height;
201*2ccf48afSBin Du 		break;
202*2ccf48afSBin Du 	default:
203*2ccf48afSBin Du 		dev_err(isp_vdev->dev, "%s|unsupported fmt=%u\n",
204*2ccf48afSBin Du 			isp_vdev->vdev.name,
205*2ccf48afSBin Du 			format->pixelformat);
206*2ccf48afSBin Du 		return -EINVAL;
207*2ccf48afSBin Du 	}
208*2ccf48afSBin Du 
209*2ccf48afSBin Du 	/*
210*2ccf48afSBin Du 	 * There is no need to check the return value, as failure will never
211*2ccf48afSBin Du 	 * happen here
212*2ccf48afSBin Du 	 */
213*2ccf48afSBin Du 	isp4vid_fill_buffer_size(format);
214*2ccf48afSBin Du 
215*2ccf48afSBin Du 	if (format->field == V4L2_FIELD_ANY)
216*2ccf48afSBin Du 		format->field = isp4vid_fmt_default.field;
217*2ccf48afSBin Du 
218*2ccf48afSBin Du 	if (format->colorspace == V4L2_COLORSPACE_DEFAULT)
219*2ccf48afSBin Du 		format->colorspace = isp4vid_fmt_default.colorspace;
220*2ccf48afSBin Du 
221*2ccf48afSBin Du 	return 0;
222*2ccf48afSBin Du }
223*2ccf48afSBin Du 
224*2ccf48afSBin Du static int isp4vid_set_fmt_2_isp(struct v4l2_subdev *sdev,
225*2ccf48afSBin Du 				 struct v4l2_pix_format *pix_fmt)
226*2ccf48afSBin Du {
227*2ccf48afSBin Du 	struct v4l2_subdev_format fmt = {};
228*2ccf48afSBin Du 
229*2ccf48afSBin Du 	switch (pix_fmt->pixelformat) {
230*2ccf48afSBin Du 	case V4L2_PIX_FMT_NV12:
231*2ccf48afSBin Du 		fmt.format.code = MEDIA_BUS_FMT_YUYV8_1_5X8;
232*2ccf48afSBin Du 		break;
233*2ccf48afSBin Du 	case V4L2_PIX_FMT_YUYV:
234*2ccf48afSBin Du 		fmt.format.code = MEDIA_BUS_FMT_YUYV8_1X16;
235*2ccf48afSBin Du 		break;
236*2ccf48afSBin Du 	default:
237*2ccf48afSBin Du 		return -EINVAL;
238*2ccf48afSBin Du 	}
239*2ccf48afSBin Du 	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
240*2ccf48afSBin Du 	fmt.pad = ISP4VID_PAD_VIDEO_OUTPUT;
241*2ccf48afSBin Du 	fmt.format.width = pix_fmt->width;
242*2ccf48afSBin Du 	fmt.format.height = pix_fmt->height;
243*2ccf48afSBin Du 	return v4l2_subdev_call(sdev, pad, set_fmt, NULL, &fmt);
244*2ccf48afSBin Du }
245*2ccf48afSBin Du 
246*2ccf48afSBin Du static int isp4vid_s_fmt_vid_cap(struct file *file, void *priv,
247*2ccf48afSBin Du 				 struct v4l2_format *f)
248*2ccf48afSBin Du {
249*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = video_drvdata(file);
250*2ccf48afSBin Du 	int ret;
251*2ccf48afSBin Du 
252*2ccf48afSBin Du 	/* Do not change the format while stream is on */
253*2ccf48afSBin Du 	if (vb2_is_busy(&isp_vdev->vbq))
254*2ccf48afSBin Du 		return -EBUSY;
255*2ccf48afSBin Du 
256*2ccf48afSBin Du 	ret = isp4vid_try_fmt_vid_cap(file, priv, f);
257*2ccf48afSBin Du 	if (ret)
258*2ccf48afSBin Du 		return ret;
259*2ccf48afSBin Du 
260*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "%s|width height:%ux%u->%ux%u\n",
261*2ccf48afSBin Du 		isp_vdev->vdev.name,
262*2ccf48afSBin Du 		isp_vdev->format.width, isp_vdev->format.height,
263*2ccf48afSBin Du 		f->fmt.pix.width, f->fmt.pix.height);
264*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "%s|pixelformat:0x%x-0x%x\n",
265*2ccf48afSBin Du 		isp_vdev->vdev.name, isp_vdev->format.pixelformat,
266*2ccf48afSBin Du 		f->fmt.pix.pixelformat);
267*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "%s|bytesperline:%u->%u\n",
268*2ccf48afSBin Du 		isp_vdev->vdev.name, isp_vdev->format.bytesperline,
269*2ccf48afSBin Du 		f->fmt.pix.bytesperline);
270*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "%s|sizeimage:%u->%u\n",
271*2ccf48afSBin Du 		isp_vdev->vdev.name, isp_vdev->format.sizeimage,
272*2ccf48afSBin Du 		f->fmt.pix.sizeimage);
273*2ccf48afSBin Du 
274*2ccf48afSBin Du 	isp_vdev->format = f->fmt.pix;
275*2ccf48afSBin Du 	ret = isp4vid_set_fmt_2_isp(isp_vdev->isp_sdev, &isp_vdev->format);
276*2ccf48afSBin Du 
277*2ccf48afSBin Du 	return ret;
278*2ccf48afSBin Du }
279*2ccf48afSBin Du 
280*2ccf48afSBin Du static int isp4vid_enum_fmt_vid_cap(struct file *file, void *priv,
281*2ccf48afSBin Du 				    struct v4l2_fmtdesc *f)
282*2ccf48afSBin Du {
283*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = video_drvdata(file);
284*2ccf48afSBin Du 
285*2ccf48afSBin Du 	switch (f->index) {
286*2ccf48afSBin Du 	case 0:
287*2ccf48afSBin Du 		f->pixelformat = V4L2_PIX_FMT_NV12;
288*2ccf48afSBin Du 		break;
289*2ccf48afSBin Du 	case 1:
290*2ccf48afSBin Du 		f->pixelformat = V4L2_PIX_FMT_YUYV;
291*2ccf48afSBin Du 		break;
292*2ccf48afSBin Du 	default:
293*2ccf48afSBin Du 		return -EINVAL;
294*2ccf48afSBin Du 	}
295*2ccf48afSBin Du 
296*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "%s|index=%d, pixelformat=0x%X\n",
297*2ccf48afSBin Du 		isp_vdev->vdev.name, f->index, f->pixelformat);
298*2ccf48afSBin Du 
299*2ccf48afSBin Du 	return 0;
300*2ccf48afSBin Du }
301*2ccf48afSBin Du 
302*2ccf48afSBin Du static int isp4vid_enum_framesizes(struct file *file, void *fh,
303*2ccf48afSBin Du 				   struct v4l2_frmsizeenum *fsize)
304*2ccf48afSBin Du {
305*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = video_drvdata(file);
306*2ccf48afSBin Du 	unsigned int i;
307*2ccf48afSBin Du 
308*2ccf48afSBin Du 	for (i = 0; i < ARRAY_SIZE(isp4vid_formats); i++) {
309*2ccf48afSBin Du 		if (isp4vid_formats[i] == fsize->pixel_format)
310*2ccf48afSBin Du 			break;
311*2ccf48afSBin Du 	}
312*2ccf48afSBin Du 
313*2ccf48afSBin Du 	if (i == ARRAY_SIZE(isp4vid_formats))
314*2ccf48afSBin Du 		return -EINVAL;
315*2ccf48afSBin Du 
316*2ccf48afSBin Du 	if (fsize->index < ARRAY_SIZE(isp4vid_frmsize)) {
317*2ccf48afSBin Du 		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
318*2ccf48afSBin Du 		fsize->discrete = isp4vid_frmsize[fsize->index];
319*2ccf48afSBin Du 		dev_dbg(isp_vdev->dev, "%s|size[%d]=%dx%d\n",
320*2ccf48afSBin Du 			isp_vdev->vdev.name, fsize->index,
321*2ccf48afSBin Du 			fsize->discrete.width, fsize->discrete.height);
322*2ccf48afSBin Du 	} else {
323*2ccf48afSBin Du 		return -EINVAL;
324*2ccf48afSBin Du 	}
325*2ccf48afSBin Du 
326*2ccf48afSBin Du 	return 0;
327*2ccf48afSBin Du }
328*2ccf48afSBin Du 
329*2ccf48afSBin Du static int isp4vid_ioctl_enum_frameintervals(struct file *file, void *priv,
330*2ccf48afSBin Du 					     struct v4l2_frmivalenum *fival)
331*2ccf48afSBin Du {
332*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = video_drvdata(file);
333*2ccf48afSBin Du 	size_t i;
334*2ccf48afSBin Du 
335*2ccf48afSBin Du 	if (fival->index >= ARRAY_SIZE(isp4vid_tpfs))
336*2ccf48afSBin Du 		return -EINVAL;
337*2ccf48afSBin Du 
338*2ccf48afSBin Du 	for (i = 0; i < ARRAY_SIZE(isp4vid_formats); i++)
339*2ccf48afSBin Du 		if (isp4vid_formats[i] == fival->pixel_format)
340*2ccf48afSBin Du 			break;
341*2ccf48afSBin Du 
342*2ccf48afSBin Du 	if (i == ARRAY_SIZE(isp4vid_formats))
343*2ccf48afSBin Du 		return -EINVAL;
344*2ccf48afSBin Du 
345*2ccf48afSBin Du 	for (i = 0; i < ARRAY_SIZE(isp4vid_frmsize); i++)
346*2ccf48afSBin Du 		if (isp4vid_frmsize[i].width == fival->width &&
347*2ccf48afSBin Du 		    isp4vid_frmsize[i].height == fival->height)
348*2ccf48afSBin Du 			break;
349*2ccf48afSBin Du 
350*2ccf48afSBin Du 	if (i == ARRAY_SIZE(isp4vid_frmsize))
351*2ccf48afSBin Du 		return -EINVAL;
352*2ccf48afSBin Du 
353*2ccf48afSBin Du 	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
354*2ccf48afSBin Du 	fival->discrete = isp4vid_tpfs[fival->index];
355*2ccf48afSBin Du 	v4l2_simplify_fraction(&fival->discrete.numerator,
356*2ccf48afSBin Du 			       &fival->discrete.denominator, 8, 333);
357*2ccf48afSBin Du 
358*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "%s|interval[%d]=%d/%d\n",
359*2ccf48afSBin Du 		isp_vdev->vdev.name, fival->index,
360*2ccf48afSBin Du 		fival->discrete.numerator,
361*2ccf48afSBin Du 		fival->discrete.denominator);
362*2ccf48afSBin Du 
363*2ccf48afSBin Du 	return 0;
364*2ccf48afSBin Du }
365*2ccf48afSBin Du 
366*2ccf48afSBin Du static int isp4vid_ioctl_g_param(struct file *file, void *priv,
367*2ccf48afSBin Du 				 struct v4l2_streamparm *param)
368*2ccf48afSBin Du {
369*2ccf48afSBin Du 	struct v4l2_captureparm *capture = &param->parm.capture;
370*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = video_drvdata(file);
371*2ccf48afSBin Du 
372*2ccf48afSBin Du 	if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
373*2ccf48afSBin Du 		return -EINVAL;
374*2ccf48afSBin Du 
375*2ccf48afSBin Du 	capture->capability   = V4L2_CAP_TIMEPERFRAME;
376*2ccf48afSBin Du 	capture->timeperframe = isp_vdev->timeperframe;
377*2ccf48afSBin Du 	capture->readbuffers  = 0;
378*2ccf48afSBin Du 
379*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "%s|timeperframe=%d/%d\n", isp_vdev->vdev.name,
380*2ccf48afSBin Du 		capture->timeperframe.numerator,
381*2ccf48afSBin Du 		capture->timeperframe.denominator);
382*2ccf48afSBin Du 
383*2ccf48afSBin Du 	return 0;
384*2ccf48afSBin Du }
385*2ccf48afSBin Du 
386*2ccf48afSBin Du static const struct v4l2_ioctl_ops isp4vid_vdev_ioctl_ops = {
387*2ccf48afSBin Du 	.vidioc_querycap            = isp4vid_ioctl_querycap,
388*2ccf48afSBin Du 	.vidioc_enum_fmt_vid_cap    = isp4vid_enum_fmt_vid_cap,
389*2ccf48afSBin Du 	.vidioc_g_fmt_vid_cap       = isp4vid_g_fmt_vid_cap,
390*2ccf48afSBin Du 	.vidioc_s_fmt_vid_cap       = isp4vid_s_fmt_vid_cap,
391*2ccf48afSBin Du 	.vidioc_try_fmt_vid_cap     = isp4vid_try_fmt_vid_cap,
392*2ccf48afSBin Du 	.vidioc_reqbufs             = vb2_ioctl_reqbufs,
393*2ccf48afSBin Du 	.vidioc_querybuf            = vb2_ioctl_querybuf,
394*2ccf48afSBin Du 	.vidioc_qbuf                = vb2_ioctl_qbuf,
395*2ccf48afSBin Du 	.vidioc_expbuf              = vb2_ioctl_expbuf,
396*2ccf48afSBin Du 	.vidioc_dqbuf               = vb2_ioctl_dqbuf,
397*2ccf48afSBin Du 	.vidioc_create_bufs         = vb2_ioctl_create_bufs,
398*2ccf48afSBin Du 	.vidioc_prepare_buf         = vb2_ioctl_prepare_buf,
399*2ccf48afSBin Du 	.vidioc_streamon            = vb2_ioctl_streamon,
400*2ccf48afSBin Du 	.vidioc_streamoff           = vb2_ioctl_streamoff,
401*2ccf48afSBin Du 	.vidioc_g_parm              = isp4vid_ioctl_g_param,
402*2ccf48afSBin Du 	.vidioc_s_parm              = isp4vid_ioctl_g_param,
403*2ccf48afSBin Du 	.vidioc_enum_framesizes     = isp4vid_enum_framesizes,
404*2ccf48afSBin Du 	.vidioc_enum_frameintervals = isp4vid_ioctl_enum_frameintervals,
405*2ccf48afSBin Du };
406*2ccf48afSBin Du 
407*2ccf48afSBin Du static unsigned int isp4vid_get_image_size(struct v4l2_pix_format *fmt)
408*2ccf48afSBin Du {
409*2ccf48afSBin Du 	switch (fmt->pixelformat) {
410*2ccf48afSBin Du 	case V4L2_PIX_FMT_NV12:
411*2ccf48afSBin Du 		return fmt->width * fmt->height * 3 / 2;
412*2ccf48afSBin Du 	case V4L2_PIX_FMT_YUYV:
413*2ccf48afSBin Du 		return fmt->width * fmt->height * 2;
414*2ccf48afSBin Du 	default:
415*2ccf48afSBin Du 		return 0;
416*2ccf48afSBin Du 	}
417*2ccf48afSBin Du }
418*2ccf48afSBin Du 
419*2ccf48afSBin Du static int isp4vid_qops_queue_setup(struct vb2_queue *vq,
420*2ccf48afSBin Du 				    unsigned int *nbuffers,
421*2ccf48afSBin Du 				    unsigned int *nplanes, unsigned int sizes[],
422*2ccf48afSBin Du 				    struct device *alloc_devs[])
423*2ccf48afSBin Du {
424*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vq);
425*2ccf48afSBin Du 	unsigned int q_num_bufs = vb2_get_num_buffers(vq);
426*2ccf48afSBin Du 
427*2ccf48afSBin Du 	if (*nplanes > 1) {
428*2ccf48afSBin Du 		dev_err(isp_vdev->dev,
429*2ccf48afSBin Du 			"fail to setup queue, no mplane supported %u\n",
430*2ccf48afSBin Du 			*nplanes);
431*2ccf48afSBin Du 		return -EINVAL;
432*2ccf48afSBin Du 	}
433*2ccf48afSBin Du 
434*2ccf48afSBin Du 	if (*nplanes == 1) {
435*2ccf48afSBin Du 		unsigned int size;
436*2ccf48afSBin Du 
437*2ccf48afSBin Du 		size = isp4vid_get_image_size(&isp_vdev->format);
438*2ccf48afSBin Du 		if (sizes[0] < size) {
439*2ccf48afSBin Du 			dev_err(isp_vdev->dev,
440*2ccf48afSBin Du 				"fail for small plane size %u, %u expected\n",
441*2ccf48afSBin Du 				sizes[0], size);
442*2ccf48afSBin Du 			return -EINVAL;
443*2ccf48afSBin Du 		}
444*2ccf48afSBin Du 	}
445*2ccf48afSBin Du 
446*2ccf48afSBin Du 	if (q_num_bufs + *nbuffers < ISP4IF_MAX_STREAM_BUF_COUNT)
447*2ccf48afSBin Du 		*nbuffers = ISP4IF_MAX_STREAM_BUF_COUNT - q_num_bufs;
448*2ccf48afSBin Du 
449*2ccf48afSBin Du 	switch (isp_vdev->format.pixelformat) {
450*2ccf48afSBin Du 	case V4L2_PIX_FMT_NV12:
451*2ccf48afSBin Du 	case V4L2_PIX_FMT_YUYV: {
452*2ccf48afSBin Du 		*nplanes = 1;
453*2ccf48afSBin Du 		sizes[0] = max(sizes[0], isp_vdev->format.sizeimage);
454*2ccf48afSBin Du 		isp_vdev->format.sizeimage = sizes[0];
455*2ccf48afSBin Du 	}
456*2ccf48afSBin Du 	break;
457*2ccf48afSBin Du 	default:
458*2ccf48afSBin Du 		dev_err(isp_vdev->dev, "%s|unsupported fmt=%u\n",
459*2ccf48afSBin Du 			isp_vdev->vdev.name, isp_vdev->format.pixelformat);
460*2ccf48afSBin Du 		return -EINVAL;
461*2ccf48afSBin Du 	}
462*2ccf48afSBin Du 
463*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "%s|*nbuffers=%u *nplanes=%u sizes[0]=%u\n",
464*2ccf48afSBin Du 		isp_vdev->vdev.name,
465*2ccf48afSBin Du 		*nbuffers, *nplanes, sizes[0]);
466*2ccf48afSBin Du 
467*2ccf48afSBin Du 	return 0;
468*2ccf48afSBin Du }
469*2ccf48afSBin Du 
470*2ccf48afSBin Du static void isp4vid_qops_buffer_queue(struct vb2_buffer *vb)
471*2ccf48afSBin Du {
472*2ccf48afSBin Du 	struct isp4vid_capture_buffer *buf =
473*2ccf48afSBin Du 		container_of(vb, struct isp4vid_capture_buffer, vb2.vb2_buf);
474*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
475*2ccf48afSBin Du 	struct isp4if_img_buf_info *img_buf = &buf->img_buf;
476*2ccf48afSBin Du 	void *vaddr = vb2_plane_vaddr(vb, 0);
477*2ccf48afSBin Du 
478*2ccf48afSBin Du 	dev_dbg(isp_vdev->dev, "queue buf, vaddr %p, gpuva 0x%llx, size %u\n",
479*2ccf48afSBin Du 		vaddr, buf->gpu_addr, vb->planes[0].length);
480*2ccf48afSBin Du 
481*2ccf48afSBin Du 	switch (isp_vdev->format.pixelformat) {
482*2ccf48afSBin Du 	case V4L2_PIX_FMT_NV12: {
483*2ccf48afSBin Du 		u32 y_size = isp_vdev->format.sizeimage / 3 * 2;
484*2ccf48afSBin Du 		u32 uv_size = isp_vdev->format.sizeimage / 3;
485*2ccf48afSBin Du 
486*2ccf48afSBin Du 		img_buf->planes[0].len = y_size;
487*2ccf48afSBin Du 		img_buf->planes[0].sys_addr = vaddr;
488*2ccf48afSBin Du 		img_buf->planes[0].mc_addr = buf->gpu_addr;
489*2ccf48afSBin Du 
490*2ccf48afSBin Du 		dev_dbg(isp_vdev->dev, "img_buf[0]: mc=0x%llx size=%u\n",
491*2ccf48afSBin Du 			img_buf->planes[0].mc_addr,
492*2ccf48afSBin Du 			img_buf->planes[0].len);
493*2ccf48afSBin Du 
494*2ccf48afSBin Du 		img_buf->planes[1].len = uv_size;
495*2ccf48afSBin Du 		img_buf->planes[1].sys_addr = vaddr + y_size;
496*2ccf48afSBin Du 		img_buf->planes[1].mc_addr = buf->gpu_addr + y_size;
497*2ccf48afSBin Du 
498*2ccf48afSBin Du 		dev_dbg(isp_vdev->dev, "img_buf[1]: mc=0x%llx size=%u\n",
499*2ccf48afSBin Du 			img_buf->planes[1].mc_addr,
500*2ccf48afSBin Du 			img_buf->planes[1].len);
501*2ccf48afSBin Du 
502*2ccf48afSBin Du 		img_buf->planes[2].len = 0;
503*2ccf48afSBin Du 	}
504*2ccf48afSBin Du 	break;
505*2ccf48afSBin Du 	case V4L2_PIX_FMT_YUYV: {
506*2ccf48afSBin Du 		img_buf->planes[0].len = isp_vdev->format.sizeimage;
507*2ccf48afSBin Du 		img_buf->planes[0].sys_addr = vaddr;
508*2ccf48afSBin Du 		img_buf->planes[0].mc_addr = buf->gpu_addr;
509*2ccf48afSBin Du 
510*2ccf48afSBin Du 		dev_dbg(isp_vdev->dev, "img_buf[0]: mc=0x%llx size=%u\n",
511*2ccf48afSBin Du 			img_buf->planes[0].mc_addr,
512*2ccf48afSBin Du 			img_buf->planes[0].len);
513*2ccf48afSBin Du 
514*2ccf48afSBin Du 		img_buf->planes[1].len = 0;
515*2ccf48afSBin Du 		img_buf->planes[2].len = 0;
516*2ccf48afSBin Du 	}
517*2ccf48afSBin Du 	break;
518*2ccf48afSBin Du 	default:
519*2ccf48afSBin Du 		dev_err(isp_vdev->dev, "%s|unsupported fmt=%u\n",
520*2ccf48afSBin Du 			isp_vdev->vdev.name, isp_vdev->format.pixelformat);
521*2ccf48afSBin Du 		return;
522*2ccf48afSBin Du 	}
523*2ccf48afSBin Du 
524*2ccf48afSBin Du 	if (isp_vdev->stream_started)
525*2ccf48afSBin Du 		isp4sd_ioc_send_img_buf(isp_vdev->isp_sdev, img_buf);
526*2ccf48afSBin Du 
527*2ccf48afSBin Du 	scoped_guard(mutex, &isp_vdev->buf_list_lock)
528*2ccf48afSBin Du 		list_add_tail(&buf->list, &isp_vdev->buf_list);
529*2ccf48afSBin Du }
530*2ccf48afSBin Du 
531*2ccf48afSBin Du static int isp4vid_qops_start_streaming(struct vb2_queue *vq,
532*2ccf48afSBin Du 					unsigned int count)
533*2ccf48afSBin Du {
534*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vq);
535*2ccf48afSBin Du 	struct isp4vid_capture_buffer *isp4vid_buf;
536*2ccf48afSBin Du 	struct media_entity *entity;
537*2ccf48afSBin Du 	struct v4l2_subdev *subdev;
538*2ccf48afSBin Du 	struct media_pad *pad;
539*2ccf48afSBin Du 	int ret = 0;
540*2ccf48afSBin Du 
541*2ccf48afSBin Du 	isp_vdev->sequence = 0;
542*2ccf48afSBin Du 
543*2ccf48afSBin Du 	ret = isp4sd_pwron_and_init(isp_vdev->isp_sdev);
544*2ccf48afSBin Du 	if (ret) {
545*2ccf48afSBin Du 		dev_err(isp_vdev->dev, "power up isp fail %d\n", ret);
546*2ccf48afSBin Du 		goto release_buffers;
547*2ccf48afSBin Du 	}
548*2ccf48afSBin Du 
549*2ccf48afSBin Du 	entity = &isp_vdev->vdev.entity;
550*2ccf48afSBin Du 	while (1) {
551*2ccf48afSBin Du 		pad = &entity->pads[0];
552*2ccf48afSBin Du 		if (!(pad->flags & MEDIA_PAD_FL_SINK))
553*2ccf48afSBin Du 			break;
554*2ccf48afSBin Du 
555*2ccf48afSBin Du 		pad = media_pad_remote_pad_first(pad);
556*2ccf48afSBin Du 		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
557*2ccf48afSBin Du 			break;
558*2ccf48afSBin Du 
559*2ccf48afSBin Du 		entity = pad->entity;
560*2ccf48afSBin Du 		subdev = media_entity_to_v4l2_subdev(entity);
561*2ccf48afSBin Du 
562*2ccf48afSBin Du 		ret = v4l2_subdev_call(subdev, video, s_stream, 1);
563*2ccf48afSBin Du 		if (ret < 0 && ret != -ENOIOCTLCMD) {
564*2ccf48afSBin Du 			dev_dbg(isp_vdev->dev, "fail start streaming: %s %d\n",
565*2ccf48afSBin Du 				subdev->name, ret);
566*2ccf48afSBin Du 			goto release_buffers;
567*2ccf48afSBin Du 		}
568*2ccf48afSBin Du 	}
569*2ccf48afSBin Du 
570*2ccf48afSBin Du 	list_for_each_entry(isp4vid_buf, &isp_vdev->buf_list, list)
571*2ccf48afSBin Du 		isp4sd_ioc_send_img_buf(isp_vdev->isp_sdev,
572*2ccf48afSBin Du 					&isp4vid_buf->img_buf);
573*2ccf48afSBin Du 
574*2ccf48afSBin Du 	isp_vdev->stream_started = true;
575*2ccf48afSBin Du 
576*2ccf48afSBin Du 	return 0;
577*2ccf48afSBin Du 
578*2ccf48afSBin Du release_buffers:
579*2ccf48afSBin Du 	isp4vid_capture_return_all_buffers(isp_vdev, VB2_BUF_STATE_QUEUED);
580*2ccf48afSBin Du 	return ret;
581*2ccf48afSBin Du }
582*2ccf48afSBin Du 
583*2ccf48afSBin Du static void isp4vid_qops_stop_streaming(struct vb2_queue *vq)
584*2ccf48afSBin Du {
585*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vq);
586*2ccf48afSBin Du 	struct media_entity *entity;
587*2ccf48afSBin Du 	struct v4l2_subdev *subdev;
588*2ccf48afSBin Du 	struct media_pad *pad;
589*2ccf48afSBin Du 	int ret;
590*2ccf48afSBin Du 
591*2ccf48afSBin Du 	entity = &isp_vdev->vdev.entity;
592*2ccf48afSBin Du 	while (1) {
593*2ccf48afSBin Du 		pad = &entity->pads[0];
594*2ccf48afSBin Du 		if (!(pad->flags & MEDIA_PAD_FL_SINK))
595*2ccf48afSBin Du 			break;
596*2ccf48afSBin Du 
597*2ccf48afSBin Du 		pad = media_pad_remote_pad_first(pad);
598*2ccf48afSBin Du 		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
599*2ccf48afSBin Du 			break;
600*2ccf48afSBin Du 
601*2ccf48afSBin Du 		entity = pad->entity;
602*2ccf48afSBin Du 		subdev = media_entity_to_v4l2_subdev(entity);
603*2ccf48afSBin Du 
604*2ccf48afSBin Du 		ret = v4l2_subdev_call(subdev, video, s_stream, 0);
605*2ccf48afSBin Du 
606*2ccf48afSBin Du 		if (ret < 0 && ret != -ENOIOCTLCMD)
607*2ccf48afSBin Du 			dev_dbg(isp_vdev->dev, "fail stop streaming: %s %d\n",
608*2ccf48afSBin Du 				subdev->name, ret);
609*2ccf48afSBin Du 	}
610*2ccf48afSBin Du 
611*2ccf48afSBin Du 	isp_vdev->stream_started = false;
612*2ccf48afSBin Du 	isp4sd_pwroff_and_deinit(isp_vdev->isp_sdev);
613*2ccf48afSBin Du 
614*2ccf48afSBin Du 	/* Release all active buffers */
615*2ccf48afSBin Du 	isp4vid_capture_return_all_buffers(isp_vdev, VB2_BUF_STATE_ERROR);
616*2ccf48afSBin Du }
617*2ccf48afSBin Du 
618*2ccf48afSBin Du static int isp4vid_qops_buf_init(struct vb2_buffer *vb)
619*2ccf48afSBin Du {
620*2ccf48afSBin Du 	struct isp4vid_capture_buffer *buf =
621*2ccf48afSBin Du 		container_of(vb, struct isp4vid_capture_buffer, vb2.vb2_buf);
622*2ccf48afSBin Du 	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
623*2ccf48afSBin Du 	void *mem_priv = vb->planes[0].mem_priv;
624*2ccf48afSBin Du 	struct device *dev = isp_vdev->dev;
625*2ccf48afSBin Du 	u64 gpu_addr;
626*2ccf48afSBin Du 	void *bo;
627*2ccf48afSBin Du 	int ret;
628*2ccf48afSBin Du 
629*2ccf48afSBin Du 	if (vb->planes[0].dbuf) {
630*2ccf48afSBin Du 		buf->dbuf = vb->planes[0].dbuf;
631*2ccf48afSBin Du 	} else {
632*2ccf48afSBin Du 		/*
633*2ccf48afSBin Du 		 * HAS_DMA is a Kconfig dependency so CONFIG_HAS_DMA is always
634*2ccf48afSBin Du 		 * defined when this driver is compiled. The #else branch is
635*2ccf48afSBin Du 		 * kept as a safeguard in case the dependency is ever removed.
636*2ccf48afSBin Du 		 */
637*2ccf48afSBin Du #ifdef CONFIG_HAS_DMA
638*2ccf48afSBin Du 		buf->dbuf = vb2_vmalloc_memops.get_dmabuf(vb, mem_priv, 0);
639*2ccf48afSBin Du 		if (IS_ERR_OR_NULL(buf->dbuf)) {
640*2ccf48afSBin Du 			dev_err(dev, "fail to get dma buf\n");
641*2ccf48afSBin Du 			return -EINVAL;
642*2ccf48afSBin Du 		}
643*2ccf48afSBin Du #else
644*2ccf48afSBin Du 		dev_err(dev, "get dmabuf fail -- CONFIG_HAS_DMA not defined\n");
645*2ccf48afSBin Du 		buf->dbuf = NULL;
646*2ccf48afSBin Du 		return -EINVAL;
647*2ccf48afSBin Du #endif
648*2ccf48afSBin Du 	}
649*2ccf48afSBin Du 
650*2ccf48afSBin Du 	/* create isp user BO and obtain gpu_addr */
651*2ccf48afSBin Du 	ret = isp_user_buffer_alloc(dev, buf->dbuf, &bo, &gpu_addr);
652*2ccf48afSBin Du 	if (ret) {
653*2ccf48afSBin Du 		dev_err(dev, "fail to create isp user BO\n");
654*2ccf48afSBin Du 		if (!vb->planes[0].dbuf) {
655*2ccf48afSBin Du 			dma_buf_put(buf->dbuf);
656*2ccf48afSBin Du 			buf->dbuf = NULL;
657*2ccf48afSBin Du 		}
658*2ccf48afSBin Du 
659*2ccf48afSBin Du 		return ret;
660*2ccf48afSBin Du 	}
661*2ccf48afSBin Du 
662*2ccf48afSBin Du 	buf->bo = bo;
663*2ccf48afSBin Du 	buf->gpu_addr = gpu_addr;
664*2ccf48afSBin Du 	return 0;
665*2ccf48afSBin Du }
666*2ccf48afSBin Du 
667*2ccf48afSBin Du static void isp4vid_qops_buf_cleanup(struct vb2_buffer *vb)
668*2ccf48afSBin Du {
669*2ccf48afSBin Du 	struct isp4vid_capture_buffer *buf =
670*2ccf48afSBin Du 		container_of(vb, struct isp4vid_capture_buffer, vb2.vb2_buf);
671*2ccf48afSBin Du 
672*2ccf48afSBin Du 	if (buf->bo) {
673*2ccf48afSBin Du 		isp_user_buffer_free(buf->bo);
674*2ccf48afSBin Du 		buf->bo = NULL;
675*2ccf48afSBin Du 	}
676*2ccf48afSBin Du 
677*2ccf48afSBin Du 	/*
678*2ccf48afSBin Du 	 * Only put dmabufs we obtained ourselves via get_dmabuf, not ones
679*2ccf48afSBin Du 	 * provided by the framework for DMABUF import
680*2ccf48afSBin Du 	 */
681*2ccf48afSBin Du 	if (buf->dbuf && buf->dbuf != vb->planes[0].dbuf)
682*2ccf48afSBin Du 		dma_buf_put(buf->dbuf);
683*2ccf48afSBin Du 
684*2ccf48afSBin Du 	buf->dbuf = NULL;
685*2ccf48afSBin Du }
686*2ccf48afSBin Du 
687*2ccf48afSBin Du static const struct vb2_ops isp4vid_qops = {
688*2ccf48afSBin Du 	.queue_setup = isp4vid_qops_queue_setup,
689*2ccf48afSBin Du 	.buf_init = isp4vid_qops_buf_init,
690*2ccf48afSBin Du 	.buf_cleanup = isp4vid_qops_buf_cleanup,
691*2ccf48afSBin Du 	.start_streaming = isp4vid_qops_start_streaming,
692*2ccf48afSBin Du 	.stop_streaming = isp4vid_qops_stop_streaming,
693*2ccf48afSBin Du 	.buf_queue = isp4vid_qops_buffer_queue,
694*2ccf48afSBin Du };
695*2ccf48afSBin Du 
696*2ccf48afSBin Du int isp4vid_dev_init(struct isp4vid_dev *isp_vdev, struct v4l2_subdev *isp_sd)
697*2ccf48afSBin Du {
698*2ccf48afSBin Du 	const char *vdev_name = isp4vid_video_dev_name;
699*2ccf48afSBin Du 	struct v4l2_device *v4l2_dev;
700*2ccf48afSBin Du 	struct video_device *vdev;
701*2ccf48afSBin Du 	struct vb2_queue *q;
702*2ccf48afSBin Du 	int ret;
703*2ccf48afSBin Du 
704*2ccf48afSBin Du 	if (!isp_vdev || !isp_sd || !isp_sd->v4l2_dev)
705*2ccf48afSBin Du 		return -EINVAL;
706*2ccf48afSBin Du 
707*2ccf48afSBin Du 	v4l2_dev = isp_sd->v4l2_dev;
708*2ccf48afSBin Du 	vdev = &isp_vdev->vdev;
709*2ccf48afSBin Du 
710*2ccf48afSBin Du 	isp_vdev->isp_sdev = isp_sd;
711*2ccf48afSBin Du 	isp_vdev->dev = v4l2_dev->dev;
712*2ccf48afSBin Du 
713*2ccf48afSBin Du 	/* Initialize the vb2_queue struct */
714*2ccf48afSBin Du 	mutex_init(&isp_vdev->vbq_lock);
715*2ccf48afSBin Du 	q = &isp_vdev->vbq;
716*2ccf48afSBin Du 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
717*2ccf48afSBin Du 	q->io_modes = VB2_MMAP | VB2_DMABUF;
718*2ccf48afSBin Du 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
719*2ccf48afSBin Du 	q->buf_struct_size = sizeof(struct isp4vid_capture_buffer);
720*2ccf48afSBin Du 	q->min_queued_buffers = 2;
721*2ccf48afSBin Du 	q->ops = &isp4vid_qops;
722*2ccf48afSBin Du 	q->drv_priv = isp_vdev;
723*2ccf48afSBin Du 	q->mem_ops = &vb2_vmalloc_memops;
724*2ccf48afSBin Du 	q->lock = &isp_vdev->vbq_lock;
725*2ccf48afSBin Du 	q->dev = v4l2_dev->dev;
726*2ccf48afSBin Du 	ret = vb2_queue_init(q);
727*2ccf48afSBin Du 	if (ret) {
728*2ccf48afSBin Du 		dev_err(v4l2_dev->dev, "vb2_queue_init error:%d\n", ret);
729*2ccf48afSBin Du 		return ret;
730*2ccf48afSBin Du 	}
731*2ccf48afSBin Du 
732*2ccf48afSBin Du 	/* Initialize buffer list and its lock */
733*2ccf48afSBin Du 	mutex_init(&isp_vdev->buf_list_lock);
734*2ccf48afSBin Du 	INIT_LIST_HEAD(&isp_vdev->buf_list);
735*2ccf48afSBin Du 
736*2ccf48afSBin Du 	/* Set default frame format */
737*2ccf48afSBin Du 	isp_vdev->format = isp4vid_fmt_default;
738*2ccf48afSBin Du 	isp_vdev->timeperframe = ISP4VID_ISP_TPF_DEFAULT;
739*2ccf48afSBin Du 	v4l2_simplify_fraction(&isp_vdev->timeperframe.numerator,
740*2ccf48afSBin Du 			       &isp_vdev->timeperframe.denominator, 8, 333);
741*2ccf48afSBin Du 
742*2ccf48afSBin Du 	ret = isp4vid_fill_buffer_size(&isp_vdev->format);
743*2ccf48afSBin Du 	if (ret) {
744*2ccf48afSBin Du 		dev_err(v4l2_dev->dev, "fail to fill buffer size: %d\n", ret);
745*2ccf48afSBin Du 		goto err_release_vb2_queue;
746*2ccf48afSBin Du 	}
747*2ccf48afSBin Du 
748*2ccf48afSBin Du 	ret = isp4vid_set_fmt_2_isp(isp_sd, &isp_vdev->format);
749*2ccf48afSBin Du 	if (ret) {
750*2ccf48afSBin Du 		dev_err(v4l2_dev->dev, "fail init format :%d\n", ret);
751*2ccf48afSBin Du 		goto err_release_vb2_queue;
752*2ccf48afSBin Du 	}
753*2ccf48afSBin Du 
754*2ccf48afSBin Du 	/* Initialize the video_device struct */
755*2ccf48afSBin Du 	isp_vdev->vdev.entity.name = vdev_name;
756*2ccf48afSBin Du 	isp_vdev->vdev.entity.function = MEDIA_ENT_F_IO_V4L;
757*2ccf48afSBin Du 	isp_vdev->vdev_pad.flags = MEDIA_PAD_FL_SINK;
758*2ccf48afSBin Du 	ret = media_entity_pads_init(&isp_vdev->vdev.entity, 1,
759*2ccf48afSBin Du 				     &isp_vdev->vdev_pad);
760*2ccf48afSBin Du 
761*2ccf48afSBin Du 	if (ret) {
762*2ccf48afSBin Du 		dev_err(v4l2_dev->dev, "init media entity pad fail:%d\n", ret);
763*2ccf48afSBin Du 		goto err_release_vb2_queue;
764*2ccf48afSBin Du 	}
765*2ccf48afSBin Du 
766*2ccf48afSBin Du 	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE |
767*2ccf48afSBin Du 			    V4L2_CAP_STREAMING | V4L2_CAP_IO_MC;
768*2ccf48afSBin Du 	vdev->entity.ops = &isp4vid_vdev_ent_ops;
769*2ccf48afSBin Du 	vdev->release = video_device_release_empty;
770*2ccf48afSBin Du 	vdev->fops = &isp4vid_vdev_fops;
771*2ccf48afSBin Du 	vdev->ioctl_ops = &isp4vid_vdev_ioctl_ops;
772*2ccf48afSBin Du 	vdev->lock = NULL;
773*2ccf48afSBin Du 	vdev->queue = q;
774*2ccf48afSBin Du 	vdev->v4l2_dev = v4l2_dev;
775*2ccf48afSBin Du 	vdev->vfl_dir = VFL_DIR_RX;
776*2ccf48afSBin Du 	strscpy(vdev->name, vdev_name, sizeof(vdev->name));
777*2ccf48afSBin Du 	video_set_drvdata(vdev, isp_vdev);
778*2ccf48afSBin Du 
779*2ccf48afSBin Du 	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
780*2ccf48afSBin Du 	if (ret) {
781*2ccf48afSBin Du 		dev_err(v4l2_dev->dev, "register video device fail:%d\n", ret);
782*2ccf48afSBin Du 		goto err_entity_cleanup;
783*2ccf48afSBin Du 	}
784*2ccf48afSBin Du 
785*2ccf48afSBin Du 	return 0;
786*2ccf48afSBin Du 
787*2ccf48afSBin Du err_entity_cleanup:
788*2ccf48afSBin Du 	media_entity_cleanup(&isp_vdev->vdev.entity);
789*2ccf48afSBin Du err_release_vb2_queue:
790*2ccf48afSBin Du 	vb2_queue_release(q);
791*2ccf48afSBin Du 	return ret;
792*2ccf48afSBin Du }
793*2ccf48afSBin Du 
794*2ccf48afSBin Du void isp4vid_dev_deinit(struct isp4vid_dev *isp_vdev)
795*2ccf48afSBin Du {
796*2ccf48afSBin Du 	vb2_video_unregister_device(&isp_vdev->vdev);
797*2ccf48afSBin Du }
798