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