File Index
Files and directories
Sign in
FILE

ipu6-isys-video.c

File preview with syntax highlighting.

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