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