1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 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/device.h>
12#include <linux/list.h>
13#include <linux/math64.h>
14#include <linux/minmax.h>
15#include <linux/module.h>
16#include <linux/mutex.h>
17#include <linux/pm_runtime.h>
18#include <linux/spinlock.h>
19#include <linux/string.h>
20
21#include <media/media-entity.h>
22#include <media/v4l2-ctrls.h>
23#include <media/v4l2-dev.h>
24#include <media/v4l2-fh.h>
25#include <media/v4l2-ioctl.h>
26#include <media/v4l2-subdev.h>
27#include <media/videobuf2-v4l2.h>
28
29#include "ipu6.h"
30#include "ipu6-bus.h"
31#include "ipu6-cpd.h"
32#include "ipu6-fw-isys.h"
33#include "ipu6-isys.h"
34#include "ipu6-isys-csi2.h"
35#include "ipu6-isys-queue.h"
36#include "ipu6-isys-video.h"
37#include "ipu6-platform-regs.h"
38
39const struct ipu6_isys_pixelformat ipu6_isys_pfmts[] = {
40	{ V4L2_PIX_FMT_SBGGR12, 16, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
41	  IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
42	{ V4L2_PIX_FMT_SGBRG12, 16, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
43	  IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
44	{ V4L2_PIX_FMT_SGRBG12, 16, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
45	  IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
46	{ V4L2_PIX_FMT_SRGGB12, 16, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
47	  IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
48	{ V4L2_PIX_FMT_SBGGR10, 16, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
49	  IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
50	{ V4L2_PIX_FMT_SGBRG10, 16, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
51	  IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
52	{ V4L2_PIX_FMT_SGRBG10, 16, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
53	  IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
54	{ V4L2_PIX_FMT_SRGGB10, 16, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
55	  IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
56	{ V4L2_PIX_FMT_SBGGR8, 8, 8, MEDIA_BUS_FMT_SBGGR8_1X8,
57	  IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
58	{ V4L2_PIX_FMT_SGBRG8, 8, 8, MEDIA_BUS_FMT_SGBRG8_1X8,
59	  IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
60	{ V4L2_PIX_FMT_SGRBG8, 8, 8, MEDIA_BUS_FMT_SGRBG8_1X8,
61	  IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
62	{ V4L2_PIX_FMT_SRGGB8, 8, 8, MEDIA_BUS_FMT_SRGGB8_1X8,
63	  IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
64	{ V4L2_PIX_FMT_SBGGR12P, 12, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
65	  IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
66	{ V4L2_PIX_FMT_SGBRG12P, 12, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
67	  IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
68	{ V4L2_PIX_FMT_SGRBG12P, 12, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
69	  IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
70	{ V4L2_PIX_FMT_SRGGB12P, 12, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
71	  IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
72	{ V4L2_PIX_FMT_SBGGR10P, 10, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
73	  IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
74	{ V4L2_PIX_FMT_SGBRG10P, 10, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
75	  IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
76	{ V4L2_PIX_FMT_SGRBG10P, 10, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
77	  IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
78	{ V4L2_PIX_FMT_SRGGB10P, 10, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
79	  IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
80	{ V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16,
81	  IPU6_FW_ISYS_FRAME_FORMAT_UYVY},
82	{ V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16,
83	  IPU6_FW_ISYS_FRAME_FORMAT_YUYV},
84	{ V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16,
85	  IPU6_FW_ISYS_FRAME_FORMAT_RGB565 },
86	{ V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24,
87	  IPU6_FW_ISYS_FRAME_FORMAT_RGBA888 },
88	{ V4L2_META_FMT_GENERIC_8, 8, 8, MEDIA_BUS_FMT_META_8,
89	  IPU6_FW_ISYS_FRAME_FORMAT_RAW8, true },
90	{ V4L2_META_FMT_GENERIC_CSI2_10, 10, 10, MEDIA_BUS_FMT_META_10,
91	  IPU6_FW_ISYS_FRAME_FORMAT_RAW10, true },
92	{ V4L2_META_FMT_GENERIC_CSI2_12, 12, 12, MEDIA_BUS_FMT_META_12,
93	  IPU6_FW_ISYS_FRAME_FORMAT_RAW12, true },
94	{ V4L2_META_FMT_GENERIC_CSI2_16, 16, 16, MEDIA_BUS_FMT_META_16,
95	  IPU6_FW_ISYS_FRAME_FORMAT_RAW16, true },
96};
97
98static int video_open(struct file *file)
99{
100	struct ipu6_isys_video *av = video_drvdata(file);
101	struct ipu6_isys *isys = av->isys;
102	struct ipu6_bus_device *adev = isys->adev;
103
104	mutex_lock(&isys->mutex);
105	if (isys->need_reset) {
106		mutex_unlock(&isys->mutex);
107		dev_warn(&adev->auxdev.dev, "isys power cycle required\n");
108		return -EIO;
109	}
110	mutex_unlock(&isys->mutex);
111
112	return v4l2_fh_open(file);
113}
114
115const struct ipu6_isys_pixelformat *
116ipu6_isys_get_isys_format(u32 pixelformat, u32 type)
117{
118	const struct ipu6_isys_pixelformat *default_pfmt = NULL;
119	unsigned int i;
120
121	for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
122		const struct ipu6_isys_pixelformat *pfmt = &ipu6_isys_pfmts[i];
123
124		if (type && ((!pfmt->is_meta &&
125			      type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
126			     (pfmt->is_meta &&
127			      type != V4L2_BUF_TYPE_META_CAPTURE)))
128			continue;
129
130		if (!default_pfmt)
131			default_pfmt = pfmt;
132
133		if (pfmt->pixelformat != pixelformat)
134			continue;
135
136		return pfmt;
137	}
138
139	return default_pfmt;
140}
141
142static int ipu6_isys_vidioc_querycap(struct file *file, void *fh,
143				     struct v4l2_capability *cap)
144{
145	struct ipu6_isys_video *av = video_drvdata(file);
146
147	strscpy(cap->driver, IPU6_ISYS_NAME, sizeof(cap->driver));
148	strscpy(cap->card, av->isys->media_dev.model, sizeof(cap->card));
149
150	return 0;
151}
152
153static int ipu6_isys_vidioc_enum_fmt(struct file *file, void *fh,
154				     struct v4l2_fmtdesc *f)
155{
156	unsigned int i, num_found;
157
158	for (i = 0, num_found = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
159		if ((ipu6_isys_pfmts[i].is_meta &&
160		     f->type != V4L2_BUF_TYPE_META_CAPTURE) ||
161		    (!ipu6_isys_pfmts[i].is_meta &&
162		     f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
163			continue;
164
165		if (f->mbus_code && f->mbus_code != ipu6_isys_pfmts[i].code)
166			continue;
167
168		if (num_found < f->index) {
169			num_found++;
170			continue;
171		}
172
173		f->flags = 0;
174		f->pixelformat = ipu6_isys_pfmts[i].pixelformat;
175
176		return 0;
177	}
178
179	return -EINVAL;
180}
181
182static int ipu6_isys_vidioc_enum_framesizes(struct file *file, void *fh,
183					    struct v4l2_frmsizeenum *fsize)
184{
185	unsigned int i;
186
187	if (fsize->index > 0)
188		return -EINVAL;
189
190	for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
191		if (fsize->pixel_format != ipu6_isys_pfmts[i].pixelformat)
192			continue;
193
194		fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
195		fsize->stepwise.min_width = IPU6_ISYS_MIN_WIDTH;
196		fsize->stepwise.max_width = IPU6_ISYS_MAX_WIDTH;
197		fsize->stepwise.min_height = IPU6_ISYS_MIN_HEIGHT;
198		fsize->stepwise.max_height = IPU6_ISYS_MAX_HEIGHT;
199		fsize->stepwise.step_width = 2;
200		fsize->stepwise.step_height = 2;
201
202		return 0;
203	}
204
205	return -EINVAL;
206}
207
208static int ipu6_isys_vidioc_g_fmt_vid_cap(struct file *file, void *fh,
209				      struct v4l2_format *f)
210{
211	struct ipu6_isys_video *av = video_drvdata(file);
212
213	f->fmt.pix = av->pix_fmt;
214
215	return 0;
216}
217
218static int ipu6_isys_vidioc_g_fmt_meta_cap(struct file *file, void *fh,
219					   struct v4l2_format *f)
220{
221	struct ipu6_isys_video *av = video_drvdata(file);
222
223	f->fmt.meta = av->meta_fmt;
224
225	return 0;
226}
227
228static void ipu6_isys_try_fmt_cap(struct ipu6_isys_video *av, u32 type,
229				  u32 *format, u32 *width, u32 *height,
230				  u32 *bytesperline, u32 *sizeimage)
231{
232	const struct ipu6_isys_pixelformat *pfmt =
233		ipu6_isys_get_isys_format(*format, type);
234
235	*format = pfmt->pixelformat;
236	*width = clamp(*width, IPU6_ISYS_MIN_WIDTH, IPU6_ISYS_MAX_WIDTH);
237	*height = clamp(*height, IPU6_ISYS_MIN_HEIGHT, IPU6_ISYS_MAX_HEIGHT);
238
239	if (pfmt->bpp != pfmt->bpp_packed)
240		*bytesperline = *width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE);
241	else
242		*bytesperline = DIV_ROUND_UP(*width * pfmt->bpp, BITS_PER_BYTE);
243
244	*bytesperline = ALIGN(*bytesperline, av->isys->line_align);
245
246	/*
247	 * (height + 1) * bytesperline due to a hardware issue: the DMA unit
248	 * is a power of two, and a line should be transferred as few units
249	 * as possible. The result is that up to line length more data than
250	 * the image size may be transferred to memory after the image.
251	 * Another limitation is the GDA allocation unit size. For low
252	 * resolution it gives a bigger number. Use larger one to avoid
253	 * memory corruption.
254	 */
255	*sizeimage = *bytesperline * *height +
256		max(*bytesperline,
257		    av->isys->pdata->ipdata->isys_dma_overshoot);
258}
259
260static void __ipu6_isys_vidioc_try_fmt_vid_cap(struct ipu6_isys_video *av,
261					       struct v4l2_format *f)
262{
263	ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.pix.pixelformat,
264			      &f->fmt.pix.width, &f->fmt.pix.height,
265			      &f->fmt.pix.bytesperline, &f->fmt.pix.sizeimage);
266
267	f->fmt.pix.field = V4L2_FIELD_NONE;
268	f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
269	f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
270	f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
271	f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
272}
273
274static int ipu6_isys_vidioc_try_fmt_vid_cap(struct file *file, void *fh,
275					    struct v4l2_format *f)
276{
277	struct ipu6_isys_video *av = video_drvdata(file);
278
279	if (vb2_is_busy(&av->aq.vbq))
280		return -EBUSY;
281
282	__ipu6_isys_vidioc_try_fmt_vid_cap(av, f);
283
284	return 0;
285}
286
287static int __ipu6_isys_vidioc_try_fmt_meta_cap(struct ipu6_isys_video *av,
288					       struct v4l2_format *f)
289{
290	ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.meta.dataformat,
291			      &f->fmt.meta.width, &f->fmt.meta.height,
292			      &f->fmt.meta.bytesperline,
293			      &f->fmt.meta.buffersize);
294
295	return 0;
296}
297
298static int ipu6_isys_vidioc_try_fmt_meta_cap(struct file *file, void *fh,
299					     struct v4l2_format *f)
300{
301	struct ipu6_isys_video *av = video_drvdata(file);
302
303	__ipu6_isys_vidioc_try_fmt_meta_cap(av, f);
304
305	return 0;
306}
307
308static int ipu6_isys_vidioc_s_fmt_vid_cap(struct file *file, void *fh,
309				      struct v4l2_format *f)
310{
311	struct ipu6_isys_video *av = video_drvdata(file);
312
313	ipu6_isys_vidioc_try_fmt_vid_cap(file, fh, f);
314	av->pix_fmt = f->fmt.pix;
315
316	return 0;
317}
318
319static int ipu6_isys_vidioc_s_fmt_meta_cap(struct file *file, void *fh,
320					   struct v4l2_format *f)
321{
322	struct ipu6_isys_video *av = video_drvdata(file);
323
324	if (vb2_is_busy(&av->aq.vbq))
325		return -EBUSY;
326
327	ipu6_isys_vidioc_try_fmt_meta_cap(file, fh, f);
328	av->meta_fmt = f->fmt.meta;
329
330	return 0;
331}
332
333static int ipu6_isys_vidioc_reqbufs(struct file *file, void *priv,
334				    struct v4l2_requestbuffers *p)
335{
336	struct ipu6_isys_video *av = video_drvdata(file);
337	int ret;
338
339	av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->type);
340	av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->type);
341
342	ret = vb2_queue_change_type(&av->aq.vbq, p->type);
343	if (ret)
344		return ret;
345
346	return vb2_ioctl_reqbufs(file, priv, p);
347}
348
349static int ipu6_isys_vidioc_create_bufs(struct file *file, void *priv,
350					struct v4l2_create_buffers *p)
351{
352	struct ipu6_isys_video *av = video_drvdata(file);
353	int ret;
354
355	av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->format.type);
356	av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->format.type);
357
358	ret = vb2_queue_change_type(&av->aq.vbq, p->format.type);
359	if (ret)
360		return ret;
361
362	return vb2_ioctl_create_bufs(file, priv, p);
363}
364
365static int link_validate(struct media_link *link)
366{
367	struct ipu6_isys_video *av =
368		container_of(link->sink, struct ipu6_isys_video, pad);
369	struct device *dev = &av->isys->adev->auxdev.dev;
370	struct v4l2_subdev_state *s_state;
371	struct v4l2_subdev *s_sd;
372	struct v4l2_mbus_framefmt *s_fmt;
373	struct media_pad *s_pad;
374	u32 s_stream, code;
375	int ret = -EPIPE;
376
377	if (!link->source->entity)
378		return ret;
379
380	s_sd = media_entity_to_v4l2_subdev(link->source->entity);
381	s_state = v4l2_subdev_get_unlocked_active_state(s_sd);
382	if (!s_state)
383		return ret;
384
385	dev_dbg(dev, "validating link \"%s\":%u -> \"%s\"\n",
386		link->source->entity->name, link->source->index,
387		link->sink->entity->name);
388
389	s_pad = media_pad_remote_pad_first(&av->pad);
390	s_stream = ipu6_isys_get_src_stream_by_src_pad(s_sd, s_pad->index);
391
392	v4l2_subdev_lock_state(s_state);
393
394	s_fmt = v4l2_subdev_state_get_format(s_state, s_pad->index, s_stream);
395	if (!s_fmt) {
396		dev_err(dev, "failed to get source pad format\n");
397		goto unlock;
398	}
399
400	code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code;
401
402	if (s_fmt->width != ipu6_isys_get_frame_width(av) ||
403	    s_fmt->height != ipu6_isys_get_frame_height(av) ||
404	    s_fmt->code != code) {
405		dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n",
406			s_fmt->width, s_fmt->height, s_fmt->code,
407			ipu6_isys_get_frame_width(av),
408			ipu6_isys_get_frame_height(av), code);
409		goto unlock;
410	}
411
412	v4l2_subdev_unlock_state(s_state);
413
414	return 0;
415unlock:
416	v4l2_subdev_unlock_state(s_state);
417
418	return ret;
419}
420
421static void get_stream_opened(struct ipu6_isys_video *av)
422{
423	unsigned long flags;
424
425	spin_lock_irqsave(&av->isys->streams_lock, flags);
426	av->isys->stream_opened++;
427	spin_unlock_irqrestore(&av->isys->streams_lock, flags);
428}
429
430static void put_stream_opened(struct ipu6_isys_video *av)
431{
432	unsigned long flags;
433
434	spin_lock_irqsave(&av->isys->streams_lock, flags);
435	av->isys->stream_opened--;
436	spin_unlock_irqrestore(&av->isys->streams_lock, flags);
437}
438
439static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
440				struct ipu6_fw_isys_stream_cfg_data_abi *cfg)
441{
442	struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
443	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
444	struct ipu6_fw_isys_input_pin_info_abi *input_pin;
445	struct ipu6_fw_isys_output_pin_info_abi *output_pin;
446	struct ipu6_isys_stream *stream = av->stream;
447	struct ipu6_isys_queue *aq = &av->aq;
448	struct v4l2_mbus_framefmt fmt;
449	const struct ipu6_isys_pixelformat *pfmt =
450		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
451	struct v4l2_rect v4l2_crop;
452	struct ipu6_isys *isys = av->isys;
453	struct device *dev = &isys->adev->auxdev.dev;
454	int input_pins = cfg->nof_input_pins++;
455	int output_pins;
456	u32 src_stream;
457	int ret;
458
459	src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
460	ret = ipu6_isys_get_stream_pad_fmt(sd, src_pad->index, src_stream,
461					   &fmt);
462	if (ret < 0) {
463		dev_err(dev, "can't get stream format (%d)\n", ret);
464		return ret;
465	}
466
467	ret = ipu6_isys_get_stream_pad_crop(sd, src_pad->index, src_stream,
468					    &v4l2_crop);
469	if (ret < 0) {
470		dev_err(dev, "can't get stream crop (%d)\n", ret);
471		return ret;
472	}
473
474	input_pin = &cfg->input_pins[input_pins];
475	input_pin->input_res.width = fmt.width;
476	input_pin->input_res.height = fmt.height;
477	input_pin->dt = av->dt;
478	input_pin->bits_per_pix = pfmt->bpp_packed;
479	input_pin->mapped_dt = 0x40; /* invalid mipi data type */
480	input_pin->mipi_decompression = 0;
481	input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR;
482	input_pin->mipi_store_mode = pfmt->bpp == pfmt->bpp_packed ?
483		IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER :
484		IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL;
485	input_pin->crop_first_and_last_lines = v4l2_crop.top & 1;
486
487	output_pins = cfg->nof_output_pins++;
488	aq->fw_output = output_pins;
489	stream->output_pins[output_pins].pin_ready = ipu6_isys_queue_buf_ready;
490	stream->output_pins[output_pins].aq = aq;
491
492	output_pin = &cfg->output_pins[output_pins];
493	output_pin->input_pin_id = input_pins;
494	output_pin->output_res.width = ipu6_isys_get_frame_width(av);
495	output_pin->output_res.height = ipu6_isys_get_frame_height(av);
496
497	output_pin->stride = ipu6_isys_get_bytes_per_line(av);
498	if (pfmt->bpp != pfmt->bpp_packed)
499		output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC;
500	else
501		output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI;
502	output_pin->ft = pfmt->css_pixelformat;
503	output_pin->send_irq = 1;
504	memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets));
505	output_pin->s2m_pixel_soc_pixel_remapping =
506		S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
507	output_pin->csi_be_soc_pixel_remapping =
508		CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
509
510	output_pin->snoopable = true;
511	output_pin->error_handling_enable = false;
512	output_pin->sensor_type = isys->sensor_type++;
513	if (isys->sensor_type > isys->pdata->ipdata->sensor_type_end)
514		isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
515
516	return 0;
517}
518
519static int start_stream_firmware(struct ipu6_isys_video *av,
520				 struct ipu6_isys_buffer_list *bl)
521{
522	struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
523	struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
524	struct ipu6_isys_stream *stream = av->stream;
525	struct device *dev = &av->isys->adev->auxdev.dev;
526	struct isys_fw_msgs *msg = NULL;
527	struct ipu6_isys_queue *aq;
528	int ret, retout, tout;
529	u16 send_type;
530
531	msg = ipu6_get_fw_msg_buf(stream);
532	if (!msg)
533		return -ENOMEM;
534
535	stream_cfg = &msg->fw_msg.stream;
536	stream_cfg->src = stream->stream_source;
537	stream_cfg->vc = stream->vc;
538	stream_cfg->isl_use = 0;
539	stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL;
540
541	list_for_each_entry(aq, &stream->queues, node) {
542		struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
543
544		ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
545		if (ret < 0) {
546			ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg);
547			return ret;
548		}
549	}
550
551	ipu6_fw_isys_dump_stream_cfg(dev, stream_cfg);
552
553	stream->nr_output_pins = stream_cfg->nof_output_pins;
554
555	reinit_completion(&stream->stream_open_completion);
556
557	ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
558				       stream_cfg, msg->dma_addr,
559				       sizeof(*stream_cfg),
560				       IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
561	if (ret < 0) {
562		dev_err(dev, "can't open stream (%d)\n", ret);
563		ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg);
564		return ret;
565	}
566
567	get_stream_opened(av);
568
569	tout = wait_for_completion_timeout(&stream->stream_open_completion,
570					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
571
572	ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg);
573
574	if (!tout) {
575		dev_err(dev, "stream open time out\n");
576		ret = -ETIMEDOUT;
577		goto out_put_stream_opened;
578	}
579	if (stream->error) {
580		dev_err(dev, "stream open error: %d\n", stream->error);
581		ret = -EIO;
582		goto out_put_stream_opened;
583	}
584	dev_dbg(dev, "start stream: open complete\n");
585
586	if (bl) {
587		msg = ipu6_get_fw_msg_buf(stream);
588		if (!msg) {
589			ret = -ENOMEM;
590			goto out_put_stream_opened;
591		}
592		buf = &msg->fw_msg.frame;
593		ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
594		ipu6_isys_buffer_list_queue(bl,
595					    IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
596	}
597
598	reinit_completion(&stream->stream_start_completion);
599
600	if (bl) {
601		send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
602		ipu6_fw_isys_dump_frame_buff_set(dev, buf,
603						 stream_cfg->nof_output_pins);
604		ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
605					       buf, msg->dma_addr,
606					       sizeof(*buf), send_type);
607	} else {
608		send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START;
609		ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
610					      send_type);
611	}
612
613	if (ret < 0) {
614		dev_err(dev, "can't start streaming (%d)\n", ret);
615		goto out_stream_close;
616	}
617
618	tout = wait_for_completion_timeout(&stream->stream_start_completion,
619					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
620	if (!tout) {
621		dev_err(dev, "stream start time out\n");
622		ret = -ETIMEDOUT;
623		goto out_stream_close;
624	}
625	if (stream->error) {
626		dev_err(dev, "stream start error: %d\n", stream->error);
627		ret = -EIO;
628		goto out_stream_close;
629	}
630	dev_dbg(dev, "start stream: complete\n");
631
632	return 0;
633
634out_stream_close:
635	reinit_completion(&stream->stream_close_completion);
636
637	retout = ipu6_fw_isys_simple_cmd(av->isys,
638					 stream->stream_handle,
639					 IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
640	if (retout < 0) {
641		dev_dbg(dev, "can't close stream (%d)\n", retout);
642		goto out_put_stream_opened;
643	}
644
645	tout = wait_for_completion_timeout(&stream->stream_close_completion,
646					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
647	if (!tout)
648		dev_err(dev, "stream close time out\n");
649	else if (stream->error)
650		dev_err(dev, "stream close error: %d\n", stream->error);
651	else
652		dev_dbg(dev, "stream close complete\n");
653
654out_put_stream_opened:
655	put_stream_opened(av);
656
657	return ret;
658}
659
660static void stop_streaming_firmware(struct ipu6_isys_video *av)
661{
662	struct device *dev = &av->isys->adev->auxdev.dev;
663	struct ipu6_isys_stream *stream = av->stream;
664	int ret, tout;
665
666	reinit_completion(&stream->stream_stop_completion);
667
668	ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
669				      IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
670
671	if (ret < 0) {
672		dev_err(dev, "can't stop stream (%d)\n", ret);
673		return;
674	}
675
676	tout = wait_for_completion_timeout(&stream->stream_stop_completion,
677					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
678	if (!tout)
679		dev_warn(dev, "stream stop time out\n");
680	else if (stream->error)
681		dev_warn(dev, "stream stop error: %d\n", stream->error);
682	else
683		dev_dbg(dev, "stop stream: complete\n");
684}
685
686static void close_streaming_firmware(struct ipu6_isys_video *av)
687{
688	struct ipu6_isys_stream *stream = av->stream;
689	struct device *dev = &av->isys->adev->auxdev.dev;
690	int ret, tout;
691
692	reinit_completion(&stream->stream_close_completion);
693
694	ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
695				      IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
696	if (ret < 0) {
697		dev_err(dev, "can't close stream (%d)\n", ret);
698		return;
699	}
700
701	tout = wait_for_completion_timeout(&stream->stream_close_completion,
702					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
703	if (!tout)
704		dev_warn(dev, "stream close time out\n");
705	else if (stream->error)
706		dev_warn(dev, "stream close error: %d\n", stream->error);
707	else
708		dev_dbg(dev, "close stream: complete\n");
709
710	put_stream_opened(av);
711}
712
713int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
714				   struct media_entity *source_entity,
715				   int nr_queues)
716{
717	struct ipu6_isys_stream *stream = av->stream;
718	struct ipu6_isys_csi2 *csi2;
719
720	if (WARN_ON(stream->nr_streaming))
721		return -EINVAL;
722
723	stream->nr_queues = nr_queues;
724	atomic_set(&stream->sequence, 0);
725
726	stream->seq_index = 0;
727	memset(stream->seq, 0, sizeof(stream->seq));
728
729	if (WARN_ON(!list_empty(&stream->queues)))
730		return -EINVAL;
731
732	stream->stream_source = stream->asd->source;
733	csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
734	csi2->receiver_errors = 0;
735	stream->source_entity = source_entity;
736
737	dev_dbg(&av->isys->adev->auxdev.dev,
738		"prepare stream: external entity %s\n",
739		stream->source_entity->name);
740
741	return 0;
742}
743
744void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
745					  bool state)
746{
747	struct ipu6_isys *isys = av->isys;
748	struct ipu6_isys_csi2 *csi2 = NULL;
749	struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
750	struct device *dev = &isys->adev->auxdev.dev;
751	struct v4l2_mbus_framefmt format;
752	struct v4l2_subdev *esd;
753	struct v4l2_control hb = { .id = V4L2_CID_HBLANK, .value = 0 };
754	unsigned int bpp, lanes;
755	s64 link_freq = 0;
756	u64 pixel_rate = 0;
757	int ret;
758
759	if (!state)
760		return;
761
762	esd = media_entity_to_v4l2_subdev(av->stream->source_entity);
763
764	av->watermark.width = ipu6_isys_get_frame_width(av);
765	av->watermark.height = ipu6_isys_get_frame_height(av);
766	av->watermark.sram_gran_shift = isys->pdata->ipdata->sram_gran_shift;
767	av->watermark.sram_gran_size = isys->pdata->ipdata->sram_gran_size;
768
769	ret = v4l2_g_ctrl(esd->ctrl_handler, &hb);
770	if (!ret && hb.value >= 0)
771		av->watermark.hblank = hb.value;
772	else
773		av->watermark.hblank = 0;
774
775	csi2 = ipu6_isys_subdev_to_csi2(av->stream->asd);
776	link_freq = ipu6_isys_csi2_get_link_freq(csi2);
777	if (link_freq > 0) {
778		lanes = csi2->nlanes;
779		ret = ipu6_isys_get_stream_pad_fmt(&csi2->asd.sd, 0,
780						   av->source_stream, &format);
781		if (!ret) {
782			bpp = ipu6_isys_mbus_code_to_bpp(format.code);
783			pixel_rate = mul_u64_u32_div(link_freq, lanes * 2, bpp);
784		}
785	}
786
787	av->watermark.pixel_rate = pixel_rate;
788
789	if (!pixel_rate) {
790		mutex_lock(&iwake_watermark->mutex);
791		iwake_watermark->force_iwake_disable = true;
792		mutex_unlock(&iwake_watermark->mutex);
793		dev_warn(dev, "unexpected pixel_rate from %s, disable iwake.\n",
794			 av->stream->source_entity->name);
795	}
796}
797
798static void calculate_stream_datarate(struct ipu6_isys_video *av)
799{
800	struct video_stream_watermark *watermark = &av->watermark;
801	const struct ipu6_isys_pixelformat *pfmt =
802		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
803	u32 pages_per_line, pb_bytes_per_line, pixels_per_line, bytes_per_line;
804	u64 line_time_ns, stream_data_rate;
805	u16 shift, size;
806
807	shift = watermark->sram_gran_shift;
808	size = watermark->sram_gran_size;
809
810	pixels_per_line = watermark->width + watermark->hblank;
811	line_time_ns =  div_u64(pixels_per_line * NSEC_PER_SEC,
812				watermark->pixel_rate);
813	bytes_per_line = watermark->width * pfmt->bpp / 8;
814	pages_per_line = DIV_ROUND_UP(bytes_per_line, size);
815	pb_bytes_per_line = pages_per_line << shift;
816	stream_data_rate = div64_u64(pb_bytes_per_line * 1000, line_time_ns);
817
818	watermark->stream_data_rate = stream_data_rate;
819}
820
821void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state)
822{
823	struct isys_iwake_watermark *iwake_watermark =
824		&av->isys->iwake_watermark;
825
826	if (!av->watermark.pixel_rate)
827		return;
828
829	if (state) {
830		calculate_stream_datarate(av);
831		mutex_lock(&iwake_watermark->mutex);
832		list_add(&av->watermark.stream_node,
833			 &iwake_watermark->video_list);
834		mutex_unlock(&iwake_watermark->mutex);
835	} else {
836		av->watermark.stream_data_rate = 0;
837		mutex_lock(&iwake_watermark->mutex);
838		list_del(&av->watermark.stream_node);
839		mutex_unlock(&iwake_watermark->mutex);
840	}
841
842	update_watermark_setting(av->isys);
843}
844
845void ipu6_isys_put_stream(struct ipu6_isys_stream *stream)
846{
847	struct device *dev;
848	unsigned int i;
849	unsigned long flags;
850
851	if (!stream) {
852		pr_err("ipu6-isys: no available stream\n");
853		return;
854	}
855
856	dev = &stream->isys->adev->auxdev.dev;
857
858	spin_lock_irqsave(&stream->isys->streams_lock, flags);
859	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
860		if (&stream->isys->streams[i] == stream) {
861			if (stream->isys->streams_ref_count[i] > 0)
862				stream->isys->streams_ref_count[i]--;
863			else
864				dev_warn(dev, "invalid stream %d\n", i);
865
866			break;
867		}
868	}
869	spin_unlock_irqrestore(&stream->isys->streams_lock, flags);
870}
871
872static struct ipu6_isys_stream *
873ipu6_isys_get_stream(struct ipu6_isys_video *av, struct ipu6_isys_subdev *asd)
874{
875	struct ipu6_isys_stream *stream = NULL;
876	struct ipu6_isys *isys = av->isys;
877	unsigned long flags;
878	unsigned int i;
879	u8 vc = av->vc;
880
881	if (!isys)
882		return NULL;
883
884	spin_lock_irqsave(&isys->streams_lock, flags);
885	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
886		if (isys->streams_ref_count[i] && isys->streams[i].vc == vc &&
887		    isys->streams[i].asd == asd) {
888			isys->streams_ref_count[i]++;
889			stream = &isys->streams[i];
890			break;
891		}
892	}
893
894	if (!stream) {
895		for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
896			if (!isys->streams_ref_count[i]) {
897				isys->streams_ref_count[i]++;
898				stream = &isys->streams[i];
899				stream->vc = vc;
900				stream->asd = asd;
901				break;
902			}
903		}
904	}
905	spin_unlock_irqrestore(&isys->streams_lock, flags);
906
907	return stream;
908}
909
910struct ipu6_isys_stream *
911ipu6_isys_query_stream_by_handle(struct ipu6_isys *isys, u8 stream_handle)
912{
913	unsigned long flags;
914	struct ipu6_isys_stream *stream = NULL;
915
916	if (!isys)
917		return NULL;
918
919	if (stream_handle >= IPU6_ISYS_MAX_STREAMS) {
920		dev_err(&isys->adev->auxdev.dev,
921			"stream_handle %d is invalid\n", stream_handle);
922		return NULL;
923	}
924
925	spin_lock_irqsave(&isys->streams_lock, flags);
926	if (isys->streams_ref_count[stream_handle] > 0) {
927		isys->streams_ref_count[stream_handle]++;
928		stream = &isys->streams[stream_handle];
929	}
930	spin_unlock_irqrestore(&isys->streams_lock, flags);
931
932	return stream;
933}
934
935struct ipu6_isys_stream *
936ipu6_isys_query_stream_by_source(struct ipu6_isys *isys, int source, u8 vc)
937{
938	struct ipu6_isys_stream *stream = NULL;
939	unsigned long flags;
940	unsigned int i;
941
942	if (!isys)
943		return NULL;
944
945	if (source < 0) {
946		dev_err(&stream->isys->adev->auxdev.dev,
947			"query stream with invalid port number\n");
948		return NULL;
949	}
950
951	spin_lock_irqsave(&isys->streams_lock, flags);
952	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
953		if (!isys->streams_ref_count[i])
954			continue;
955
956		if (isys->streams[i].stream_source == source &&
957		    isys->streams[i].vc == vc) {
958			stream = &isys->streams[i];
959			isys->streams_ref_count[i]++;
960			break;
961		}
962	}
963	spin_unlock_irqrestore(&isys->streams_lock, flags);
964
965	return stream;
966}
967
968static u64 get_stream_mask_by_pipeline(struct ipu6_isys_video *__av)
969{
970	struct media_pipeline *pipeline =
971		media_entity_pipeline(&__av->vdev.entity);
972	unsigned int i;
973	u64 stream_mask = 0;
974
975	for (i = 0; i < NR_OF_CSI2_SRC_PADS; i++) {
976		struct ipu6_isys_video *av = &__av->csi2->av[i];
977
978		if (pipeline == media_entity_pipeline(&av->vdev.entity))
979			stream_mask |= BIT_ULL(av->source_stream);
980	}
981
982	return stream_mask;
983}
984
985int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
986				  struct ipu6_isys_buffer_list *bl)
987{
988	struct v4l2_subdev_krouting *routing;
989	struct ipu6_isys_stream *stream = av->stream;
990	struct v4l2_subdev_state *subdev_state;
991	struct device *dev = &av->isys->adev->auxdev.dev;
992	struct v4l2_subdev *sd;
993	struct v4l2_subdev *ssd;
994	struct media_pad *r_pad;
995	struct media_pad *s_pad;
996	u32 sink_pad, sink_stream;
997	u64 r_stream;
998	u64 stream_mask = 0;
999	int ret = 0;
1000
1001	dev_dbg(dev, "set stream: %d\n", state);
1002
1003	if (WARN(!stream->source_entity, "No source entity for stream\n"))
1004		return -ENODEV;
1005
1006	ssd = media_entity_to_v4l2_subdev(stream->source_entity);
1007	sd = &stream->asd->sd;
1008	r_pad = media_pad_remote_pad_first(&av->pad);
1009	r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
1010
1011	subdev_state = v4l2_subdev_lock_and_get_active_state(sd);
1012	routing = &subdev_state->routing;
1013	ret = v4l2_subdev_routing_find_opposite_end(routing, r_pad->index,
1014						    r_stream, &sink_pad,
1015						    &sink_stream);
1016	v4l2_subdev_unlock_state(subdev_state);
1017	if (ret)
1018		return ret;
1019
1020	s_pad = media_pad_remote_pad_first(&stream->asd->pad[sink_pad]);
1021
1022	stream_mask = get_stream_mask_by_pipeline(av);
1023	if (!state) {
1024		stop_streaming_firmware(av);
1025
1026		/* stop external sub-device now. */
1027		dev_dbg(dev, "disable streams 0x%llx of %s\n", stream_mask,
1028			ssd->name);
1029		ret = v4l2_subdev_disable_streams(ssd, s_pad->index,
1030						  stream_mask);
1031		if (ret) {
1032			dev_err(dev, "disable streams of %s failed with %d\n",
1033				ssd->name, ret);
1034			return ret;
1035		}
1036
1037		/* stop sub-device which connects with video */
1038		dev_dbg(dev, "stream off entity %s pad:%d\n", sd->name,
1039			r_pad->index);
1040		ret = v4l2_subdev_call(sd, video, s_stream, state);
1041		if (ret) {
1042			dev_err(dev, "stream off %s failed with %d\n", sd->name,
1043				ret);
1044			return ret;
1045		}
1046		close_streaming_firmware(av);
1047	} else {
1048		ret = start_stream_firmware(av, bl);
1049		if (ret) {
1050			dev_err(dev, "start stream of firmware failed\n");
1051			return ret;
1052		}
1053
1054		/* start sub-device which connects with video */
1055		dev_dbg(dev, "stream on %s pad %d\n", sd->name, r_pad->index);
1056		ret = v4l2_subdev_call(sd, video, s_stream, state);
1057		if (ret) {
1058			dev_err(dev, "stream on %s failed with %d\n", sd->name,
1059				ret);
1060			goto out_media_entity_stop_streaming_firmware;
1061		}
1062
1063		/* start external sub-device now. */
1064		dev_dbg(dev, "enable streams 0x%llx of %s\n", stream_mask,
1065			ssd->name);
1066		ret = v4l2_subdev_enable_streams(ssd, s_pad->index,
1067						 stream_mask);
1068		if (ret) {
1069			dev_err(dev,
1070				"enable streams 0x%llx of %s failed with %d\n",
1071				stream_mask, stream->source_entity->name, ret);
1072			goto out_media_entity_stop_streaming;
1073		}
1074	}
1075
1076	av->streaming = state;
1077
1078	return 0;
1079
1080out_media_entity_stop_streaming:
1081	v4l2_subdev_disable_streams(sd, r_pad->index, BIT(r_stream));
1082
1083out_media_entity_stop_streaming_firmware:
1084	stop_streaming_firmware(av);
1085
1086	return ret;
1087}
1088
1089static const struct v4l2_ioctl_ops ipu6_v4l2_ioctl_ops = {
1090	.vidioc_querycap = ipu6_isys_vidioc_querycap,
1091	.vidioc_enum_fmt_vid_cap = ipu6_isys_vidioc_enum_fmt,
1092	.vidioc_enum_fmt_meta_cap = ipu6_isys_vidioc_enum_fmt,
1093	.vidioc_enum_framesizes = ipu6_isys_vidioc_enum_framesizes,
1094	.vidioc_g_fmt_vid_cap = ipu6_isys_vidioc_g_fmt_vid_cap,
1095	.vidioc_s_fmt_vid_cap = ipu6_isys_vidioc_s_fmt_vid_cap,
1096	.vidioc_try_fmt_vid_cap = ipu6_isys_vidioc_try_fmt_vid_cap,
1097	.vidioc_g_fmt_meta_cap = ipu6_isys_vidioc_g_fmt_meta_cap,
1098	.vidioc_s_fmt_meta_cap = ipu6_isys_vidioc_s_fmt_meta_cap,
1099	.vidioc_try_fmt_meta_cap = ipu6_isys_vidioc_try_fmt_meta_cap,
1100	.vidioc_reqbufs = ipu6_isys_vidioc_reqbufs,
1101	.vidioc_create_bufs = ipu6_isys_vidioc_create_bufs,
1102	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1103	.vidioc_querybuf = vb2_ioctl_querybuf,
1104	.vidioc_qbuf = vb2_ioctl_qbuf,
1105	.vidioc_dqbuf = vb2_ioctl_dqbuf,
1106	.vidioc_streamon = vb2_ioctl_streamon,
1107	.vidioc_streamoff = vb2_ioctl_streamoff,
1108	.vidioc_expbuf = vb2_ioctl_expbuf,
1109};
1110
1111static const struct media_entity_operations entity_ops = {
1112	.link_validate = link_validate,
1113};
1114
1115static const struct v4l2_file_operations isys_fops = {
1116	.owner = THIS_MODULE,
1117	.poll = vb2_fop_poll,
1118	.unlocked_ioctl = video_ioctl2,
1119	.mmap = vb2_fop_mmap,
1120	.open = video_open,
1121	.release = vb2_fop_release,
1122};
1123
1124int ipu6_isys_fw_open(struct ipu6_isys *isys)
1125{
1126	struct ipu6_bus_device *adev = isys->adev;
1127	const struct ipu6_isys_internal_pdata *ipdata = isys->pdata->ipdata;
1128	int ret;
1129
1130	ret = pm_runtime_resume_and_get(&adev->auxdev.dev);
1131	if (ret < 0)
1132		return ret;
1133
1134	mutex_lock(&isys->mutex);
1135
1136	if (isys->ref_count++)
1137		goto unlock;
1138
1139	ipu6_configure_spc(adev->isp, &ipdata->hw_variant,
1140			   IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX, isys->pdata->base,
1141			   adev->pkg_dir, adev->pkg_dir_dma_addr);
1142
1143	/*
1144	 * Buffers could have been left to wrong queue at last closure.
1145	 * Move them now back to empty buffer queue.
1146	 */
1147	ipu6_cleanup_fw_msg_bufs(isys);
1148
1149	if (isys->fwcom) {
1150		/*
1151		 * Something went wrong in previous shutdown. As we are now
1152		 * restarting isys we can safely delete old context.
1153		 */
1154		dev_warn(&adev->auxdev.dev, "clearing old context\n");
1155		ipu6_fw_isys_cleanup(isys);
1156	}
1157
1158	ret = ipu6_fw_isys_init(isys, ipdata->num_parallel_streams);
1159	if (ret < 0)
1160		goto out;
1161
1162unlock:
1163	mutex_unlock(&isys->mutex);
1164
1165	return 0;
1166
1167out:
1168	isys->ref_count--;
1169	mutex_unlock(&isys->mutex);
1170	pm_runtime_put(&adev->auxdev.dev);
1171
1172	return ret;
1173}
1174
1175void ipu6_isys_fw_close(struct ipu6_isys *isys)
1176{
1177	mutex_lock(&isys->mutex);
1178
1179	isys->ref_count--;
1180	if (!isys->ref_count) {
1181		ipu6_fw_isys_close(isys);
1182		if (isys->fwcom) {
1183			isys->need_reset = true;
1184			dev_warn(&isys->adev->auxdev.dev,
1185				 "failed to close fw isys\n");
1186		}
1187	}
1188
1189	mutex_unlock(&isys->mutex);
1190
1191	if (isys->need_reset)
1192		pm_runtime_put_sync(&isys->adev->auxdev.dev);
1193	else
1194		pm_runtime_put(&isys->adev->auxdev.dev);
1195}
1196
1197int ipu6_isys_setup_video(struct ipu6_isys_video *av,
1198			  struct media_entity **source_entity, int *nr_queues)
1199{
1200	const struct ipu6_isys_pixelformat *pfmt =
1201		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
1202	struct device *dev = &av->isys->adev->auxdev.dev;
1203	struct v4l2_mbus_frame_desc_entry entry;
1204	struct v4l2_subdev_route *route = NULL;
1205	struct v4l2_subdev_route *r;
1206	struct v4l2_subdev_state *state;
1207	struct ipu6_isys_subdev *asd;
1208	struct v4l2_subdev *remote_sd;
1209	struct media_pipeline *pipeline;
1210	struct media_pad *source_pad, *remote_pad;
1211	int ret = -EINVAL;
1212
1213	*nr_queues = 0;
1214
1215	remote_pad = media_pad_remote_pad_unique(&av->pad);
1216	if (IS_ERR(remote_pad)) {
1217		dev_dbg(dev, "failed to get remote pad\n");
1218		return PTR_ERR(remote_pad);
1219	}
1220
1221	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
1222	asd = to_ipu6_isys_subdev(remote_sd);
1223	source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]);
1224	if (!source_pad) {
1225		dev_dbg(dev, "No external source entity\n");
1226		return -ENODEV;
1227	}
1228
1229	*source_entity = source_pad->entity;
1230
1231	/* Find the root */
1232	state = v4l2_subdev_lock_and_get_active_state(remote_sd);
1233	for_each_active_route(&state->routing, r) {
1234		(*nr_queues)++;
1235
1236		if (r->source_pad == remote_pad->index)
1237			route = r;
1238	}
1239
1240	if (!route) {
1241		v4l2_subdev_unlock_state(state);
1242		dev_dbg(dev, "Failed to find route\n");
1243		return -ENODEV;
1244	}
1245	av->source_stream = route->sink_stream;
1246	v4l2_subdev_unlock_state(state);
1247
1248	ret = ipu6_isys_csi2_get_remote_desc(av->source_stream,
1249					     to_ipu6_isys_csi2(asd),
1250					     *source_entity, &entry);
1251	if (ret == -ENOIOCTLCMD) {
1252		av->vc = 0;
1253		av->dt = ipu6_isys_mbus_code_to_mipi(pfmt->code);
1254	} else if (!ret) {
1255		dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
1256			entry.stream, entry.length, entry.bus.csi2.vc,
1257			entry.bus.csi2.dt);
1258
1259		av->vc = entry.bus.csi2.vc;
1260		av->dt = entry.bus.csi2.dt;
1261	} else {
1262		dev_err(dev, "failed to get remote frame desc\n");
1263		return ret;
1264	}
1265
1266	pipeline = media_entity_pipeline(&av->vdev.entity);
1267	if (!pipeline)
1268		ret = video_device_pipeline_alloc_start(&av->vdev);
1269	else
1270		ret = video_device_pipeline_start(&av->vdev, pipeline);
1271	if (ret < 0) {
1272		dev_dbg(dev, "media pipeline start failed\n");
1273		return ret;
1274	}
1275
1276	av->stream = ipu6_isys_get_stream(av, asd);
1277	if (!av->stream) {
1278		video_device_pipeline_stop(&av->vdev);
1279		dev_err(dev, "no available stream for firmware\n");
1280		return -EINVAL;
1281	}
1282
1283	return 0;
1284}
1285
1286/*
1287 * Do everything that's needed to initialise things related to video
1288 * buffer queue, video node, and the related media entity. The caller
1289 * is expected to assign isys field and set the name of the video
1290 * device.
1291 */
1292int ipu6_isys_video_init(struct ipu6_isys_video *av)
1293{
1294	struct v4l2_format format = {
1295		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
1296		.fmt.pix = {
1297			.width = 1920,
1298			.height = 1080,
1299		},
1300	};
1301	struct v4l2_format format_meta = {
1302		.type = V4L2_BUF_TYPE_META_CAPTURE,
1303		.fmt.meta = {
1304			.width = 1920,
1305			.height = 4,
1306		},
1307	};
1308	int ret;
1309
1310	mutex_init(&av->mutex);
1311	av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC |
1312			       V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE;
1313	av->vdev.vfl_dir = VFL_DIR_RX;
1314
1315	ret = ipu6_isys_queue_init(&av->aq);
1316	if (ret)
1317		goto out_free_watermark;
1318
1319	av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
1320	ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad);
1321	if (ret)
1322		goto out_vb2_queue_release;
1323
1324	av->vdev.entity.ops = &entity_ops;
1325	av->vdev.release = video_device_release_empty;
1326	av->vdev.fops = &isys_fops;
1327	av->vdev.v4l2_dev = &av->isys->v4l2_dev;
1328	if (!av->vdev.ioctl_ops)
1329		av->vdev.ioctl_ops = &ipu6_v4l2_ioctl_ops;
1330	av->vdev.queue = &av->aq.vbq;
1331	av->vdev.lock = &av->mutex;
1332
1333	__ipu6_isys_vidioc_try_fmt_vid_cap(av, &format);
1334	av->pix_fmt = format.fmt.pix;
1335	__ipu6_isys_vidioc_try_fmt_meta_cap(av, &format_meta);
1336	av->meta_fmt = format_meta.fmt.meta;
1337
1338	set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags);
1339	video_set_drvdata(&av->vdev, av);
1340
1341	ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1);
1342	if (ret)
1343		goto out_media_entity_cleanup;
1344
1345	return ret;
1346
1347out_media_entity_cleanup:
1348	vb2_video_unregister_device(&av->vdev);
1349	media_entity_cleanup(&av->vdev.entity);
1350
1351out_vb2_queue_release:
1352	vb2_queue_release(&av->aq.vbq);
1353
1354out_free_watermark:
1355	mutex_destroy(&av->mutex);
1356
1357	return ret;
1358}
1359
1360void ipu6_isys_video_cleanup(struct ipu6_isys_video *av)
1361{
1362	vb2_video_unregister_device(&av->vdev);
1363	media_entity_cleanup(&av->vdev.entity);
1364	mutex_destroy(&av->mutex);
1365}
1366
1367u32 ipu6_isys_get_format(struct ipu6_isys_video *av)
1368{
1369	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1370		return av->pix_fmt.pixelformat;
1371
1372	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1373		return av->meta_fmt.dataformat;
1374
1375	return 0;
1376}
1377
1378u32 ipu6_isys_get_data_size(struct ipu6_isys_video *av)
1379{
1380	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1381		return av->pix_fmt.sizeimage;
1382
1383	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1384		return av->meta_fmt.buffersize;
1385
1386	return 0;
1387}
1388
1389u32 ipu6_isys_get_bytes_per_line(struct ipu6_isys_video *av)
1390{
1391	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1392		return av->pix_fmt.bytesperline;
1393
1394	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1395		return av->meta_fmt.bytesperline;
1396
1397	return 0;
1398}
1399
1400u32 ipu6_isys_get_frame_width(struct ipu6_isys_video *av)
1401{
1402	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1403		return av->pix_fmt.width;
1404
1405	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1406		return av->meta_fmt.width;
1407
1408	return 0;
1409}
1410
1411u32 ipu6_isys_get_frame_height(struct ipu6_isys_video *av)
1412{
1413	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1414		return av->pix_fmt.height;
1415
1416	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1417		return av->meta_fmt.height;
1418
1419	return 0;
1420}
1421