1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2013 - 2025 Intel Corporation
4  */
5 
6 #include <linux/align.h>
7 #include <linux/bits.h>
8 #include <linux/bug.h>
9 #include <linux/completion.h>
10 #include <linux/container_of.h>
11 #include <linux/compat.h>
12 #include <linux/device.h>
13 #include <linux/iopoll.h>
14 #include <linux/list.h>
15 #include <linux/minmax.h>
16 #include <linux/module.h>
17 #include <linux/mutex.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/spinlock.h>
20 #include <linux/string.h>
21 
22 #include <media/media-entity.h>
23 #include <media/v4l2-dev.h>
24 #include <media/v4l2-fh.h>
25 #include <media/v4l2-ioctl.h>
26 #include <media/v4l2-mc.h>
27 #include <media/v4l2-subdev.h>
28 #include <media/videobuf2-v4l2.h>
29 
30 #include "abi/ipu7_fw_isys_abi.h"
31 
32 #include "ipu7.h"
33 #include "ipu7-bus.h"
34 #include "ipu7-buttress-regs.h"
35 #include "ipu7-fw-isys.h"
36 #include "ipu7-isys.h"
37 #include "ipu7-isys-video.h"
38 #include "ipu7-platform-regs.h"
39 
40 const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = {
41 	{V4L2_PIX_FMT_SBGGR12, 16, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
42 	 IPU_INSYS_FRAME_FORMAT_RAW16},
43 	{V4L2_PIX_FMT_SGBRG12, 16, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
44 	 IPU_INSYS_FRAME_FORMAT_RAW16},
45 	{V4L2_PIX_FMT_SGRBG12, 16, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
46 	 IPU_INSYS_FRAME_FORMAT_RAW16},
47 	{V4L2_PIX_FMT_SRGGB12, 16, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
48 	 IPU_INSYS_FRAME_FORMAT_RAW16},
49 	{V4L2_PIX_FMT_SBGGR10, 16, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
50 	 IPU_INSYS_FRAME_FORMAT_RAW16},
51 	{V4L2_PIX_FMT_SGBRG10, 16, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
52 	 IPU_INSYS_FRAME_FORMAT_RAW16},
53 	{V4L2_PIX_FMT_SGRBG10, 16, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
54 	 IPU_INSYS_FRAME_FORMAT_RAW16},
55 	{V4L2_PIX_FMT_SRGGB10, 16, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
56 	 IPU_INSYS_FRAME_FORMAT_RAW16},
57 	{V4L2_PIX_FMT_SBGGR8, 8, 8, MEDIA_BUS_FMT_SBGGR8_1X8,
58 	 IPU_INSYS_FRAME_FORMAT_RAW8},
59 	{V4L2_PIX_FMT_SGBRG8, 8, 8, MEDIA_BUS_FMT_SGBRG8_1X8,
60 	 IPU_INSYS_FRAME_FORMAT_RAW8},
61 	{V4L2_PIX_FMT_SGRBG8, 8, 8, MEDIA_BUS_FMT_SGRBG8_1X8,
62 	 IPU_INSYS_FRAME_FORMAT_RAW8},
63 	{V4L2_PIX_FMT_SRGGB8, 8, 8, MEDIA_BUS_FMT_SRGGB8_1X8,
64 	 IPU_INSYS_FRAME_FORMAT_RAW8},
65 	{V4L2_PIX_FMT_SBGGR12P, 12, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
66 	 IPU_INSYS_FRAME_FORMAT_RAW12},
67 	{V4L2_PIX_FMT_SGBRG12P, 12, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
68 	 IPU_INSYS_FRAME_FORMAT_RAW12},
69 	{V4L2_PIX_FMT_SGRBG12P, 12, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
70 	 IPU_INSYS_FRAME_FORMAT_RAW12},
71 	{V4L2_PIX_FMT_SRGGB12P, 12, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
72 	 IPU_INSYS_FRAME_FORMAT_RAW12},
73 	{V4L2_PIX_FMT_SBGGR10P, 10, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
74 	 IPU_INSYS_FRAME_FORMAT_RAW10},
75 	{V4L2_PIX_FMT_SGBRG10P, 10, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
76 	 IPU_INSYS_FRAME_FORMAT_RAW10},
77 	{V4L2_PIX_FMT_SGRBG10P, 10, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
78 	 IPU_INSYS_FRAME_FORMAT_RAW10},
79 	{V4L2_PIX_FMT_SRGGB10P, 10, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
80 	 IPU_INSYS_FRAME_FORMAT_RAW10},
81 	{V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16,
82 	 IPU_INSYS_FRAME_FORMAT_UYVY},
83 	{V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16,
84 	 IPU_INSYS_FRAME_FORMAT_YUYV},
85 	{V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16,
86 	 IPU_INSYS_FRAME_FORMAT_RGB565},
87 	{V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24,
88 	 IPU_INSYS_FRAME_FORMAT_RGBA888},
89 };
90 
video_open(struct file * file)91 static int video_open(struct file *file)
92 {
93 	return v4l2_fh_open(file);
94 }
95 
ipu7_isys_get_isys_format(u32 pixelformat)96 const struct ipu7_isys_pixelformat *ipu7_isys_get_isys_format(u32 pixelformat)
97 {
98 	unsigned int i;
99 
100 	for (i = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) {
101 		const struct ipu7_isys_pixelformat *pfmt = &ipu7_isys_pfmts[i];
102 
103 		if (pfmt->pixelformat == pixelformat)
104 			return pfmt;
105 	}
106 
107 	return &ipu7_isys_pfmts[0];
108 }
109 
ipu7_isys_vidioc_querycap(struct file * file,void * fh,struct v4l2_capability * cap)110 static int ipu7_isys_vidioc_querycap(struct file *file, void *fh,
111 				     struct v4l2_capability *cap)
112 {
113 	struct ipu7_isys_video *av = video_drvdata(file);
114 
115 	strscpy(cap->driver, IPU_ISYS_NAME, sizeof(cap->driver));
116 	strscpy(cap->card, av->isys->media_dev.model, sizeof(cap->card));
117 
118 	return 0;
119 }
120 
ipu7_isys_vidioc_enum_fmt(struct file * file,void * fh,struct v4l2_fmtdesc * f)121 static int ipu7_isys_vidioc_enum_fmt(struct file *file, void *fh,
122 				     struct v4l2_fmtdesc *f)
123 {
124 	unsigned int i, num_found;
125 
126 	for (i = 0, num_found = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) {
127 		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
128 			continue;
129 
130 		if (f->mbus_code && f->mbus_code != ipu7_isys_pfmts[i].code)
131 			continue;
132 
133 		if (num_found < f->index) {
134 			num_found++;
135 			continue;
136 		}
137 
138 		f->flags = 0;
139 		f->pixelformat = ipu7_isys_pfmts[i].pixelformat;
140 
141 		return 0;
142 	}
143 
144 	return -EINVAL;
145 }
146 
ipu7_isys_vidioc_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)147 static int ipu7_isys_vidioc_enum_framesizes(struct file *file, void *fh,
148 					    struct v4l2_frmsizeenum *fsize)
149 {
150 	unsigned int i;
151 
152 	if (fsize->index > 0)
153 		return -EINVAL;
154 
155 	for (i = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) {
156 		if (fsize->pixel_format != ipu7_isys_pfmts[i].pixelformat)
157 			continue;
158 
159 		fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
160 		fsize->stepwise.min_width = IPU_ISYS_MIN_WIDTH;
161 		fsize->stepwise.max_width = IPU_ISYS_MAX_WIDTH;
162 		fsize->stepwise.min_height = IPU_ISYS_MIN_HEIGHT;
163 		fsize->stepwise.max_height = IPU_ISYS_MAX_HEIGHT;
164 		fsize->stepwise.step_width = 2;
165 		fsize->stepwise.step_height = 2;
166 
167 		return 0;
168 	}
169 
170 	return -EINVAL;
171 }
172 
ipu7_isys_vidioc_g_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * f)173 static int ipu7_isys_vidioc_g_fmt_vid_cap(struct file *file, void *fh,
174 					  struct v4l2_format *f)
175 {
176 	struct ipu7_isys_video *av = video_drvdata(file);
177 
178 	f->fmt.pix = av->pix_fmt;
179 
180 	return 0;
181 }
182 
ipu7_isys_try_fmt_cap(struct ipu7_isys_video * av,u32 type,u32 * format,u32 * width,u32 * height,u32 * bytesperline,u32 * sizeimage)183 static void ipu7_isys_try_fmt_cap(struct ipu7_isys_video *av, u32 type,
184 				  u32 *format, u32 *width, u32 *height,
185 				  u32 *bytesperline, u32 *sizeimage)
186 {
187 	const struct ipu7_isys_pixelformat *pfmt =
188 		ipu7_isys_get_isys_format(*format);
189 
190 	*format = pfmt->pixelformat;
191 	*width = clamp(*width, IPU_ISYS_MIN_WIDTH, IPU_ISYS_MAX_WIDTH);
192 	*height = clamp(*height, IPU_ISYS_MIN_HEIGHT, IPU_ISYS_MAX_HEIGHT);
193 
194 	if (pfmt->bpp != pfmt->bpp_packed)
195 		*bytesperline = *width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE);
196 	else
197 		*bytesperline = DIV_ROUND_UP(*width * pfmt->bpp, BITS_PER_BYTE);
198 
199 	*bytesperline = ALIGN(*bytesperline, 64U);
200 
201 	/*
202 	 * (height + 1) * bytesperline due to a hardware issue: the DMA unit
203 	 * is a power of two, and a line should be transferred as few units
204 	 * as possible. The result is that up to line length more data than
205 	 * the image size may be transferred to memory after the image.
206 	 * Another limitation is the GDA allocation unit size. For low
207 	 * resolution it gives a bigger number. Use larger one to avoid
208 	 * memory corruption.
209 	 */
210 	*sizeimage = *bytesperline * *height +
211 		max(*bytesperline,
212 		    av->isys->pdata->ipdata->isys_dma_overshoot);
213 }
214 
__ipu_isys_vidioc_try_fmt_vid_cap(struct ipu7_isys_video * av,struct v4l2_format * f)215 static void __ipu_isys_vidioc_try_fmt_vid_cap(struct ipu7_isys_video *av,
216 					      struct v4l2_format *f)
217 {
218 	ipu7_isys_try_fmt_cap(av, f->type, &f->fmt.pix.pixelformat,
219 			      &f->fmt.pix.width, &f->fmt.pix.height,
220 			      &f->fmt.pix.bytesperline, &f->fmt.pix.sizeimage);
221 
222 	f->fmt.pix.field = V4L2_FIELD_NONE;
223 	f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
224 	f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
225 	f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
226 	f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
227 }
228 
ipu7_isys_vidioc_try_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * f)229 static int ipu7_isys_vidioc_try_fmt_vid_cap(struct file *file, void *fh,
230 					    struct v4l2_format *f)
231 {
232 	struct ipu7_isys_video *av = video_drvdata(file);
233 
234 	if (vb2_is_busy(&av->aq.vbq))
235 		return -EBUSY;
236 
237 	__ipu_isys_vidioc_try_fmt_vid_cap(av, f);
238 
239 	return 0;
240 }
241 
ipu7_isys_vidioc_s_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * f)242 static int ipu7_isys_vidioc_s_fmt_vid_cap(struct file *file, void *fh,
243 					  struct v4l2_format *f)
244 {
245 	struct ipu7_isys_video *av = video_drvdata(file);
246 
247 	ipu7_isys_vidioc_try_fmt_vid_cap(file, fh, f);
248 	av->pix_fmt = f->fmt.pix;
249 
250 	return 0;
251 }
252 
ipu7_isys_vidioc_reqbufs(struct file * file,void * priv,struct v4l2_requestbuffers * p)253 static int ipu7_isys_vidioc_reqbufs(struct file *file, void *priv,
254 				    struct v4l2_requestbuffers *p)
255 {
256 	struct ipu7_isys_video *av = video_drvdata(file);
257 	int ret;
258 
259 	av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->type);
260 	av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->type);
261 
262 	ret = vb2_queue_change_type(&av->aq.vbq, p->type);
263 	if (ret)
264 		return ret;
265 
266 	return vb2_ioctl_reqbufs(file, priv, p);
267 }
268 
ipu7_isys_vidioc_create_bufs(struct file * file,void * priv,struct v4l2_create_buffers * p)269 static int ipu7_isys_vidioc_create_bufs(struct file *file, void *priv,
270 					struct v4l2_create_buffers *p)
271 {
272 	struct ipu7_isys_video *av = video_drvdata(file);
273 	int ret;
274 
275 	av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->format.type);
276 	av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->format.type);
277 
278 	ret = vb2_queue_change_type(&av->aq.vbq, p->format.type);
279 	if (ret)
280 		return ret;
281 
282 	return vb2_ioctl_create_bufs(file, priv, p);
283 }
284 
link_validate(struct media_link * link)285 static int link_validate(struct media_link *link)
286 {
287 	struct ipu7_isys_video *av =
288 		container_of(link->sink, struct ipu7_isys_video, pad);
289 	struct device *dev = &av->isys->adev->auxdev.dev;
290 	struct v4l2_subdev_state *s_state;
291 	struct v4l2_mbus_framefmt *s_fmt;
292 	struct v4l2_subdev *s_sd;
293 	struct media_pad *s_pad;
294 	u32 s_stream, code;
295 	int ret = -EPIPE;
296 
297 	if (!link->source->entity)
298 		return ret;
299 
300 	s_sd = media_entity_to_v4l2_subdev(link->source->entity);
301 	s_state = v4l2_subdev_get_unlocked_active_state(s_sd);
302 	if (!s_state)
303 		return ret;
304 
305 	dev_dbg(dev, "validating link \"%s\":%u -> \"%s\"\n",
306 		link->source->entity->name, link->source->index,
307 		link->sink->entity->name);
308 
309 	s_pad = media_pad_remote_pad_first(&av->pad);
310 	s_stream = ipu7_isys_get_src_stream_by_src_pad(s_sd, s_pad->index);
311 
312 	v4l2_subdev_lock_state(s_state);
313 
314 	s_fmt = v4l2_subdev_state_get_format(s_state, s_pad->index, s_stream);
315 	if (!s_fmt) {
316 		dev_err(dev, "failed to get source pad format\n");
317 		goto unlock;
318 	}
319 
320 	code = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat)->code;
321 
322 	if (s_fmt->width != av->pix_fmt.width ||
323 	    s_fmt->height != av->pix_fmt.height || s_fmt->code != code) {
324 		dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n",
325 			s_fmt->width, s_fmt->height, s_fmt->code,
326 			av->pix_fmt.width, av->pix_fmt.height, code);
327 		goto unlock;
328 	}
329 
330 	v4l2_subdev_unlock_state(s_state);
331 
332 	return 0;
333 unlock:
334 	v4l2_subdev_unlock_state(s_state);
335 
336 	return ret;
337 }
338 
get_stream_opened(struct ipu7_isys_video * av)339 static void get_stream_opened(struct ipu7_isys_video *av)
340 {
341 	unsigned long flags;
342 
343 	spin_lock_irqsave(&av->isys->streams_lock, flags);
344 	av->isys->stream_opened++;
345 	spin_unlock_irqrestore(&av->isys->streams_lock, flags);
346 }
347 
put_stream_opened(struct ipu7_isys_video * av)348 static void put_stream_opened(struct ipu7_isys_video *av)
349 {
350 	unsigned long flags;
351 
352 	spin_lock_irqsave(&av->isys->streams_lock, flags);
353 	av->isys->stream_opened--;
354 	spin_unlock_irqrestore(&av->isys->streams_lock, flags);
355 }
356 
ipu7_isys_fw_pin_cfg(struct ipu7_isys_video * av,struct ipu7_insys_stream_cfg * cfg)357 static int ipu7_isys_fw_pin_cfg(struct ipu7_isys_video *av,
358 				struct ipu7_insys_stream_cfg *cfg)
359 {
360 	struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
361 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
362 	struct ipu7_isys_stream *stream = av->stream;
363 	const struct ipu7_isys_pixelformat *pfmt =
364 		ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
365 	struct ipu7_insys_output_pin *output_pin;
366 	struct ipu7_insys_input_pin *input_pin;
367 	int input_pins = cfg->nof_input_pins++;
368 	struct ipu7_isys_queue *aq = &av->aq;
369 	struct ipu7_isys *isys = av->isys;
370 	struct device *dev = &isys->adev->auxdev.dev;
371 	struct v4l2_mbus_framefmt fmt;
372 	int output_pins;
373 	u32 src_stream;
374 	int ret;
375 
376 	src_stream = ipu7_isys_get_src_stream_by_src_pad(sd, src_pad->index);
377 	ret = ipu7_isys_get_stream_pad_fmt(sd, src_pad->index, src_stream,
378 					   &fmt);
379 	if (ret < 0) {
380 		dev_err(dev, "can't get stream format (%d)\n", ret);
381 		return ret;
382 	}
383 
384 	input_pin = &cfg->input_pins[input_pins];
385 	input_pin->input_res.width = fmt.width;
386 	input_pin->input_res.height = fmt.height;
387 	input_pin->dt = av->dt;
388 	input_pin->disable_mipi_unpacking = 0;
389 	pfmt = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
390 	if (pfmt->bpp == pfmt->bpp_packed && pfmt->bpp % BITS_PER_BYTE)
391 		input_pin->disable_mipi_unpacking = 1;
392 	input_pin->mapped_dt = N_IPU_INSYS_MIPI_DATA_TYPE;
393 	input_pin->dt_rename_mode = IPU_INSYS_MIPI_DT_NO_RENAME;
394 	/* if enable polling isys interrupt, the follow values maybe set */
395 	input_pin->sync_msg_map = IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF |
396 		IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED |
397 		IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF |
398 		IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED;
399 
400 	output_pins = cfg->nof_output_pins++;
401 	aq->fw_output = output_pins;
402 	stream->output_pins[output_pins].pin_ready = ipu7_isys_queue_buf_ready;
403 	stream->output_pins[output_pins].aq = aq;
404 
405 	output_pin = &cfg->output_pins[output_pins];
406 	/* output pin msg link */
407 	output_pin->link.buffer_lines = 0;
408 	output_pin->link.foreign_key = IPU_MSG_LINK_FOREIGN_KEY_NONE;
409 	output_pin->link.granularity_pointer_update = 0;
410 	output_pin->link.msg_link_streaming_mode =
411 		IA_GOFO_MSG_LINK_STREAMING_MODE_SOFF;
412 
413 	output_pin->link.pbk_id = IPU_MSG_LINK_PBK_ID_DONT_CARE;
414 	output_pin->link.pbk_slot_id = IPU_MSG_LINK_PBK_SLOT_ID_DONT_CARE;
415 	output_pin->link.dest = IPU_INSYS_OUTPUT_LINK_DEST_MEM;
416 	output_pin->link.use_sw_managed = 1;
417 	/* TODO: set the snoop bit for metadata capture */
418 	output_pin->link.is_snoop = 0;
419 
420 	/* output pin crop */
421 	output_pin->crop.line_top = 0;
422 	output_pin->crop.line_bottom = 0;
423 
424 	/* output de-compression */
425 	output_pin->dpcm.enable = 0;
426 
427 	/* frame format type */
428 	pfmt = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
429 	output_pin->ft = (u16)pfmt->css_pixelformat;
430 
431 	/* stride in bytes */
432 	output_pin->stride = av->pix_fmt.bytesperline;
433 	output_pin->send_irq = 1;
434 	output_pin->early_ack_en = 0;
435 
436 	/* input pin id */
437 	output_pin->input_pin_id = input_pins;
438 
439 	return 0;
440 }
441 
442 /* Create stream and start it using the CSS FW ABI. */
start_stream_firmware(struct ipu7_isys_video * av,struct ipu7_isys_buffer_list * bl)443 static int start_stream_firmware(struct ipu7_isys_video *av,
444 				 struct ipu7_isys_buffer_list *bl)
445 {
446 	struct device *dev = &av->isys->adev->auxdev.dev;
447 	struct ipu7_isys_stream *stream = av->stream;
448 	struct ipu7_insys_stream_cfg *stream_cfg;
449 	struct ipu7_insys_buffset *buf = NULL;
450 	struct isys_fw_msgs *msg = NULL;
451 	struct ipu7_isys_queue *aq;
452 	int ret, retout, tout;
453 	u16 send_type;
454 
455 	if (WARN_ON(!bl))
456 		return -EIO;
457 
458 	msg = ipu7_get_fw_msg_buf(stream);
459 	if (!msg)
460 		return -ENOMEM;
461 
462 	stream_cfg = &msg->fw_msg.stream;
463 	stream_cfg->port_id = stream->stream_source;
464 	stream_cfg->vc = stream->vc;
465 	stream_cfg->stream_msg_map = IPU_INSYS_STREAM_ENABLE_MSG_SEND_RESP |
466 				     IPU_INSYS_STREAM_ENABLE_MSG_SEND_IRQ;
467 
468 	list_for_each_entry(aq, &stream->queues, node) {
469 		struct ipu7_isys_video *__av = ipu7_isys_queue_to_video(aq);
470 
471 		ret = ipu7_isys_fw_pin_cfg(__av, stream_cfg);
472 		if (ret < 0) {
473 			ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
474 			return ret;
475 		}
476 	}
477 
478 	ipu7_fw_isys_dump_stream_cfg(dev, stream_cfg);
479 
480 	stream->nr_output_pins = stream_cfg->nof_output_pins;
481 
482 	reinit_completion(&stream->stream_open_completion);
483 
484 	ret = ipu7_fw_isys_complex_cmd(av->isys, stream->stream_handle,
485 				       stream_cfg, msg->dma_addr,
486 				       sizeof(*stream_cfg),
487 				       IPU_INSYS_SEND_TYPE_STREAM_OPEN);
488 	if (ret < 0) {
489 		dev_err(dev, "can't open stream (%d)\n", ret);
490 		ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
491 		return ret;
492 	}
493 
494 	get_stream_opened(av);
495 
496 	tout = wait_for_completion_timeout(&stream->stream_open_completion,
497 					   FW_CALL_TIMEOUT_JIFFIES);
498 
499 	ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
500 
501 	if (!tout) {
502 		dev_err(dev, "stream open time out\n");
503 		ret = -ETIMEDOUT;
504 		goto out_put_stream_opened;
505 	}
506 	if (stream->error) {
507 		dev_err(dev, "stream open error: %d\n", stream->error);
508 		ret = -EIO;
509 		goto out_put_stream_opened;
510 	}
511 	dev_dbg(dev, "start stream: open complete\n");
512 
513 	msg = ipu7_get_fw_msg_buf(stream);
514 	if (!msg) {
515 		ret = -ENOMEM;
516 		goto out_put_stream_opened;
517 	}
518 	buf = &msg->fw_msg.frame;
519 
520 	ipu7_isys_buffer_to_fw_frame_buff(buf, stream, bl);
521 	ipu7_isys_buffer_list_queue(bl, IPU_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
522 
523 	reinit_completion(&stream->stream_start_completion);
524 
525 	send_type = IPU_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
526 	ipu7_fw_isys_dump_frame_buff_set(dev, buf,
527 					 stream_cfg->nof_output_pins);
528 	ret = ipu7_fw_isys_complex_cmd(av->isys, stream->stream_handle, buf,
529 				       msg->dma_addr, sizeof(*buf),
530 				       send_type);
531 	if (ret < 0) {
532 		dev_err(dev, "can't start streaming (%d)\n", ret);
533 		goto out_stream_close;
534 	}
535 
536 	tout = wait_for_completion_timeout(&stream->stream_start_completion,
537 					   FW_CALL_TIMEOUT_JIFFIES);
538 	if (!tout) {
539 		dev_err(dev, "stream start time out\n");
540 		ret = -ETIMEDOUT;
541 		goto out_stream_close;
542 	}
543 	if (stream->error) {
544 		dev_err(dev, "stream start error: %d\n", stream->error);
545 		ret = -EIO;
546 		goto out_stream_close;
547 	}
548 	dev_dbg(dev, "start stream: complete\n");
549 
550 	return 0;
551 
552 out_stream_close:
553 	reinit_completion(&stream->stream_close_completion);
554 
555 	retout = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle,
556 					 IPU_INSYS_SEND_TYPE_STREAM_CLOSE);
557 	if (retout < 0) {
558 		dev_dbg(dev, "can't close stream (%d)\n", retout);
559 		goto out_put_stream_opened;
560 	}
561 
562 	tout = wait_for_completion_timeout(&stream->stream_close_completion,
563 					   FW_CALL_TIMEOUT_JIFFIES);
564 	if (!tout)
565 		dev_err(dev, "stream close time out with error %d\n",
566 			stream->error);
567 	else
568 		dev_dbg(dev, "stream close complete\n");
569 
570 out_put_stream_opened:
571 	put_stream_opened(av);
572 
573 	return ret;
574 }
575 
stop_streaming_firmware(struct ipu7_isys_video * av)576 static void stop_streaming_firmware(struct ipu7_isys_video *av)
577 {
578 	struct device *dev = &av->isys->adev->auxdev.dev;
579 	struct ipu7_isys_stream *stream = av->stream;
580 	int ret, tout;
581 
582 	reinit_completion(&stream->stream_stop_completion);
583 
584 	ret = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle,
585 				      IPU_INSYS_SEND_TYPE_STREAM_FLUSH);
586 	if (ret < 0) {
587 		dev_err(dev, "can't stop stream (%d)\n", ret);
588 		return;
589 	}
590 
591 	tout = wait_for_completion_timeout(&stream->stream_stop_completion,
592 					   FW_CALL_TIMEOUT_JIFFIES);
593 	if (!tout)
594 		dev_warn(dev, "stream stop time out\n");
595 	else if (stream->error)
596 		dev_warn(dev, "stream stop error: %d\n", stream->error);
597 	else
598 		dev_dbg(dev, "stop stream: complete\n");
599 }
600 
close_streaming_firmware(struct ipu7_isys_video * av)601 static void close_streaming_firmware(struct ipu7_isys_video *av)
602 {
603 	struct device *dev = &av->isys->adev->auxdev.dev;
604 	struct ipu7_isys_stream *stream =  av->stream;
605 	int ret, tout;
606 
607 	reinit_completion(&stream->stream_close_completion);
608 
609 	ret = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle,
610 				      IPU_INSYS_SEND_TYPE_STREAM_CLOSE);
611 	if (ret < 0) {
612 		dev_err(dev, "can't close stream (%d)\n", ret);
613 		return;
614 	}
615 
616 	tout = wait_for_completion_timeout(&stream->stream_close_completion,
617 					   FW_CALL_TIMEOUT_JIFFIES);
618 	if (!tout)
619 		dev_warn(dev, "stream close time out\n");
620 	else if (stream->error)
621 		dev_warn(dev, "stream close error: %d\n", stream->error);
622 	else
623 		dev_dbg(dev, "close stream: complete\n");
624 
625 	put_stream_opened(av);
626 }
627 
ipu7_isys_video_prepare_stream(struct ipu7_isys_video * av,struct media_entity * source_entity,int nr_queues)628 int ipu7_isys_video_prepare_stream(struct ipu7_isys_video *av,
629 				   struct media_entity *source_entity,
630 				   int nr_queues)
631 {
632 	struct ipu7_isys_stream *stream = av->stream;
633 	struct ipu7_isys_csi2 *csi2;
634 
635 	if (WARN_ON(stream->nr_streaming))
636 		return -EINVAL;
637 
638 	stream->nr_queues = nr_queues;
639 	atomic_set(&stream->sequence, 0);
640 	atomic_set(&stream->buf_id, 0);
641 
642 	stream->seq_index = 0;
643 	memset(stream->seq, 0, sizeof(stream->seq));
644 
645 	if (WARN_ON(!list_empty(&stream->queues)))
646 		return -EINVAL;
647 
648 	stream->stream_source = stream->asd->source;
649 
650 	csi2 = ipu7_isys_subdev_to_csi2(stream->asd);
651 	csi2->receiver_errors = 0;
652 	stream->source_entity = source_entity;
653 
654 	dev_dbg(&av->isys->adev->auxdev.dev,
655 		"prepare stream: external entity %s\n",
656 		stream->source_entity->name);
657 
658 	return 0;
659 }
660 
ipu7_isys_put_stream(struct ipu7_isys_stream * stream)661 void ipu7_isys_put_stream(struct ipu7_isys_stream *stream)
662 {
663 	unsigned long flags;
664 	struct device *dev;
665 	unsigned int i;
666 
667 	if (!stream) {
668 		pr_err("ipu7-isys: no available stream\n");
669 		return;
670 	}
671 
672 	dev = &stream->isys->adev->auxdev.dev;
673 
674 	spin_lock_irqsave(&stream->isys->streams_lock, flags);
675 	for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
676 		if (&stream->isys->streams[i] == stream) {
677 			if (stream->isys->streams_ref_count[i] > 0)
678 				stream->isys->streams_ref_count[i]--;
679 			else
680 				dev_warn(dev, "invalid stream %d\n", i);
681 
682 			break;
683 		}
684 	}
685 	spin_unlock_irqrestore(&stream->isys->streams_lock, flags);
686 }
687 
688 static struct ipu7_isys_stream *
ipu7_isys_get_stream(struct ipu7_isys_video * av,struct ipu7_isys_subdev * asd)689 ipu7_isys_get_stream(struct ipu7_isys_video *av, struct ipu7_isys_subdev *asd)
690 {
691 	struct ipu7_isys_stream *stream = NULL;
692 	struct ipu7_isys *isys = av->isys;
693 	unsigned long flags;
694 	unsigned int i;
695 	u8 vc = av->vc;
696 
697 	if (!isys)
698 		return NULL;
699 
700 	spin_lock_irqsave(&isys->streams_lock, flags);
701 	for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
702 		if (isys->streams_ref_count[i] && isys->streams[i].vc == vc &&
703 		    isys->streams[i].asd == asd) {
704 			isys->streams_ref_count[i]++;
705 			stream = &isys->streams[i];
706 			break;
707 		}
708 	}
709 
710 	if (!stream) {
711 		for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
712 			if (!isys->streams_ref_count[i]) {
713 				isys->streams_ref_count[i]++;
714 				stream = &isys->streams[i];
715 				stream->vc = vc;
716 				stream->asd = asd;
717 				break;
718 			}
719 		}
720 	}
721 	spin_unlock_irqrestore(&isys->streams_lock, flags);
722 
723 	return stream;
724 }
725 
726 struct ipu7_isys_stream *
ipu7_isys_query_stream_by_handle(struct ipu7_isys * isys,u8 stream_handle)727 ipu7_isys_query_stream_by_handle(struct ipu7_isys *isys, u8 stream_handle)
728 {
729 	unsigned long flags;
730 	struct ipu7_isys_stream *stream = NULL;
731 
732 	if (!isys)
733 		return NULL;
734 
735 	if (stream_handle >= IPU_ISYS_MAX_STREAMS) {
736 		dev_err(&isys->adev->auxdev.dev,
737 			"stream_handle %d is invalid\n", stream_handle);
738 		return NULL;
739 	}
740 
741 	spin_lock_irqsave(&isys->streams_lock, flags);
742 	if (isys->streams_ref_count[stream_handle] > 0) {
743 		isys->streams_ref_count[stream_handle]++;
744 		stream = &isys->streams[stream_handle];
745 	}
746 	spin_unlock_irqrestore(&isys->streams_lock, flags);
747 
748 	return stream;
749 }
750 
751 struct ipu7_isys_stream *
ipu7_isys_query_stream_by_source(struct ipu7_isys * isys,int source,u8 vc)752 ipu7_isys_query_stream_by_source(struct ipu7_isys *isys, int source, u8 vc)
753 {
754 	struct ipu7_isys_stream *stream = NULL;
755 	unsigned long flags;
756 	unsigned int i;
757 
758 	if (!isys)
759 		return NULL;
760 
761 	if (source < 0) {
762 		dev_err(&isys->adev->auxdev.dev,
763 			"query stream with invalid port number\n");
764 		return NULL;
765 	}
766 
767 	spin_lock_irqsave(&isys->streams_lock, flags);
768 	for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
769 		if (!isys->streams_ref_count[i])
770 			continue;
771 
772 		if (isys->streams[i].stream_source == source &&
773 		    isys->streams[i].vc == vc) {
774 			stream = &isys->streams[i];
775 			isys->streams_ref_count[i]++;
776 			break;
777 		}
778 	}
779 	spin_unlock_irqrestore(&isys->streams_lock, flags);
780 
781 	return stream;
782 }
783 
get_remote_pad_stream(struct media_pad * r_pad)784 static u32 get_remote_pad_stream(struct media_pad *r_pad)
785 {
786 	struct v4l2_subdev_state *state;
787 	struct v4l2_subdev *sd;
788 	u32 stream_id = 0;
789 	unsigned int i;
790 
791 	sd = media_entity_to_v4l2_subdev(r_pad->entity);
792 	state = v4l2_subdev_lock_and_get_active_state(sd);
793 	if (!state)
794 		return 0;
795 
796 	for (i = 0; i < state->stream_configs.num_configs; i++) {
797 		struct v4l2_subdev_stream_config *cfg =
798 			&state->stream_configs.configs[i];
799 		if (cfg->pad == r_pad->index) {
800 			stream_id = cfg->stream;
801 			break;
802 		}
803 	}
804 
805 	v4l2_subdev_unlock_state(state);
806 
807 	return stream_id;
808 }
809 
ipu7_isys_video_set_streaming(struct ipu7_isys_video * av,int state,struct ipu7_isys_buffer_list * bl)810 int ipu7_isys_video_set_streaming(struct ipu7_isys_video *av, int state,
811 				  struct ipu7_isys_buffer_list *bl)
812 {
813 	struct ipu7_isys_stream *stream = av->stream;
814 	struct device *dev = &av->isys->adev->auxdev.dev;
815 	struct media_pad *r_pad;
816 	struct v4l2_subdev *sd;
817 	u32 r_stream;
818 	int ret = 0;
819 
820 	dev_dbg(dev, "set stream: %d\n", state);
821 
822 	if (WARN(!stream->source_entity, "No source entity for stream\n"))
823 		return -ENODEV;
824 
825 	sd = &stream->asd->sd;
826 	r_pad = media_pad_remote_pad_first(&av->pad);
827 	r_stream = get_remote_pad_stream(r_pad);
828 	if (!state) {
829 		stop_streaming_firmware(av);
830 
831 		/* stop sub-device which connects with video */
832 		dev_dbg(dev, "disable streams %s pad:%d mask:0x%llx\n",
833 			sd->name, r_pad->index, BIT_ULL(r_stream));
834 		ret = v4l2_subdev_disable_streams(sd, r_pad->index,
835 						  BIT_ULL(r_stream));
836 		if (ret) {
837 			dev_err(dev, "disable streams %s failed with %d\n",
838 				sd->name, ret);
839 			return ret;
840 		}
841 
842 		close_streaming_firmware(av);
843 	} else {
844 		ret = start_stream_firmware(av, bl);
845 		if (ret) {
846 			dev_err(dev, "start stream of firmware failed\n");
847 			return ret;
848 		}
849 
850 		/* start sub-device which connects with video */
851 		dev_dbg(dev, "enable streams %s pad: %d mask:0x%llx\n",
852 			sd->name, r_pad->index, BIT_ULL(r_stream));
853 		ret = v4l2_subdev_enable_streams(sd, r_pad->index,
854 						 BIT_ULL(r_stream));
855 		if (ret) {
856 			dev_err(dev, "enable streams %s failed with %d\n",
857 				sd->name, ret);
858 			goto out_media_entity_stop_streaming_firmware;
859 		}
860 	}
861 
862 	av->streaming = state;
863 
864 	return 0;
865 
866 out_media_entity_stop_streaming_firmware:
867 	stop_streaming_firmware(av);
868 
869 	return ret;
870 }
871 
872 static const struct v4l2_ioctl_ops ipu7_v4l2_ioctl_ops = {
873 	.vidioc_querycap = ipu7_isys_vidioc_querycap,
874 	.vidioc_enum_fmt_vid_cap = ipu7_isys_vidioc_enum_fmt,
875 	.vidioc_enum_framesizes = ipu7_isys_vidioc_enum_framesizes,
876 	.vidioc_g_fmt_vid_cap = ipu7_isys_vidioc_g_fmt_vid_cap,
877 	.vidioc_s_fmt_vid_cap = ipu7_isys_vidioc_s_fmt_vid_cap,
878 	.vidioc_try_fmt_vid_cap = ipu7_isys_vidioc_try_fmt_vid_cap,
879 	.vidioc_reqbufs = ipu7_isys_vidioc_reqbufs,
880 	.vidioc_create_bufs = ipu7_isys_vidioc_create_bufs,
881 	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
882 	.vidioc_querybuf = vb2_ioctl_querybuf,
883 	.vidioc_qbuf = vb2_ioctl_qbuf,
884 	.vidioc_dqbuf = vb2_ioctl_dqbuf,
885 	.vidioc_streamon = vb2_ioctl_streamon,
886 	.vidioc_streamoff = vb2_ioctl_streamoff,
887 	.vidioc_expbuf = vb2_ioctl_expbuf,
888 };
889 
890 static const struct media_entity_operations entity_ops = {
891 	.link_validate = link_validate,
892 };
893 
894 static const struct v4l2_file_operations isys_fops = {
895 	.owner = THIS_MODULE,
896 	.poll = vb2_fop_poll,
897 	.unlocked_ioctl = video_ioctl2,
898 	.mmap = vb2_fop_mmap,
899 	.open = video_open,
900 	.release = vb2_fop_release,
901 };
902 
ipu7_isys_fw_open(struct ipu7_isys * isys)903 int ipu7_isys_fw_open(struct ipu7_isys *isys)
904 {
905 	struct ipu7_bus_device *adev = isys->adev;
906 	int ret;
907 
908 	ret = pm_runtime_resume_and_get(&adev->auxdev.dev);
909 	if (ret < 0)
910 		return ret;
911 
912 	mutex_lock(&isys->mutex);
913 
914 	if (isys->ref_count++)
915 		goto unlock;
916 
917 	/*
918 	 * Buffers could have been left to wrong queue at last closure.
919 	 * Move them now back to empty buffer queue.
920 	 */
921 	ipu7_cleanup_fw_msg_bufs(isys);
922 
923 	ret = ipu7_fw_isys_open(isys);
924 	if (ret < 0)
925 		goto out;
926 
927 unlock:
928 	mutex_unlock(&isys->mutex);
929 
930 	return 0;
931 out:
932 	isys->ref_count--;
933 	mutex_unlock(&isys->mutex);
934 	pm_runtime_put(&adev->auxdev.dev);
935 
936 	return ret;
937 }
938 
ipu7_isys_fw_close(struct ipu7_isys * isys)939 void ipu7_isys_fw_close(struct ipu7_isys *isys)
940 {
941 	mutex_lock(&isys->mutex);
942 
943 	isys->ref_count--;
944 
945 	if (!isys->ref_count)
946 		ipu7_fw_isys_close(isys);
947 
948 	mutex_unlock(&isys->mutex);
949 }
950 
ipu7_isys_setup_video(struct ipu7_isys_video * av,struct media_entity ** source_entity,int * nr_queues)951 int ipu7_isys_setup_video(struct ipu7_isys_video *av,
952 			  struct media_entity **source_entity, int *nr_queues)
953 {
954 	const struct ipu7_isys_pixelformat *pfmt =
955 		ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
956 	struct device *dev = &av->isys->adev->auxdev.dev;
957 	struct media_pad *source_pad, *remote_pad;
958 	struct v4l2_mbus_frame_desc_entry entry;
959 	struct v4l2_subdev_route *route = NULL;
960 	struct v4l2_subdev_route *r;
961 	struct v4l2_subdev_state *state;
962 	struct ipu7_isys_subdev *asd;
963 	struct v4l2_subdev *remote_sd;
964 	struct media_pipeline *pipeline;
965 	int ret = -EINVAL;
966 
967 	*nr_queues = 0;
968 
969 	remote_pad = media_pad_remote_pad_unique(&av->pad);
970 	if (IS_ERR(remote_pad)) {
971 		dev_dbg(dev, "failed to get remote pad\n");
972 		return PTR_ERR(remote_pad);
973 	}
974 
975 	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
976 	asd = to_ipu7_isys_subdev(remote_sd);
977 
978 	source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]);
979 	if (!source_pad) {
980 		dev_dbg(dev, "No external source entity\n");
981 		return -ENODEV;
982 	}
983 
984 	*source_entity = source_pad->entity;
985 
986 	state = v4l2_subdev_lock_and_get_active_state(remote_sd);
987 	for_each_active_route(&state->routing, r) {
988 		if (r->source_pad == remote_pad->index)
989 			route = r;
990 	}
991 
992 	if (!route) {
993 		v4l2_subdev_unlock_state(state);
994 		dev_dbg(dev, "Failed to find route\n");
995 		return -ENODEV;
996 	}
997 
998 	v4l2_subdev_unlock_state(state);
999 
1000 	ret = ipu7_isys_csi2_get_remote_desc(route->sink_stream,
1001 					     to_ipu7_isys_csi2(asd),
1002 					     *source_entity, &entry,
1003 					     nr_queues);
1004 	if (ret == -ENOIOCTLCMD) {
1005 		av->vc = 0;
1006 		av->dt = ipu7_isys_mbus_code_to_mipi(pfmt->code);
1007 		if (av->dt == 0xff)
1008 			return -EINVAL;
1009 		*nr_queues = 1;
1010 	} else if (*nr_queues && !ret) {
1011 		dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
1012 			entry.stream, entry.length, entry.bus.csi2.vc,
1013 			entry.bus.csi2.dt);
1014 
1015 		av->vc = entry.bus.csi2.vc;
1016 		av->dt = entry.bus.csi2.dt;
1017 	} else {
1018 		dev_err(dev, "failed to get remote frame desc\n");
1019 		return ret;
1020 	}
1021 
1022 	pipeline = media_entity_pipeline(&av->vdev.entity);
1023 	if (!pipeline)
1024 		ret = video_device_pipeline_alloc_start(&av->vdev);
1025 	else
1026 		ret = video_device_pipeline_start(&av->vdev, pipeline);
1027 	if (ret < 0) {
1028 		dev_dbg(dev, "media pipeline start failed\n");
1029 		return ret;
1030 	}
1031 
1032 	av->stream = ipu7_isys_get_stream(av, asd);
1033 	if (!av->stream) {
1034 		video_device_pipeline_stop(&av->vdev);
1035 		dev_err(dev, "no available stream for firmware\n");
1036 		return -EINVAL;
1037 	}
1038 
1039 	return 0;
1040 }
1041 
1042 /*
1043  * Do everything that's needed to initialise things related to video
1044  * buffer queue, video node, and the related media entity. The caller
1045  * is expected to assign isys field and set the name of the video
1046  * device.
1047  */
ipu7_isys_video_init(struct ipu7_isys_video * av)1048 int ipu7_isys_video_init(struct ipu7_isys_video *av)
1049 {
1050 	struct v4l2_format format = {
1051 		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
1052 		.fmt.pix = {
1053 			.width = 1920,
1054 			.height = 1080,
1055 		},
1056 	};
1057 	int ret;
1058 
1059 	mutex_init(&av->mutex);
1060 	av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC |
1061 		V4L2_CAP_VIDEO_CAPTURE;
1062 	av->vdev.vfl_dir = VFL_DIR_RX;
1063 
1064 	ret = ipu7_isys_queue_init(&av->aq);
1065 	if (ret)
1066 		goto out_mutex_destroy;
1067 
1068 	av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
1069 	ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad);
1070 	if (ret)
1071 		goto out_vb2_queue_cleanup;
1072 
1073 	av->vdev.entity.ops = &entity_ops;
1074 	av->vdev.release = video_device_release_empty;
1075 	av->vdev.fops = &isys_fops;
1076 	av->vdev.v4l2_dev = &av->isys->v4l2_dev;
1077 	av->vdev.dev_parent = &av->isys->adev->isp->pdev->dev;
1078 	av->vdev.ioctl_ops = &ipu7_v4l2_ioctl_ops;
1079 	av->vdev.queue = &av->aq.vbq;
1080 	av->vdev.lock = &av->mutex;
1081 
1082 	__ipu_isys_vidioc_try_fmt_vid_cap(av, &format);
1083 	av->pix_fmt = format.fmt.pix;
1084 
1085 	set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags);
1086 	video_set_drvdata(&av->vdev, av);
1087 
1088 	ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1);
1089 	if (ret)
1090 		goto out_media_entity_cleanup;
1091 
1092 	return ret;
1093 
1094 out_media_entity_cleanup:
1095 	vb2_video_unregister_device(&av->vdev);
1096 	media_entity_cleanup(&av->vdev.entity);
1097 
1098 out_vb2_queue_cleanup:
1099 	vb2_queue_release(&av->aq.vbq);
1100 
1101 out_mutex_destroy:
1102 	mutex_destroy(&av->mutex);
1103 
1104 	return ret;
1105 }
1106 
ipu7_isys_video_cleanup(struct ipu7_isys_video * av)1107 void ipu7_isys_video_cleanup(struct ipu7_isys_video *av)
1108 {
1109 	vb2_video_unregister_device(&av->vdev);
1110 	media_entity_cleanup(&av->vdev.entity);
1111 	mutex_destroy(&av->mutex);
1112 }
1113