xref: /linux/drivers/media/pci/intel/ipu6/ipu6-isys-video.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
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 
39 const 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 
video_open(struct file * file)98 static 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 
115 const struct ipu6_isys_pixelformat *
ipu6_isys_get_isys_format(u32 pixelformat,u32 type)116 ipu6_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 
ipu6_isys_vidioc_querycap(struct file * file,void * fh,struct v4l2_capability * cap)142 static 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 
ipu6_isys_vidioc_enum_fmt(struct file * file,void * fh,struct v4l2_fmtdesc * f)153 static 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 
ipu6_isys_vidioc_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)182 static 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 
ipu6_isys_vidioc_g_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * f)208 static 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 
ipu6_isys_vidioc_g_fmt_meta_cap(struct file * file,void * fh,struct v4l2_format * f)218 static 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 
ipu6_isys_try_fmt_cap(struct ipu6_isys_video * av,u32 type,u32 * format,u32 * width,u32 * height,u32 * bytesperline,u32 * sizeimage)228 static 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, 64);
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 
__ipu6_isys_vidioc_try_fmt_vid_cap(struct ipu6_isys_video * av,struct v4l2_format * f)260 static 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 
ipu6_isys_vidioc_try_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * f)274 static 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 
__ipu6_isys_vidioc_try_fmt_meta_cap(struct ipu6_isys_video * av,struct v4l2_format * f)287 static 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 
ipu6_isys_vidioc_try_fmt_meta_cap(struct file * file,void * fh,struct v4l2_format * f)298 static 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 
ipu6_isys_vidioc_s_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * f)308 static 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 
ipu6_isys_vidioc_s_fmt_meta_cap(struct file * file,void * fh,struct v4l2_format * f)319 static 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 
ipu6_isys_vidioc_reqbufs(struct file * file,void * priv,struct v4l2_requestbuffers * p)333 static 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 
ipu6_isys_vidioc_create_bufs(struct file * file,void * priv,struct v4l2_create_buffers * p)349 static 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 
link_validate(struct media_link * link)365 static 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;
415 unlock:
416 	v4l2_subdev_unlock_state(s_state);
417 
418 	return ret;
419 }
420 
get_stream_opened(struct ipu6_isys_video * av)421 static 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 
put_stream_opened(struct ipu6_isys_video * av)430 static 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 
ipu6_isys_fw_pin_cfg(struct ipu6_isys_video * av,struct ipu6_fw_isys_stream_cfg_data_abi * cfg)439 static 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_queue[output_pins] = aq;
490 
491 	output_pin = &cfg->output_pins[output_pins];
492 	output_pin->input_pin_id = input_pins;
493 	output_pin->output_res.width = ipu6_isys_get_frame_width(av);
494 	output_pin->output_res.height = ipu6_isys_get_frame_height(av);
495 
496 	output_pin->stride = ipu6_isys_get_bytes_per_line(av);
497 	if (pfmt->bpp != pfmt->bpp_packed)
498 		output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC;
499 	else
500 		output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI;
501 	output_pin->ft = pfmt->css_pixelformat;
502 	output_pin->send_irq = 1;
503 	memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets));
504 	output_pin->s2m_pixel_soc_pixel_remapping =
505 		S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
506 	output_pin->csi_be_soc_pixel_remapping =
507 		CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
508 
509 	output_pin->snoopable = true;
510 	output_pin->error_handling_enable = false;
511 	output_pin->sensor_type = isys->sensor_type++;
512 	if (isys->sensor_type > isys->pdata->ipdata->sensor_type_end)
513 		isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
514 
515 	return 0;
516 }
517 
start_stream_firmware(struct ipu6_isys_video * av,struct ipu6_isys_buffer_list * bl)518 static int start_stream_firmware(struct ipu6_isys_video *av,
519 				 struct ipu6_isys_buffer_list *bl)
520 {
521 	struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
522 	struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
523 	struct ipu6_isys_stream *stream = av->stream;
524 	struct device *dev = &av->isys->adev->auxdev.dev;
525 	struct isys_fw_msgs *msg = NULL;
526 	struct ipu6_isys_queue *aq;
527 	int ret, retout, tout;
528 	u16 send_type;
529 
530 	msg = ipu6_get_fw_msg_buf(stream);
531 	if (!msg)
532 		return -ENOMEM;
533 
534 	stream_cfg = &msg->fw_msg.stream;
535 	stream_cfg->src = stream->stream_source;
536 	stream_cfg->vc = stream->vc;
537 	stream_cfg->isl_use = 0;
538 	stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL;
539 
540 	list_for_each_entry(aq, &stream->queues, node) {
541 		struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
542 
543 		ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
544 		if (ret < 0) {
545 			ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
546 			return ret;
547 		}
548 	}
549 
550 	ipu6_fw_isys_dump_stream_cfg(dev, stream_cfg);
551 
552 	stream->nr_output_pins = stream_cfg->nof_output_pins;
553 
554 	reinit_completion(&stream->stream_open_completion);
555 
556 	ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
557 				       stream_cfg, msg->dma_addr,
558 				       sizeof(*stream_cfg),
559 				       IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
560 	if (ret < 0) {
561 		dev_err(dev, "can't open stream (%d)\n", ret);
562 		ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
563 		return ret;
564 	}
565 
566 	get_stream_opened(av);
567 
568 	tout = wait_for_completion_timeout(&stream->stream_open_completion,
569 					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
570 
571 	ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
572 
573 	if (!tout) {
574 		dev_err(dev, "stream open time out\n");
575 		ret = -ETIMEDOUT;
576 		goto out_put_stream_opened;
577 	}
578 	if (stream->error) {
579 		dev_err(dev, "stream open error: %d\n", stream->error);
580 		ret = -EIO;
581 		goto out_put_stream_opened;
582 	}
583 	dev_dbg(dev, "start stream: open complete\n");
584 
585 	if (bl) {
586 		msg = ipu6_get_fw_msg_buf(stream);
587 		if (!msg) {
588 			ret = -ENOMEM;
589 			goto out_put_stream_opened;
590 		}
591 		buf = &msg->fw_msg.frame;
592 		ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
593 		ipu6_isys_buffer_list_queue(bl,
594 					    IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
595 	}
596 
597 	reinit_completion(&stream->stream_start_completion);
598 
599 	if (bl) {
600 		send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
601 		ipu6_fw_isys_dump_frame_buff_set(dev, buf,
602 						 stream_cfg->nof_output_pins);
603 		ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
604 					       buf, msg->dma_addr,
605 					       sizeof(*buf), send_type);
606 	} else {
607 		send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START;
608 		ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
609 					      send_type);
610 	}
611 
612 	if (ret < 0) {
613 		dev_err(dev, "can't start streaming (%d)\n", ret);
614 		goto out_stream_close;
615 	}
616 
617 	tout = wait_for_completion_timeout(&stream->stream_start_completion,
618 					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
619 	if (!tout) {
620 		dev_err(dev, "stream start time out\n");
621 		ret = -ETIMEDOUT;
622 		goto out_stream_close;
623 	}
624 	if (stream->error) {
625 		dev_err(dev, "stream start error: %d\n", stream->error);
626 		ret = -EIO;
627 		goto out_stream_close;
628 	}
629 	dev_dbg(dev, "start stream: complete\n");
630 
631 	return 0;
632 
633 out_stream_close:
634 	reinit_completion(&stream->stream_close_completion);
635 
636 	retout = ipu6_fw_isys_simple_cmd(av->isys,
637 					 stream->stream_handle,
638 					 IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
639 	if (retout < 0) {
640 		dev_dbg(dev, "can't close stream (%d)\n", retout);
641 		goto out_put_stream_opened;
642 	}
643 
644 	tout = wait_for_completion_timeout(&stream->stream_close_completion,
645 					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
646 	if (!tout)
647 		dev_err(dev, "stream close time out\n");
648 	else if (stream->error)
649 		dev_err(dev, "stream close error: %d\n", stream->error);
650 	else
651 		dev_dbg(dev, "stream close complete\n");
652 
653 out_put_stream_opened:
654 	put_stream_opened(av);
655 
656 	return ret;
657 }
658 
stop_streaming_firmware(struct ipu6_isys_video * av)659 static void stop_streaming_firmware(struct ipu6_isys_video *av)
660 {
661 	struct device *dev = &av->isys->adev->auxdev.dev;
662 	struct ipu6_isys_stream *stream = av->stream;
663 	int ret, tout;
664 
665 	reinit_completion(&stream->stream_stop_completion);
666 
667 	ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
668 				      IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
669 
670 	if (ret < 0) {
671 		dev_err(dev, "can't stop stream (%d)\n", ret);
672 		return;
673 	}
674 
675 	tout = wait_for_completion_timeout(&stream->stream_stop_completion,
676 					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
677 	if (!tout)
678 		dev_warn(dev, "stream stop time out\n");
679 	else if (stream->error)
680 		dev_warn(dev, "stream stop error: %d\n", stream->error);
681 	else
682 		dev_dbg(dev, "stop stream: complete\n");
683 }
684 
close_streaming_firmware(struct ipu6_isys_video * av)685 static void close_streaming_firmware(struct ipu6_isys_video *av)
686 {
687 	struct ipu6_isys_stream *stream = av->stream;
688 	struct device *dev = &av->isys->adev->auxdev.dev;
689 	int ret, tout;
690 
691 	reinit_completion(&stream->stream_close_completion);
692 
693 	ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
694 				      IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
695 	if (ret < 0) {
696 		dev_err(dev, "can't close stream (%d)\n", ret);
697 		return;
698 	}
699 
700 	tout = wait_for_completion_timeout(&stream->stream_close_completion,
701 					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
702 	if (!tout)
703 		dev_warn(dev, "stream close time out\n");
704 	else if (stream->error)
705 		dev_warn(dev, "stream close error: %d\n", stream->error);
706 	else
707 		dev_dbg(dev, "close stream: complete\n");
708 
709 	put_stream_opened(av);
710 }
711 
ipu6_isys_video_prepare_stream(struct ipu6_isys_video * av,struct media_entity * source_entity,int nr_queues)712 int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
713 				   struct media_entity *source_entity,
714 				   int nr_queues)
715 {
716 	struct ipu6_isys_stream *stream = av->stream;
717 	struct ipu6_isys_csi2 *csi2;
718 
719 	if (WARN_ON(stream->nr_streaming))
720 		return -EINVAL;
721 
722 	stream->nr_queues = nr_queues;
723 	atomic_set(&stream->sequence, 0);
724 
725 	stream->seq_index = 0;
726 	memset(stream->seq, 0, sizeof(stream->seq));
727 
728 	if (WARN_ON(!list_empty(&stream->queues)))
729 		return -EINVAL;
730 
731 	stream->stream_source = stream->asd->source;
732 	csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
733 	csi2->receiver_errors = 0;
734 	stream->source_entity = source_entity;
735 
736 	dev_dbg(&av->isys->adev->auxdev.dev,
737 		"prepare stream: external entity %s\n",
738 		stream->source_entity->name);
739 
740 	return 0;
741 }
742 
ipu6_isys_configure_stream_watermark(struct ipu6_isys_video * av,bool state)743 void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
744 					  bool state)
745 {
746 	struct ipu6_isys *isys = av->isys;
747 	struct ipu6_isys_csi2 *csi2 = NULL;
748 	struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
749 	struct device *dev = &isys->adev->auxdev.dev;
750 	struct v4l2_mbus_framefmt format;
751 	struct v4l2_subdev *esd;
752 	struct v4l2_control hb = { .id = V4L2_CID_HBLANK, .value = 0 };
753 	unsigned int bpp, lanes;
754 	s64 link_freq = 0;
755 	u64 pixel_rate = 0;
756 	int ret;
757 
758 	if (!state)
759 		return;
760 
761 	esd = media_entity_to_v4l2_subdev(av->stream->source_entity);
762 
763 	av->watermark.width = ipu6_isys_get_frame_width(av);
764 	av->watermark.height = ipu6_isys_get_frame_height(av);
765 	av->watermark.sram_gran_shift = isys->pdata->ipdata->sram_gran_shift;
766 	av->watermark.sram_gran_size = isys->pdata->ipdata->sram_gran_size;
767 
768 	ret = v4l2_g_ctrl(esd->ctrl_handler, &hb);
769 	if (!ret && hb.value >= 0)
770 		av->watermark.hblank = hb.value;
771 	else
772 		av->watermark.hblank = 0;
773 
774 	csi2 = ipu6_isys_subdev_to_csi2(av->stream->asd);
775 	link_freq = ipu6_isys_csi2_get_link_freq(csi2);
776 	if (link_freq > 0) {
777 		lanes = csi2->nlanes;
778 		ret = ipu6_isys_get_stream_pad_fmt(&csi2->asd.sd, 0,
779 						   av->source_stream, &format);
780 		if (!ret) {
781 			bpp = ipu6_isys_mbus_code_to_bpp(format.code);
782 			pixel_rate = mul_u64_u32_div(link_freq, lanes * 2, bpp);
783 		}
784 	}
785 
786 	av->watermark.pixel_rate = pixel_rate;
787 
788 	if (!pixel_rate) {
789 		mutex_lock(&iwake_watermark->mutex);
790 		iwake_watermark->force_iwake_disable = true;
791 		mutex_unlock(&iwake_watermark->mutex);
792 		dev_warn(dev, "unexpected pixel_rate from %s, disable iwake.\n",
793 			 av->stream->source_entity->name);
794 	}
795 }
796 
calculate_stream_datarate(struct ipu6_isys_video * av)797 static void calculate_stream_datarate(struct ipu6_isys_video *av)
798 {
799 	struct video_stream_watermark *watermark = &av->watermark;
800 	const struct ipu6_isys_pixelformat *pfmt =
801 		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
802 	u32 pages_per_line, pb_bytes_per_line, pixels_per_line, bytes_per_line;
803 	u64 line_time_ns, stream_data_rate;
804 	u16 shift, size;
805 
806 	shift = watermark->sram_gran_shift;
807 	size = watermark->sram_gran_size;
808 
809 	pixels_per_line = watermark->width + watermark->hblank;
810 	line_time_ns =  div_u64(pixels_per_line * NSEC_PER_SEC,
811 				watermark->pixel_rate);
812 	bytes_per_line = watermark->width * pfmt->bpp / 8;
813 	pages_per_line = DIV_ROUND_UP(bytes_per_line, size);
814 	pb_bytes_per_line = pages_per_line << shift;
815 	stream_data_rate = div64_u64(pb_bytes_per_line * 1000, line_time_ns);
816 
817 	watermark->stream_data_rate = stream_data_rate;
818 }
819 
ipu6_isys_update_stream_watermark(struct ipu6_isys_video * av,bool state)820 void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state)
821 {
822 	struct isys_iwake_watermark *iwake_watermark =
823 		&av->isys->iwake_watermark;
824 
825 	if (!av->watermark.pixel_rate)
826 		return;
827 
828 	if (state) {
829 		calculate_stream_datarate(av);
830 		mutex_lock(&iwake_watermark->mutex);
831 		list_add(&av->watermark.stream_node,
832 			 &iwake_watermark->video_list);
833 		mutex_unlock(&iwake_watermark->mutex);
834 	} else {
835 		av->watermark.stream_data_rate = 0;
836 		mutex_lock(&iwake_watermark->mutex);
837 		list_del(&av->watermark.stream_node);
838 		mutex_unlock(&iwake_watermark->mutex);
839 	}
840 
841 	update_watermark_setting(av->isys);
842 }
843 
ipu6_isys_put_stream(struct ipu6_isys_stream * stream)844 void ipu6_isys_put_stream(struct ipu6_isys_stream *stream)
845 {
846 	struct device *dev;
847 	unsigned int i;
848 	unsigned long flags;
849 
850 	if (!stream) {
851 		pr_err("ipu6-isys: no available stream\n");
852 		return;
853 	}
854 
855 	dev = &stream->isys->adev->auxdev.dev;
856 
857 	spin_lock_irqsave(&stream->isys->streams_lock, flags);
858 	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
859 		if (&stream->isys->streams[i] == stream) {
860 			if (stream->isys->streams_ref_count[i] > 0)
861 				stream->isys->streams_ref_count[i]--;
862 			else
863 				dev_warn(dev, "invalid stream %d\n", i);
864 
865 			break;
866 		}
867 	}
868 	spin_unlock_irqrestore(&stream->isys->streams_lock, flags);
869 }
870 
871 static struct ipu6_isys_stream *
ipu6_isys_get_stream(struct ipu6_isys_video * av,struct ipu6_isys_subdev * asd)872 ipu6_isys_get_stream(struct ipu6_isys_video *av, struct ipu6_isys_subdev *asd)
873 {
874 	struct ipu6_isys_stream *stream = NULL;
875 	struct ipu6_isys *isys = av->isys;
876 	unsigned long flags;
877 	unsigned int i;
878 	u8 vc = av->vc;
879 
880 	if (!isys)
881 		return NULL;
882 
883 	spin_lock_irqsave(&isys->streams_lock, flags);
884 	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
885 		if (isys->streams_ref_count[i] && isys->streams[i].vc == vc &&
886 		    isys->streams[i].asd == asd) {
887 			isys->streams_ref_count[i]++;
888 			stream = &isys->streams[i];
889 			break;
890 		}
891 	}
892 
893 	if (!stream) {
894 		for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
895 			if (!isys->streams_ref_count[i]) {
896 				isys->streams_ref_count[i]++;
897 				stream = &isys->streams[i];
898 				stream->vc = vc;
899 				stream->asd = asd;
900 				break;
901 			}
902 		}
903 	}
904 	spin_unlock_irqrestore(&isys->streams_lock, flags);
905 
906 	return stream;
907 }
908 
909 struct ipu6_isys_stream *
ipu6_isys_query_stream_by_handle(struct ipu6_isys * isys,u8 stream_handle)910 ipu6_isys_query_stream_by_handle(struct ipu6_isys *isys, u8 stream_handle)
911 {
912 	unsigned long flags;
913 	struct ipu6_isys_stream *stream = NULL;
914 
915 	if (!isys)
916 		return NULL;
917 
918 	if (stream_handle >= IPU6_ISYS_MAX_STREAMS) {
919 		dev_err(&isys->adev->auxdev.dev,
920 			"stream_handle %d is invalid\n", stream_handle);
921 		return NULL;
922 	}
923 
924 	spin_lock_irqsave(&isys->streams_lock, flags);
925 	if (isys->streams_ref_count[stream_handle] > 0) {
926 		isys->streams_ref_count[stream_handle]++;
927 		stream = &isys->streams[stream_handle];
928 	}
929 	spin_unlock_irqrestore(&isys->streams_lock, flags);
930 
931 	return stream;
932 }
933 
934 struct ipu6_isys_stream *
ipu6_isys_query_stream_by_source(struct ipu6_isys * isys,int source,u8 vc)935 ipu6_isys_query_stream_by_source(struct ipu6_isys *isys, int source, u8 vc)
936 {
937 	struct ipu6_isys_stream *stream = NULL;
938 	unsigned long flags;
939 	unsigned int i;
940 
941 	if (!isys)
942 		return NULL;
943 
944 	if (source < 0) {
945 		dev_err(&isys->adev->auxdev.dev,
946 			"query stream with invalid port number\n");
947 		return NULL;
948 	}
949 
950 	spin_lock_irqsave(&isys->streams_lock, flags);
951 	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
952 		if (!isys->streams_ref_count[i])
953 			continue;
954 
955 		if (isys->streams[i].stream_source == source &&
956 		    isys->streams[i].vc == vc) {
957 			stream = &isys->streams[i];
958 			isys->streams_ref_count[i]++;
959 			break;
960 		}
961 	}
962 	spin_unlock_irqrestore(&isys->streams_lock, flags);
963 
964 	return stream;
965 }
966 
get_stream_mask_by_pipeline(struct ipu6_isys_video * __av)967 static u64 get_stream_mask_by_pipeline(struct ipu6_isys_video *__av)
968 {
969 	struct media_pipeline *pipeline =
970 		media_entity_pipeline(&__av->vdev.entity);
971 	unsigned int i;
972 	u64 stream_mask = 0;
973 
974 	for (i = 0; i < NR_OF_CSI2_SRC_PADS; i++) {
975 		struct ipu6_isys_video *av = &__av->csi2->av[i];
976 
977 		if (pipeline == media_entity_pipeline(&av->vdev.entity))
978 			stream_mask |= BIT_ULL(av->source_stream);
979 	}
980 
981 	return stream_mask;
982 }
983 
ipu6_isys_video_set_streaming(struct ipu6_isys_video * av,int state,struct ipu6_isys_buffer_list * bl)984 int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
985 				  struct ipu6_isys_buffer_list *bl)
986 {
987 	struct v4l2_subdev_krouting *routing;
988 	struct ipu6_isys_stream *stream = av->stream;
989 	struct v4l2_subdev_state *subdev_state;
990 	struct device *dev = &av->isys->adev->auxdev.dev;
991 	struct v4l2_subdev *sd;
992 	struct media_pad *r_pad;
993 	u32 sink_pad, sink_stream;
994 	u64 r_stream;
995 	u64 stream_mask = 0;
996 	int ret = 0;
997 
998 	dev_dbg(dev, "set stream: %d\n", state);
999 
1000 	if (WARN(!stream->source_entity, "No source entity for stream\n"))
1001 		return -ENODEV;
1002 
1003 	sd = &stream->asd->sd;
1004 	r_pad = media_pad_remote_pad_first(&av->pad);
1005 	r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
1006 
1007 	subdev_state = v4l2_subdev_lock_and_get_active_state(sd);
1008 	routing = &subdev_state->routing;
1009 	ret = v4l2_subdev_routing_find_opposite_end(routing, r_pad->index,
1010 						    r_stream, &sink_pad,
1011 						    &sink_stream);
1012 	v4l2_subdev_unlock_state(subdev_state);
1013 	if (ret)
1014 		return ret;
1015 
1016 	stream_mask = get_stream_mask_by_pipeline(av);
1017 	if (!state) {
1018 		stop_streaming_firmware(av);
1019 
1020 		/* stop sub-device which connects with video */
1021 		dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n",
1022 			sd->name, r_pad->index, stream_mask);
1023 		ret = v4l2_subdev_disable_streams(sd, r_pad->index,
1024 						  stream_mask);
1025 		if (ret) {
1026 			dev_err(dev, "stream off %s failed with %d\n", sd->name,
1027 				ret);
1028 			return ret;
1029 		}
1030 		close_streaming_firmware(av);
1031 	} else {
1032 		ret = start_stream_firmware(av, bl);
1033 		if (ret) {
1034 			dev_err(dev, "start stream of firmware failed\n");
1035 			return ret;
1036 		}
1037 
1038 		/* start sub-device which connects with video */
1039 		dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name,
1040 			r_pad->index, stream_mask);
1041 		ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask);
1042 		if (ret) {
1043 			dev_err(dev, "stream on %s failed with %d\n", sd->name,
1044 				ret);
1045 			goto out_media_entity_stop_streaming_firmware;
1046 		}
1047 	}
1048 
1049 	av->streaming = state;
1050 
1051 	return 0;
1052 
1053 out_media_entity_stop_streaming_firmware:
1054 	stop_streaming_firmware(av);
1055 
1056 	return ret;
1057 }
1058 
1059 static const struct v4l2_ioctl_ops ipu6_v4l2_ioctl_ops = {
1060 	.vidioc_querycap = ipu6_isys_vidioc_querycap,
1061 	.vidioc_enum_fmt_vid_cap = ipu6_isys_vidioc_enum_fmt,
1062 	.vidioc_enum_fmt_meta_cap = ipu6_isys_vidioc_enum_fmt,
1063 	.vidioc_enum_framesizes = ipu6_isys_vidioc_enum_framesizes,
1064 	.vidioc_g_fmt_vid_cap = ipu6_isys_vidioc_g_fmt_vid_cap,
1065 	.vidioc_s_fmt_vid_cap = ipu6_isys_vidioc_s_fmt_vid_cap,
1066 	.vidioc_try_fmt_vid_cap = ipu6_isys_vidioc_try_fmt_vid_cap,
1067 	.vidioc_g_fmt_meta_cap = ipu6_isys_vidioc_g_fmt_meta_cap,
1068 	.vidioc_s_fmt_meta_cap = ipu6_isys_vidioc_s_fmt_meta_cap,
1069 	.vidioc_try_fmt_meta_cap = ipu6_isys_vidioc_try_fmt_meta_cap,
1070 	.vidioc_reqbufs = ipu6_isys_vidioc_reqbufs,
1071 	.vidioc_create_bufs = ipu6_isys_vidioc_create_bufs,
1072 	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1073 	.vidioc_querybuf = vb2_ioctl_querybuf,
1074 	.vidioc_qbuf = vb2_ioctl_qbuf,
1075 	.vidioc_dqbuf = vb2_ioctl_dqbuf,
1076 	.vidioc_streamon = vb2_ioctl_streamon,
1077 	.vidioc_streamoff = vb2_ioctl_streamoff,
1078 	.vidioc_expbuf = vb2_ioctl_expbuf,
1079 };
1080 
1081 static const struct media_entity_operations entity_ops = {
1082 	.link_validate = link_validate,
1083 };
1084 
1085 static const struct v4l2_file_operations isys_fops = {
1086 	.owner = THIS_MODULE,
1087 	.poll = vb2_fop_poll,
1088 	.unlocked_ioctl = video_ioctl2,
1089 	.mmap = vb2_fop_mmap,
1090 	.open = video_open,
1091 	.release = vb2_fop_release,
1092 };
1093 
ipu6_isys_fw_open(struct ipu6_isys * isys)1094 int ipu6_isys_fw_open(struct ipu6_isys *isys)
1095 {
1096 	struct ipu6_bus_device *adev = isys->adev;
1097 	const struct ipu6_isys_internal_pdata *ipdata = isys->pdata->ipdata;
1098 	int ret;
1099 
1100 	ret = pm_runtime_resume_and_get(&adev->auxdev.dev);
1101 	if (ret < 0)
1102 		return ret;
1103 
1104 	mutex_lock(&isys->mutex);
1105 
1106 	if (isys->ref_count++)
1107 		goto unlock;
1108 
1109 	ipu6_configure_spc(adev->isp, &ipdata->hw_variant,
1110 			   IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX, isys->pdata->base,
1111 			   adev->pkg_dir, adev->pkg_dir_dma_addr);
1112 
1113 	/*
1114 	 * Buffers could have been left to wrong queue at last closure.
1115 	 * Move them now back to empty buffer queue.
1116 	 */
1117 	ipu6_cleanup_fw_msg_bufs(isys);
1118 
1119 	if (isys->fwcom) {
1120 		/*
1121 		 * Something went wrong in previous shutdown. As we are now
1122 		 * restarting isys we can safely delete old context.
1123 		 */
1124 		dev_warn(&adev->auxdev.dev, "clearing old context\n");
1125 		ipu6_fw_isys_cleanup(isys);
1126 	}
1127 
1128 	ret = ipu6_fw_isys_init(isys, ipdata->num_parallel_streams);
1129 	if (ret < 0)
1130 		goto out;
1131 
1132 unlock:
1133 	mutex_unlock(&isys->mutex);
1134 
1135 	return 0;
1136 
1137 out:
1138 	isys->ref_count--;
1139 	mutex_unlock(&isys->mutex);
1140 	pm_runtime_put(&adev->auxdev.dev);
1141 
1142 	return ret;
1143 }
1144 
ipu6_isys_fw_close(struct ipu6_isys * isys)1145 void ipu6_isys_fw_close(struct ipu6_isys *isys)
1146 {
1147 	mutex_lock(&isys->mutex);
1148 
1149 	isys->ref_count--;
1150 	if (!isys->ref_count) {
1151 		ipu6_fw_isys_close(isys);
1152 		if (isys->fwcom) {
1153 			isys->need_reset = true;
1154 			dev_warn(&isys->adev->auxdev.dev,
1155 				 "failed to close fw isys\n");
1156 		}
1157 	}
1158 
1159 	mutex_unlock(&isys->mutex);
1160 
1161 	if (isys->need_reset)
1162 		pm_runtime_put_sync(&isys->adev->auxdev.dev);
1163 	else
1164 		pm_runtime_put(&isys->adev->auxdev.dev);
1165 }
1166 
ipu6_isys_setup_video(struct ipu6_isys_video * av,struct media_entity ** source_entity,int * nr_queues)1167 int ipu6_isys_setup_video(struct ipu6_isys_video *av,
1168 			  struct media_entity **source_entity, int *nr_queues)
1169 {
1170 	const struct ipu6_isys_pixelformat *pfmt =
1171 		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
1172 	struct device *dev = &av->isys->adev->auxdev.dev;
1173 	struct v4l2_mbus_frame_desc_entry entry;
1174 	struct v4l2_subdev_route *route = NULL;
1175 	struct v4l2_subdev_route *r;
1176 	struct v4l2_subdev_state *state;
1177 	struct ipu6_isys_subdev *asd;
1178 	struct v4l2_subdev *remote_sd;
1179 	struct media_pipeline *pipeline;
1180 	struct media_pad *source_pad, *remote_pad;
1181 	int ret = -EINVAL;
1182 
1183 	*nr_queues = 0;
1184 
1185 	remote_pad = media_pad_remote_pad_unique(&av->pad);
1186 	if (IS_ERR(remote_pad)) {
1187 		dev_dbg(dev, "failed to get remote pad\n");
1188 		return PTR_ERR(remote_pad);
1189 	}
1190 
1191 	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
1192 	asd = to_ipu6_isys_subdev(remote_sd);
1193 	source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]);
1194 	if (!source_pad) {
1195 		dev_dbg(dev, "No external source entity\n");
1196 		return -ENODEV;
1197 	}
1198 
1199 	*source_entity = source_pad->entity;
1200 
1201 	/* Find the root */
1202 	state = v4l2_subdev_lock_and_get_active_state(remote_sd);
1203 	for_each_active_route(&state->routing, r) {
1204 		(*nr_queues)++;
1205 
1206 		if (r->source_pad == remote_pad->index)
1207 			route = r;
1208 	}
1209 
1210 	if (!route) {
1211 		v4l2_subdev_unlock_state(state);
1212 		dev_dbg(dev, "Failed to find route\n");
1213 		return -ENODEV;
1214 	}
1215 	av->source_stream = route->sink_stream;
1216 	v4l2_subdev_unlock_state(state);
1217 
1218 	ret = ipu6_isys_csi2_get_remote_desc(av->source_stream,
1219 					     to_ipu6_isys_csi2(asd),
1220 					     *source_entity, &entry);
1221 	if (ret == -ENOIOCTLCMD) {
1222 		av->vc = 0;
1223 		av->dt = ipu6_isys_mbus_code_to_mipi(pfmt->code);
1224 	} else if (!ret) {
1225 		dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
1226 			entry.stream, entry.length, entry.bus.csi2.vc,
1227 			entry.bus.csi2.dt);
1228 
1229 		av->vc = entry.bus.csi2.vc;
1230 		av->dt = entry.bus.csi2.dt;
1231 	} else {
1232 		dev_err(dev, "failed to get remote frame desc\n");
1233 		return ret;
1234 	}
1235 
1236 	pipeline = media_entity_pipeline(&av->vdev.entity);
1237 	if (!pipeline)
1238 		ret = video_device_pipeline_alloc_start(&av->vdev);
1239 	else
1240 		ret = video_device_pipeline_start(&av->vdev, pipeline);
1241 	if (ret < 0) {
1242 		dev_dbg(dev, "media pipeline start failed\n");
1243 		return ret;
1244 	}
1245 
1246 	av->stream = ipu6_isys_get_stream(av, asd);
1247 	if (!av->stream) {
1248 		video_device_pipeline_stop(&av->vdev);
1249 		dev_err(dev, "no available stream for firmware\n");
1250 		return -EINVAL;
1251 	}
1252 
1253 	return 0;
1254 }
1255 
1256 /*
1257  * Do everything that's needed to initialise things related to video
1258  * buffer queue, video node, and the related media entity. The caller
1259  * is expected to assign isys field and set the name of the video
1260  * device.
1261  */
ipu6_isys_video_init(struct ipu6_isys_video * av)1262 int ipu6_isys_video_init(struct ipu6_isys_video *av)
1263 {
1264 	struct v4l2_format format = {
1265 		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
1266 		.fmt.pix = {
1267 			.width = 1920,
1268 			.height = 1080,
1269 		},
1270 	};
1271 	struct v4l2_format format_meta = {
1272 		.type = V4L2_BUF_TYPE_META_CAPTURE,
1273 		.fmt.meta = {
1274 			.width = 1920,
1275 			.height = 4,
1276 		},
1277 	};
1278 	int ret;
1279 
1280 	mutex_init(&av->mutex);
1281 	av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC |
1282 			       V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE;
1283 	av->vdev.vfl_dir = VFL_DIR_RX;
1284 
1285 	ret = ipu6_isys_queue_init(&av->aq);
1286 	if (ret)
1287 		goto out_free_watermark;
1288 
1289 	av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
1290 	ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad);
1291 	if (ret)
1292 		goto out_vb2_queue_release;
1293 
1294 	av->vdev.entity.ops = &entity_ops;
1295 	av->vdev.release = video_device_release_empty;
1296 	av->vdev.fops = &isys_fops;
1297 	av->vdev.v4l2_dev = &av->isys->v4l2_dev;
1298 	av->vdev.dev_parent = &av->isys->adev->isp->pdev->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 
1318 out_media_entity_cleanup:
1319 	vb2_video_unregister_device(&av->vdev);
1320 	media_entity_cleanup(&av->vdev.entity);
1321 
1322 out_vb2_queue_release:
1323 	vb2_queue_release(&av->aq.vbq);
1324 
1325 out_free_watermark:
1326 	mutex_destroy(&av->mutex);
1327 
1328 	return ret;
1329 }
1330 
ipu6_isys_video_cleanup(struct ipu6_isys_video * av)1331 void 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 
ipu6_isys_get_format(struct ipu6_isys_video * av)1338 u32 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 
ipu6_isys_get_data_size(struct ipu6_isys_video * av)1349 u32 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 
ipu6_isys_get_bytes_per_line(struct ipu6_isys_video * av)1360 u32 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 
ipu6_isys_get_frame_width(struct ipu6_isys_video * av)1371 u32 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 
ipu6_isys_get_frame_height(struct ipu6_isys_video * av)1382 u32 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