brintos

brintos / linux-shallow public Read only

0
0
Text · 37.6 KiB · b375613 Raw
1392 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013--2024 Intel Corporation4 */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	else242		*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 unit248	 * is a power of two, and a line should be transferred as few units249	 * as possible. The result is that up to line length more data than250	 * the image size may be transferred to memory after the image.251	 * Another limitation is the GDA allocation unit size. For low252	 * resolution it gives a bigger number. Use larger one to avoid253	 * 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	else501		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	else652		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	else683		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	else708		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	else773		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			else864				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(&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 media_pad *r_pad;994	u32 sink_pad, sink_stream;995	u64 r_stream;996	u64 stream_mask = 0;997	int ret = 0;998 999	dev_dbg(dev, "set stream: %d\n", state);1000 1001	if (WARN(!stream->source_entity, "No source entity for stream\n"))1002		return -ENODEV;1003 1004	sd = &stream->asd->sd;1005	r_pad = media_pad_remote_pad_first(&av->pad);1006	r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);1007 1008	subdev_state = v4l2_subdev_lock_and_get_active_state(sd);1009	routing = &subdev_state->routing;1010	ret = v4l2_subdev_routing_find_opposite_end(routing, r_pad->index,1011						    r_stream, &sink_pad,1012						    &sink_stream);1013	v4l2_subdev_unlock_state(subdev_state);1014	if (ret)1015		return ret;1016 1017	stream_mask = get_stream_mask_by_pipeline(av);1018	if (!state) {1019		stop_streaming_firmware(av);1020 1021		/* stop sub-device which connects with video */1022		dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n",1023			sd->name, r_pad->index, stream_mask);1024		ret = v4l2_subdev_disable_streams(sd, r_pad->index,1025						  stream_mask);1026		if (ret) {1027			dev_err(dev, "stream off %s failed with %d\n", sd->name,1028				ret);1029			return ret;1030		}1031		close_streaming_firmware(av);1032	} else {1033		ret = start_stream_firmware(av, bl);1034		if (ret) {1035			dev_err(dev, "start stream of firmware failed\n");1036			return ret;1037		}1038 1039		/* start sub-device which connects with video */1040		dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name,1041			r_pad->index, stream_mask);1042		ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask);1043		if (ret) {1044			dev_err(dev, "stream on %s failed with %d\n", sd->name,1045				ret);1046			goto out_media_entity_stop_streaming_firmware;1047		}1048	}1049 1050	av->streaming = state;1051 1052	return 0;1053 1054out_media_entity_stop_streaming_firmware:1055	stop_streaming_firmware(av);1056 1057	return ret;1058}1059 1060static const struct v4l2_ioctl_ops ipu6_v4l2_ioctl_ops = {1061	.vidioc_querycap = ipu6_isys_vidioc_querycap,1062	.vidioc_enum_fmt_vid_cap = ipu6_isys_vidioc_enum_fmt,1063	.vidioc_enum_fmt_meta_cap = ipu6_isys_vidioc_enum_fmt,1064	.vidioc_enum_framesizes = ipu6_isys_vidioc_enum_framesizes,1065	.vidioc_g_fmt_vid_cap = ipu6_isys_vidioc_g_fmt_vid_cap,1066	.vidioc_s_fmt_vid_cap = ipu6_isys_vidioc_s_fmt_vid_cap,1067	.vidioc_try_fmt_vid_cap = ipu6_isys_vidioc_try_fmt_vid_cap,1068	.vidioc_g_fmt_meta_cap = ipu6_isys_vidioc_g_fmt_meta_cap,1069	.vidioc_s_fmt_meta_cap = ipu6_isys_vidioc_s_fmt_meta_cap,1070	.vidioc_try_fmt_meta_cap = ipu6_isys_vidioc_try_fmt_meta_cap,1071	.vidioc_reqbufs = ipu6_isys_vidioc_reqbufs,1072	.vidioc_create_bufs = ipu6_isys_vidioc_create_bufs,1073	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,1074	.vidioc_querybuf = vb2_ioctl_querybuf,1075	.vidioc_qbuf = vb2_ioctl_qbuf,1076	.vidioc_dqbuf = vb2_ioctl_dqbuf,1077	.vidioc_streamon = vb2_ioctl_streamon,1078	.vidioc_streamoff = vb2_ioctl_streamoff,1079	.vidioc_expbuf = vb2_ioctl_expbuf,1080};1081 1082static const struct media_entity_operations entity_ops = {1083	.link_validate = link_validate,1084};1085 1086static const struct v4l2_file_operations isys_fops = {1087	.owner = THIS_MODULE,1088	.poll = vb2_fop_poll,1089	.unlocked_ioctl = video_ioctl2,1090	.mmap = vb2_fop_mmap,1091	.open = video_open,1092	.release = vb2_fop_release,1093};1094 1095int ipu6_isys_fw_open(struct ipu6_isys *isys)1096{1097	struct ipu6_bus_device *adev = isys->adev;1098	const struct ipu6_isys_internal_pdata *ipdata = isys->pdata->ipdata;1099	int ret;1100 1101	ret = pm_runtime_resume_and_get(&adev->auxdev.dev);1102	if (ret < 0)1103		return ret;1104 1105	mutex_lock(&isys->mutex);1106 1107	if (isys->ref_count++)1108		goto unlock;1109 1110	ipu6_configure_spc(adev->isp, &ipdata->hw_variant,1111			   IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX, isys->pdata->base,1112			   adev->pkg_dir, adev->pkg_dir_dma_addr);1113 1114	/*1115	 * Buffers could have been left to wrong queue at last closure.1116	 * Move them now back to empty buffer queue.1117	 */1118	ipu6_cleanup_fw_msg_bufs(isys);1119 1120	if (isys->fwcom) {1121		/*1122		 * Something went wrong in previous shutdown. As we are now1123		 * restarting isys we can safely delete old context.1124		 */1125		dev_warn(&adev->auxdev.dev, "clearing old context\n");1126		ipu6_fw_isys_cleanup(isys);1127	}1128 1129	ret = ipu6_fw_isys_init(isys, ipdata->num_parallel_streams);1130	if (ret < 0)1131		goto out;1132 1133unlock:1134	mutex_unlock(&isys->mutex);1135 1136	return 0;1137 1138out:1139	isys->ref_count--;1140	mutex_unlock(&isys->mutex);1141	pm_runtime_put(&adev->auxdev.dev);1142 1143	return ret;1144}1145 1146void ipu6_isys_fw_close(struct ipu6_isys *isys)1147{1148	mutex_lock(&isys->mutex);1149 1150	isys->ref_count--;1151	if (!isys->ref_count) {1152		ipu6_fw_isys_close(isys);1153		if (isys->fwcom) {1154			isys->need_reset = true;1155			dev_warn(&isys->adev->auxdev.dev,1156				 "failed to close fw isys\n");1157		}1158	}1159 1160	mutex_unlock(&isys->mutex);1161 1162	if (isys->need_reset)1163		pm_runtime_put_sync(&isys->adev->auxdev.dev);1164	else1165		pm_runtime_put(&isys->adev->auxdev.dev);1166}1167 1168int ipu6_isys_setup_video(struct ipu6_isys_video *av,1169			  struct media_entity **source_entity, int *nr_queues)1170{1171	const struct ipu6_isys_pixelformat *pfmt =1172		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);1173	struct device *dev = &av->isys->adev->auxdev.dev;1174	struct v4l2_mbus_frame_desc_entry entry;1175	struct v4l2_subdev_route *route = NULL;1176	struct v4l2_subdev_route *r;1177	struct v4l2_subdev_state *state;1178	struct ipu6_isys_subdev *asd;1179	struct v4l2_subdev *remote_sd;1180	struct media_pipeline *pipeline;1181	struct media_pad *source_pad, *remote_pad;1182	int ret = -EINVAL;1183 1184	*nr_queues = 0;1185 1186	remote_pad = media_pad_remote_pad_unique(&av->pad);1187	if (IS_ERR(remote_pad)) {1188		dev_dbg(dev, "failed to get remote pad\n");1189		return PTR_ERR(remote_pad);1190	}1191 1192	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);1193	asd = to_ipu6_isys_subdev(remote_sd);1194	source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]);1195	if (!source_pad) {1196		dev_dbg(dev, "No external source entity\n");1197		return -ENODEV;1198	}1199 1200	*source_entity = source_pad->entity;1201 1202	/* Find the root */1203	state = v4l2_subdev_lock_and_get_active_state(remote_sd);1204	for_each_active_route(&state->routing, r) {1205		(*nr_queues)++;1206 1207		if (r->source_pad == remote_pad->index)1208			route = r;1209	}1210 1211	if (!route) {1212		v4l2_subdev_unlock_state(state);1213		dev_dbg(dev, "Failed to find route\n");1214		return -ENODEV;1215	}1216	av->source_stream = route->sink_stream;1217	v4l2_subdev_unlock_state(state);1218 1219	ret = ipu6_isys_csi2_get_remote_desc(av->source_stream,1220					     to_ipu6_isys_csi2(asd),1221					     *source_entity, &entry);1222	if (ret == -ENOIOCTLCMD) {1223		av->vc = 0;1224		av->dt = ipu6_isys_mbus_code_to_mipi(pfmt->code);1225	} else if (!ret) {1226		dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",1227			entry.stream, entry.length, entry.bus.csi2.vc,1228			entry.bus.csi2.dt);1229 1230		av->vc = entry.bus.csi2.vc;1231		av->dt = entry.bus.csi2.dt;1232	} else {1233		dev_err(dev, "failed to get remote frame desc\n");1234		return ret;1235	}1236 1237	pipeline = media_entity_pipeline(&av->vdev.entity);1238	if (!pipeline)1239		ret = video_device_pipeline_alloc_start(&av->vdev);1240	else1241		ret = video_device_pipeline_start(&av->vdev, pipeline);1242	if (ret < 0) {1243		dev_dbg(dev, "media pipeline start failed\n");1244		return ret;1245	}1246 1247	av->stream = ipu6_isys_get_stream(av, asd);1248	if (!av->stream) {1249		video_device_pipeline_stop(&av->vdev);1250		dev_err(dev, "no available stream for firmware\n");1251		return -EINVAL;1252	}1253 1254	return 0;1255}1256 1257/*1258 * Do everything that's needed to initialise things related to video1259 * buffer queue, video node, and the related media entity. The caller1260 * is expected to assign isys field and set the name of the video1261 * device.1262 */1263int ipu6_isys_video_init(struct ipu6_isys_video *av)1264{1265	struct v4l2_format format = {1266		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,1267		.fmt.pix = {1268			.width = 1920,1269			.height = 1080,1270		},1271	};1272	struct v4l2_format format_meta = {1273		.type = V4L2_BUF_TYPE_META_CAPTURE,1274		.fmt.meta = {1275			.width = 1920,1276			.height = 4,1277		},1278	};1279	int ret;1280 1281	mutex_init(&av->mutex);1282	av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC |1283			       V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE;1284	av->vdev.vfl_dir = VFL_DIR_RX;1285 1286	ret = ipu6_isys_queue_init(&av->aq);1287	if (ret)1288		goto out_free_watermark;1289 1290	av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;1291	ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad);1292	if (ret)1293		goto out_vb2_queue_release;1294 1295	av->vdev.entity.ops = &entity_ops;1296	av->vdev.release = video_device_release_empty;1297	av->vdev.fops = &isys_fops;1298	av->vdev.v4l2_dev = &av->isys->v4l2_dev;1299	if (!av->vdev.ioctl_ops)1300		av->vdev.ioctl_ops = &ipu6_v4l2_ioctl_ops;1301	av->vdev.queue = &av->aq.vbq;1302	av->vdev.lock = &av->mutex;1303 1304	__ipu6_isys_vidioc_try_fmt_vid_cap(av, &format);1305	av->pix_fmt = format.fmt.pix;1306	__ipu6_isys_vidioc_try_fmt_meta_cap(av, &format_meta);1307	av->meta_fmt = format_meta.fmt.meta;1308 1309	set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags);1310	video_set_drvdata(&av->vdev, av);1311 1312	ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1);1313	if (ret)1314		goto out_media_entity_cleanup;1315 1316	return ret;1317 1318out_media_entity_cleanup:1319	vb2_video_unregister_device(&av->vdev);1320	media_entity_cleanup(&av->vdev.entity);1321 1322out_vb2_queue_release:1323	vb2_queue_release(&av->aq.vbq);1324 1325out_free_watermark:1326	mutex_destroy(&av->mutex);1327 1328	return ret;1329}1330 1331void ipu6_isys_video_cleanup(struct ipu6_isys_video *av)1332{1333	vb2_video_unregister_device(&av->vdev);1334	media_entity_cleanup(&av->vdev.entity);1335	mutex_destroy(&av->mutex);1336}1337 1338u32 ipu6_isys_get_format(struct ipu6_isys_video *av)1339{1340	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)1341		return av->pix_fmt.pixelformat;1342 1343	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)1344		return av->meta_fmt.dataformat;1345 1346	return 0;1347}1348 1349u32 ipu6_isys_get_data_size(struct ipu6_isys_video *av)1350{1351	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)1352		return av->pix_fmt.sizeimage;1353 1354	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)1355		return av->meta_fmt.buffersize;1356 1357	return 0;1358}1359 1360u32 ipu6_isys_get_bytes_per_line(struct ipu6_isys_video *av)1361{1362	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)1363		return av->pix_fmt.bytesperline;1364 1365	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)1366		return av->meta_fmt.bytesperline;1367 1368	return 0;1369}1370 1371u32 ipu6_isys_get_frame_width(struct ipu6_isys_video *av)1372{1373	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)1374		return av->pix_fmt.width;1375 1376	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)1377		return av->meta_fmt.width;1378 1379	return 0;1380}1381 1382u32 ipu6_isys_get_frame_height(struct ipu6_isys_video *av)1383{1384	if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)1385		return av->pix_fmt.height;1386 1387	if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)1388		return av->meta_fmt.height;1389 1390	return 0;1391}1392