1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2013 - 2025 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/compat.h>
12 #include <linux/device.h>
13 #include <linux/iopoll.h>
14 #include <linux/list.h>
15 #include <linux/minmax.h>
16 #include <linux/module.h>
17 #include <linux/mutex.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/spinlock.h>
20 #include <linux/string.h>
21
22 #include <media/media-entity.h>
23 #include <media/v4l2-dev.h>
24 #include <media/v4l2-fh.h>
25 #include <media/v4l2-ioctl.h>
26 #include <media/v4l2-mc.h>
27 #include <media/v4l2-subdev.h>
28 #include <media/videobuf2-v4l2.h>
29
30 #include "abi/ipu7_fw_isys_abi.h"
31
32 #include "ipu7.h"
33 #include "ipu7-bus.h"
34 #include "ipu7-buttress-regs.h"
35 #include "ipu7-fw-isys.h"
36 #include "ipu7-isys.h"
37 #include "ipu7-isys-video.h"
38 #include "ipu7-platform-regs.h"
39
40 const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = {
41 {V4L2_PIX_FMT_SBGGR12, 16, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
42 IPU_INSYS_FRAME_FORMAT_RAW16},
43 {V4L2_PIX_FMT_SGBRG12, 16, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
44 IPU_INSYS_FRAME_FORMAT_RAW16},
45 {V4L2_PIX_FMT_SGRBG12, 16, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
46 IPU_INSYS_FRAME_FORMAT_RAW16},
47 {V4L2_PIX_FMT_SRGGB12, 16, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
48 IPU_INSYS_FRAME_FORMAT_RAW16},
49 {V4L2_PIX_FMT_SBGGR10, 16, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
50 IPU_INSYS_FRAME_FORMAT_RAW16},
51 {V4L2_PIX_FMT_SGBRG10, 16, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
52 IPU_INSYS_FRAME_FORMAT_RAW16},
53 {V4L2_PIX_FMT_SGRBG10, 16, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
54 IPU_INSYS_FRAME_FORMAT_RAW16},
55 {V4L2_PIX_FMT_SRGGB10, 16, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
56 IPU_INSYS_FRAME_FORMAT_RAW16},
57 {V4L2_PIX_FMT_SBGGR8, 8, 8, MEDIA_BUS_FMT_SBGGR8_1X8,
58 IPU_INSYS_FRAME_FORMAT_RAW8},
59 {V4L2_PIX_FMT_SGBRG8, 8, 8, MEDIA_BUS_FMT_SGBRG8_1X8,
60 IPU_INSYS_FRAME_FORMAT_RAW8},
61 {V4L2_PIX_FMT_SGRBG8, 8, 8, MEDIA_BUS_FMT_SGRBG8_1X8,
62 IPU_INSYS_FRAME_FORMAT_RAW8},
63 {V4L2_PIX_FMT_SRGGB8, 8, 8, MEDIA_BUS_FMT_SRGGB8_1X8,
64 IPU_INSYS_FRAME_FORMAT_RAW8},
65 {V4L2_PIX_FMT_SBGGR12P, 12, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
66 IPU_INSYS_FRAME_FORMAT_RAW12},
67 {V4L2_PIX_FMT_SGBRG12P, 12, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
68 IPU_INSYS_FRAME_FORMAT_RAW12},
69 {V4L2_PIX_FMT_SGRBG12P, 12, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
70 IPU_INSYS_FRAME_FORMAT_RAW12},
71 {V4L2_PIX_FMT_SRGGB12P, 12, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
72 IPU_INSYS_FRAME_FORMAT_RAW12},
73 {V4L2_PIX_FMT_SBGGR10P, 10, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
74 IPU_INSYS_FRAME_FORMAT_RAW10},
75 {V4L2_PIX_FMT_SGBRG10P, 10, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
76 IPU_INSYS_FRAME_FORMAT_RAW10},
77 {V4L2_PIX_FMT_SGRBG10P, 10, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
78 IPU_INSYS_FRAME_FORMAT_RAW10},
79 {V4L2_PIX_FMT_SRGGB10P, 10, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
80 IPU_INSYS_FRAME_FORMAT_RAW10},
81 {V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16,
82 IPU_INSYS_FRAME_FORMAT_UYVY},
83 {V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16,
84 IPU_INSYS_FRAME_FORMAT_YUYV},
85 {V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16,
86 IPU_INSYS_FRAME_FORMAT_RGB565},
87 {V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24,
88 IPU_INSYS_FRAME_FORMAT_RGBA888},
89 };
90
video_open(struct file * file)91 static int video_open(struct file *file)
92 {
93 return v4l2_fh_open(file);
94 }
95
ipu7_isys_get_isys_format(u32 pixelformat)96 const struct ipu7_isys_pixelformat *ipu7_isys_get_isys_format(u32 pixelformat)
97 {
98 unsigned int i;
99
100 for (i = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) {
101 const struct ipu7_isys_pixelformat *pfmt = &ipu7_isys_pfmts[i];
102
103 if (pfmt->pixelformat == pixelformat)
104 return pfmt;
105 }
106
107 return &ipu7_isys_pfmts[0];
108 }
109
ipu7_isys_vidioc_querycap(struct file * file,void * fh,struct v4l2_capability * cap)110 static int ipu7_isys_vidioc_querycap(struct file *file, void *fh,
111 struct v4l2_capability *cap)
112 {
113 struct ipu7_isys_video *av = video_drvdata(file);
114
115 strscpy(cap->driver, IPU_ISYS_NAME, sizeof(cap->driver));
116 strscpy(cap->card, av->isys->media_dev.model, sizeof(cap->card));
117
118 return 0;
119 }
120
ipu7_isys_vidioc_enum_fmt(struct file * file,void * fh,struct v4l2_fmtdesc * f)121 static int ipu7_isys_vidioc_enum_fmt(struct file *file, void *fh,
122 struct v4l2_fmtdesc *f)
123 {
124 unsigned int i, num_found;
125
126 for (i = 0, num_found = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) {
127 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
128 continue;
129
130 if (f->mbus_code && f->mbus_code != ipu7_isys_pfmts[i].code)
131 continue;
132
133 if (num_found < f->index) {
134 num_found++;
135 continue;
136 }
137
138 f->flags = 0;
139 f->pixelformat = ipu7_isys_pfmts[i].pixelformat;
140
141 return 0;
142 }
143
144 return -EINVAL;
145 }
146
ipu7_isys_vidioc_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)147 static int ipu7_isys_vidioc_enum_framesizes(struct file *file, void *fh,
148 struct v4l2_frmsizeenum *fsize)
149 {
150 unsigned int i;
151
152 if (fsize->index > 0)
153 return -EINVAL;
154
155 for (i = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) {
156 if (fsize->pixel_format != ipu7_isys_pfmts[i].pixelformat)
157 continue;
158
159 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
160 fsize->stepwise.min_width = IPU_ISYS_MIN_WIDTH;
161 fsize->stepwise.max_width = IPU_ISYS_MAX_WIDTH;
162 fsize->stepwise.min_height = IPU_ISYS_MIN_HEIGHT;
163 fsize->stepwise.max_height = IPU_ISYS_MAX_HEIGHT;
164 fsize->stepwise.step_width = 2;
165 fsize->stepwise.step_height = 2;
166
167 return 0;
168 }
169
170 return -EINVAL;
171 }
172
ipu7_isys_vidioc_g_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * f)173 static int ipu7_isys_vidioc_g_fmt_vid_cap(struct file *file, void *fh,
174 struct v4l2_format *f)
175 {
176 struct ipu7_isys_video *av = video_drvdata(file);
177
178 f->fmt.pix = av->pix_fmt;
179
180 return 0;
181 }
182
ipu7_isys_try_fmt_cap(struct ipu7_isys_video * av,u32 type,u32 * format,u32 * width,u32 * height,u32 * bytesperline,u32 * sizeimage)183 static void ipu7_isys_try_fmt_cap(struct ipu7_isys_video *av, u32 type,
184 u32 *format, u32 *width, u32 *height,
185 u32 *bytesperline, u32 *sizeimage)
186 {
187 const struct ipu7_isys_pixelformat *pfmt =
188 ipu7_isys_get_isys_format(*format);
189
190 *format = pfmt->pixelformat;
191 *width = clamp(*width, IPU_ISYS_MIN_WIDTH, IPU_ISYS_MAX_WIDTH);
192 *height = clamp(*height, IPU_ISYS_MIN_HEIGHT, IPU_ISYS_MAX_HEIGHT);
193
194 if (pfmt->bpp != pfmt->bpp_packed)
195 *bytesperline = *width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE);
196 else
197 *bytesperline = DIV_ROUND_UP(*width * pfmt->bpp, BITS_PER_BYTE);
198
199 *bytesperline = ALIGN(*bytesperline, 64U);
200
201 /*
202 * (height + 1) * bytesperline due to a hardware issue: the DMA unit
203 * is a power of two, and a line should be transferred as few units
204 * as possible. The result is that up to line length more data than
205 * the image size may be transferred to memory after the image.
206 * Another limitation is the GDA allocation unit size. For low
207 * resolution it gives a bigger number. Use larger one to avoid
208 * memory corruption.
209 */
210 *sizeimage = *bytesperline * *height +
211 max(*bytesperline,
212 av->isys->pdata->ipdata->isys_dma_overshoot);
213 }
214
__ipu_isys_vidioc_try_fmt_vid_cap(struct ipu7_isys_video * av,struct v4l2_format * f)215 static void __ipu_isys_vidioc_try_fmt_vid_cap(struct ipu7_isys_video *av,
216 struct v4l2_format *f)
217 {
218 ipu7_isys_try_fmt_cap(av, f->type, &f->fmt.pix.pixelformat,
219 &f->fmt.pix.width, &f->fmt.pix.height,
220 &f->fmt.pix.bytesperline, &f->fmt.pix.sizeimage);
221
222 f->fmt.pix.field = V4L2_FIELD_NONE;
223 f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
224 f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
225 f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
226 f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
227 }
228
ipu7_isys_vidioc_try_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * f)229 static int ipu7_isys_vidioc_try_fmt_vid_cap(struct file *file, void *fh,
230 struct v4l2_format *f)
231 {
232 struct ipu7_isys_video *av = video_drvdata(file);
233
234 if (vb2_is_busy(&av->aq.vbq))
235 return -EBUSY;
236
237 __ipu_isys_vidioc_try_fmt_vid_cap(av, f);
238
239 return 0;
240 }
241
ipu7_isys_vidioc_s_fmt_vid_cap(struct file * file,void * fh,struct v4l2_format * f)242 static int ipu7_isys_vidioc_s_fmt_vid_cap(struct file *file, void *fh,
243 struct v4l2_format *f)
244 {
245 struct ipu7_isys_video *av = video_drvdata(file);
246
247 ipu7_isys_vidioc_try_fmt_vid_cap(file, fh, f);
248 av->pix_fmt = f->fmt.pix;
249
250 return 0;
251 }
252
ipu7_isys_vidioc_reqbufs(struct file * file,void * priv,struct v4l2_requestbuffers * p)253 static int ipu7_isys_vidioc_reqbufs(struct file *file, void *priv,
254 struct v4l2_requestbuffers *p)
255 {
256 struct ipu7_isys_video *av = video_drvdata(file);
257 int ret;
258
259 av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->type);
260 av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->type);
261
262 ret = vb2_queue_change_type(&av->aq.vbq, p->type);
263 if (ret)
264 return ret;
265
266 return vb2_ioctl_reqbufs(file, priv, p);
267 }
268
ipu7_isys_vidioc_create_bufs(struct file * file,void * priv,struct v4l2_create_buffers * p)269 static int ipu7_isys_vidioc_create_bufs(struct file *file, void *priv,
270 struct v4l2_create_buffers *p)
271 {
272 struct ipu7_isys_video *av = video_drvdata(file);
273 int ret;
274
275 av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->format.type);
276 av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->format.type);
277
278 ret = vb2_queue_change_type(&av->aq.vbq, p->format.type);
279 if (ret)
280 return ret;
281
282 return vb2_ioctl_create_bufs(file, priv, p);
283 }
284
link_validate(struct media_link * link)285 static int link_validate(struct media_link *link)
286 {
287 struct ipu7_isys_video *av =
288 container_of(link->sink, struct ipu7_isys_video, pad);
289 struct device *dev = &av->isys->adev->auxdev.dev;
290 struct v4l2_subdev_state *s_state;
291 struct v4l2_mbus_framefmt *s_fmt;
292 struct v4l2_subdev *s_sd;
293 struct media_pad *s_pad;
294 u32 s_stream, code;
295 int ret = -EPIPE;
296
297 if (!link->source->entity)
298 return ret;
299
300 s_sd = media_entity_to_v4l2_subdev(link->source->entity);
301 s_state = v4l2_subdev_get_unlocked_active_state(s_sd);
302 if (!s_state)
303 return ret;
304
305 dev_dbg(dev, "validating link \"%s\":%u -> \"%s\"\n",
306 link->source->entity->name, link->source->index,
307 link->sink->entity->name);
308
309 s_pad = media_pad_remote_pad_first(&av->pad);
310 s_stream = ipu7_isys_get_src_stream_by_src_pad(s_sd, s_pad->index);
311
312 v4l2_subdev_lock_state(s_state);
313
314 s_fmt = v4l2_subdev_state_get_format(s_state, s_pad->index, s_stream);
315 if (!s_fmt) {
316 dev_err(dev, "failed to get source pad format\n");
317 goto unlock;
318 }
319
320 code = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat)->code;
321
322 if (s_fmt->width != av->pix_fmt.width ||
323 s_fmt->height != av->pix_fmt.height || s_fmt->code != code) {
324 dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n",
325 s_fmt->width, s_fmt->height, s_fmt->code,
326 av->pix_fmt.width, av->pix_fmt.height, code);
327 goto unlock;
328 }
329
330 v4l2_subdev_unlock_state(s_state);
331
332 return 0;
333 unlock:
334 v4l2_subdev_unlock_state(s_state);
335
336 return ret;
337 }
338
get_stream_opened(struct ipu7_isys_video * av)339 static void get_stream_opened(struct ipu7_isys_video *av)
340 {
341 unsigned long flags;
342
343 spin_lock_irqsave(&av->isys->streams_lock, flags);
344 av->isys->stream_opened++;
345 spin_unlock_irqrestore(&av->isys->streams_lock, flags);
346 }
347
put_stream_opened(struct ipu7_isys_video * av)348 static void put_stream_opened(struct ipu7_isys_video *av)
349 {
350 unsigned long flags;
351
352 spin_lock_irqsave(&av->isys->streams_lock, flags);
353 av->isys->stream_opened--;
354 spin_unlock_irqrestore(&av->isys->streams_lock, flags);
355 }
356
ipu7_isys_fw_pin_cfg(struct ipu7_isys_video * av,struct ipu7_insys_stream_cfg * cfg)357 static int ipu7_isys_fw_pin_cfg(struct ipu7_isys_video *av,
358 struct ipu7_insys_stream_cfg *cfg)
359 {
360 struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
361 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
362 struct ipu7_isys_stream *stream = av->stream;
363 const struct ipu7_isys_pixelformat *pfmt =
364 ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
365 struct ipu7_insys_output_pin *output_pin;
366 struct ipu7_insys_input_pin *input_pin;
367 int input_pins = cfg->nof_input_pins++;
368 struct ipu7_isys_queue *aq = &av->aq;
369 struct ipu7_isys *isys = av->isys;
370 struct device *dev = &isys->adev->auxdev.dev;
371 struct v4l2_mbus_framefmt fmt;
372 int output_pins;
373 u32 src_stream;
374 int ret;
375
376 src_stream = ipu7_isys_get_src_stream_by_src_pad(sd, src_pad->index);
377 ret = ipu7_isys_get_stream_pad_fmt(sd, src_pad->index, src_stream,
378 &fmt);
379 if (ret < 0) {
380 dev_err(dev, "can't get stream format (%d)\n", ret);
381 return ret;
382 }
383
384 input_pin = &cfg->input_pins[input_pins];
385 input_pin->input_res.width = fmt.width;
386 input_pin->input_res.height = fmt.height;
387 input_pin->dt = av->dt;
388 input_pin->disable_mipi_unpacking = 0;
389 pfmt = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
390 if (pfmt->bpp == pfmt->bpp_packed && pfmt->bpp % BITS_PER_BYTE)
391 input_pin->disable_mipi_unpacking = 1;
392 input_pin->mapped_dt = N_IPU_INSYS_MIPI_DATA_TYPE;
393 input_pin->dt_rename_mode = IPU_INSYS_MIPI_DT_NO_RENAME;
394 /* if enable polling isys interrupt, the follow values maybe set */
395 input_pin->sync_msg_map = IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF |
396 IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED |
397 IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF |
398 IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED;
399
400 output_pins = cfg->nof_output_pins++;
401 aq->fw_output = output_pins;
402 stream->output_pins[output_pins].pin_ready = ipu7_isys_queue_buf_ready;
403 stream->output_pins[output_pins].aq = aq;
404
405 output_pin = &cfg->output_pins[output_pins];
406 /* output pin msg link */
407 output_pin->link.buffer_lines = 0;
408 output_pin->link.foreign_key = IPU_MSG_LINK_FOREIGN_KEY_NONE;
409 output_pin->link.granularity_pointer_update = 0;
410 output_pin->link.msg_link_streaming_mode =
411 IA_GOFO_MSG_LINK_STREAMING_MODE_SOFF;
412
413 output_pin->link.pbk_id = IPU_MSG_LINK_PBK_ID_DONT_CARE;
414 output_pin->link.pbk_slot_id = IPU_MSG_LINK_PBK_SLOT_ID_DONT_CARE;
415 output_pin->link.dest = IPU_INSYS_OUTPUT_LINK_DEST_MEM;
416 output_pin->link.use_sw_managed = 1;
417 /* TODO: set the snoop bit for metadata capture */
418 output_pin->link.is_snoop = 0;
419
420 /* output pin crop */
421 output_pin->crop.line_top = 0;
422 output_pin->crop.line_bottom = 0;
423
424 /* output de-compression */
425 output_pin->dpcm.enable = 0;
426
427 /* frame format type */
428 pfmt = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
429 output_pin->ft = (u16)pfmt->css_pixelformat;
430
431 /* stride in bytes */
432 output_pin->stride = av->pix_fmt.bytesperline;
433 output_pin->send_irq = 1;
434 output_pin->early_ack_en = 0;
435
436 /* input pin id */
437 output_pin->input_pin_id = input_pins;
438
439 return 0;
440 }
441
442 /* Create stream and start it using the CSS FW ABI. */
start_stream_firmware(struct ipu7_isys_video * av,struct ipu7_isys_buffer_list * bl)443 static int start_stream_firmware(struct ipu7_isys_video *av,
444 struct ipu7_isys_buffer_list *bl)
445 {
446 struct device *dev = &av->isys->adev->auxdev.dev;
447 struct ipu7_isys_stream *stream = av->stream;
448 struct ipu7_insys_stream_cfg *stream_cfg;
449 struct ipu7_insys_buffset *buf = NULL;
450 struct isys_fw_msgs *msg = NULL;
451 struct ipu7_isys_queue *aq;
452 int ret, retout, tout;
453 u16 send_type;
454
455 if (WARN_ON(!bl))
456 return -EIO;
457
458 msg = ipu7_get_fw_msg_buf(stream);
459 if (!msg)
460 return -ENOMEM;
461
462 stream_cfg = &msg->fw_msg.stream;
463 stream_cfg->port_id = stream->stream_source;
464 stream_cfg->vc = stream->vc;
465 stream_cfg->stream_msg_map = IPU_INSYS_STREAM_ENABLE_MSG_SEND_RESP |
466 IPU_INSYS_STREAM_ENABLE_MSG_SEND_IRQ;
467
468 list_for_each_entry(aq, &stream->queues, node) {
469 struct ipu7_isys_video *__av = ipu7_isys_queue_to_video(aq);
470
471 ret = ipu7_isys_fw_pin_cfg(__av, stream_cfg);
472 if (ret < 0) {
473 ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
474 return ret;
475 }
476 }
477
478 ipu7_fw_isys_dump_stream_cfg(dev, stream_cfg);
479
480 stream->nr_output_pins = stream_cfg->nof_output_pins;
481
482 reinit_completion(&stream->stream_open_completion);
483
484 ret = ipu7_fw_isys_complex_cmd(av->isys, stream->stream_handle,
485 stream_cfg, msg->dma_addr,
486 sizeof(*stream_cfg),
487 IPU_INSYS_SEND_TYPE_STREAM_OPEN);
488 if (ret < 0) {
489 dev_err(dev, "can't open stream (%d)\n", ret);
490 ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
491 return ret;
492 }
493
494 get_stream_opened(av);
495
496 tout = wait_for_completion_timeout(&stream->stream_open_completion,
497 FW_CALL_TIMEOUT_JIFFIES);
498
499 ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
500
501 if (!tout) {
502 dev_err(dev, "stream open time out\n");
503 ret = -ETIMEDOUT;
504 goto out_put_stream_opened;
505 }
506 if (stream->error) {
507 dev_err(dev, "stream open error: %d\n", stream->error);
508 ret = -EIO;
509 goto out_put_stream_opened;
510 }
511 dev_dbg(dev, "start stream: open complete\n");
512
513 msg = ipu7_get_fw_msg_buf(stream);
514 if (!msg) {
515 ret = -ENOMEM;
516 goto out_put_stream_opened;
517 }
518 buf = &msg->fw_msg.frame;
519
520 ipu7_isys_buffer_to_fw_frame_buff(buf, stream, bl);
521 ipu7_isys_buffer_list_queue(bl, IPU_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
522
523 reinit_completion(&stream->stream_start_completion);
524
525 send_type = IPU_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
526 ipu7_fw_isys_dump_frame_buff_set(dev, buf,
527 stream_cfg->nof_output_pins);
528 ret = ipu7_fw_isys_complex_cmd(av->isys, stream->stream_handle, buf,
529 msg->dma_addr, sizeof(*buf),
530 send_type);
531 if (ret < 0) {
532 dev_err(dev, "can't start streaming (%d)\n", ret);
533 goto out_stream_close;
534 }
535
536 tout = wait_for_completion_timeout(&stream->stream_start_completion,
537 FW_CALL_TIMEOUT_JIFFIES);
538 if (!tout) {
539 dev_err(dev, "stream start time out\n");
540 ret = -ETIMEDOUT;
541 goto out_stream_close;
542 }
543 if (stream->error) {
544 dev_err(dev, "stream start error: %d\n", stream->error);
545 ret = -EIO;
546 goto out_stream_close;
547 }
548 dev_dbg(dev, "start stream: complete\n");
549
550 return 0;
551
552 out_stream_close:
553 reinit_completion(&stream->stream_close_completion);
554
555 retout = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle,
556 IPU_INSYS_SEND_TYPE_STREAM_CLOSE);
557 if (retout < 0) {
558 dev_dbg(dev, "can't close stream (%d)\n", retout);
559 goto out_put_stream_opened;
560 }
561
562 tout = wait_for_completion_timeout(&stream->stream_close_completion,
563 FW_CALL_TIMEOUT_JIFFIES);
564 if (!tout)
565 dev_err(dev, "stream close time out with error %d\n",
566 stream->error);
567 else
568 dev_dbg(dev, "stream close complete\n");
569
570 out_put_stream_opened:
571 put_stream_opened(av);
572
573 return ret;
574 }
575
stop_streaming_firmware(struct ipu7_isys_video * av)576 static void stop_streaming_firmware(struct ipu7_isys_video *av)
577 {
578 struct device *dev = &av->isys->adev->auxdev.dev;
579 struct ipu7_isys_stream *stream = av->stream;
580 int ret, tout;
581
582 reinit_completion(&stream->stream_stop_completion);
583
584 ret = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle,
585 IPU_INSYS_SEND_TYPE_STREAM_FLUSH);
586 if (ret < 0) {
587 dev_err(dev, "can't stop stream (%d)\n", ret);
588 return;
589 }
590
591 tout = wait_for_completion_timeout(&stream->stream_stop_completion,
592 FW_CALL_TIMEOUT_JIFFIES);
593 if (!tout)
594 dev_warn(dev, "stream stop time out\n");
595 else if (stream->error)
596 dev_warn(dev, "stream stop error: %d\n", stream->error);
597 else
598 dev_dbg(dev, "stop stream: complete\n");
599 }
600
close_streaming_firmware(struct ipu7_isys_video * av)601 static void close_streaming_firmware(struct ipu7_isys_video *av)
602 {
603 struct device *dev = &av->isys->adev->auxdev.dev;
604 struct ipu7_isys_stream *stream = av->stream;
605 int ret, tout;
606
607 reinit_completion(&stream->stream_close_completion);
608
609 ret = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle,
610 IPU_INSYS_SEND_TYPE_STREAM_CLOSE);
611 if (ret < 0) {
612 dev_err(dev, "can't close stream (%d)\n", ret);
613 return;
614 }
615
616 tout = wait_for_completion_timeout(&stream->stream_close_completion,
617 FW_CALL_TIMEOUT_JIFFIES);
618 if (!tout)
619 dev_warn(dev, "stream close time out\n");
620 else if (stream->error)
621 dev_warn(dev, "stream close error: %d\n", stream->error);
622 else
623 dev_dbg(dev, "close stream: complete\n");
624
625 put_stream_opened(av);
626 }
627
ipu7_isys_video_prepare_stream(struct ipu7_isys_video * av,struct media_entity * source_entity,int nr_queues)628 int ipu7_isys_video_prepare_stream(struct ipu7_isys_video *av,
629 struct media_entity *source_entity,
630 int nr_queues)
631 {
632 struct ipu7_isys_stream *stream = av->stream;
633 struct ipu7_isys_csi2 *csi2;
634
635 if (WARN_ON(stream->nr_streaming))
636 return -EINVAL;
637
638 stream->nr_queues = nr_queues;
639 atomic_set(&stream->sequence, 0);
640 atomic_set(&stream->buf_id, 0);
641
642 stream->seq_index = 0;
643 memset(stream->seq, 0, sizeof(stream->seq));
644
645 if (WARN_ON(!list_empty(&stream->queues)))
646 return -EINVAL;
647
648 stream->stream_source = stream->asd->source;
649
650 csi2 = ipu7_isys_subdev_to_csi2(stream->asd);
651 csi2->receiver_errors = 0;
652 stream->source_entity = source_entity;
653
654 dev_dbg(&av->isys->adev->auxdev.dev,
655 "prepare stream: external entity %s\n",
656 stream->source_entity->name);
657
658 return 0;
659 }
660
ipu7_isys_put_stream(struct ipu7_isys_stream * stream)661 void ipu7_isys_put_stream(struct ipu7_isys_stream *stream)
662 {
663 unsigned long flags;
664 struct device *dev;
665 unsigned int i;
666
667 if (!stream) {
668 pr_err("ipu7-isys: no available stream\n");
669 return;
670 }
671
672 dev = &stream->isys->adev->auxdev.dev;
673
674 spin_lock_irqsave(&stream->isys->streams_lock, flags);
675 for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
676 if (&stream->isys->streams[i] == stream) {
677 if (stream->isys->streams_ref_count[i] > 0)
678 stream->isys->streams_ref_count[i]--;
679 else
680 dev_warn(dev, "invalid stream %d\n", i);
681
682 break;
683 }
684 }
685 spin_unlock_irqrestore(&stream->isys->streams_lock, flags);
686 }
687
688 static struct ipu7_isys_stream *
ipu7_isys_get_stream(struct ipu7_isys_video * av,struct ipu7_isys_subdev * asd)689 ipu7_isys_get_stream(struct ipu7_isys_video *av, struct ipu7_isys_subdev *asd)
690 {
691 struct ipu7_isys_stream *stream = NULL;
692 struct ipu7_isys *isys = av->isys;
693 unsigned long flags;
694 unsigned int i;
695 u8 vc = av->vc;
696
697 if (!isys)
698 return NULL;
699
700 spin_lock_irqsave(&isys->streams_lock, flags);
701 for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
702 if (isys->streams_ref_count[i] && isys->streams[i].vc == vc &&
703 isys->streams[i].asd == asd) {
704 isys->streams_ref_count[i]++;
705 stream = &isys->streams[i];
706 break;
707 }
708 }
709
710 if (!stream) {
711 for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
712 if (!isys->streams_ref_count[i]) {
713 isys->streams_ref_count[i]++;
714 stream = &isys->streams[i];
715 stream->vc = vc;
716 stream->asd = asd;
717 break;
718 }
719 }
720 }
721 spin_unlock_irqrestore(&isys->streams_lock, flags);
722
723 return stream;
724 }
725
726 struct ipu7_isys_stream *
ipu7_isys_query_stream_by_handle(struct ipu7_isys * isys,u8 stream_handle)727 ipu7_isys_query_stream_by_handle(struct ipu7_isys *isys, u8 stream_handle)
728 {
729 unsigned long flags;
730 struct ipu7_isys_stream *stream = NULL;
731
732 if (!isys)
733 return NULL;
734
735 if (stream_handle >= IPU_ISYS_MAX_STREAMS) {
736 dev_err(&isys->adev->auxdev.dev,
737 "stream_handle %d is invalid\n", stream_handle);
738 return NULL;
739 }
740
741 spin_lock_irqsave(&isys->streams_lock, flags);
742 if (isys->streams_ref_count[stream_handle] > 0) {
743 isys->streams_ref_count[stream_handle]++;
744 stream = &isys->streams[stream_handle];
745 }
746 spin_unlock_irqrestore(&isys->streams_lock, flags);
747
748 return stream;
749 }
750
751 struct ipu7_isys_stream *
ipu7_isys_query_stream_by_source(struct ipu7_isys * isys,int source,u8 vc)752 ipu7_isys_query_stream_by_source(struct ipu7_isys *isys, int source, u8 vc)
753 {
754 struct ipu7_isys_stream *stream = NULL;
755 unsigned long flags;
756 unsigned int i;
757
758 if (!isys)
759 return NULL;
760
761 if (source < 0) {
762 dev_err(&isys->adev->auxdev.dev,
763 "query stream with invalid port number\n");
764 return NULL;
765 }
766
767 spin_lock_irqsave(&isys->streams_lock, flags);
768 for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
769 if (!isys->streams_ref_count[i])
770 continue;
771
772 if (isys->streams[i].stream_source == source &&
773 isys->streams[i].vc == vc) {
774 stream = &isys->streams[i];
775 isys->streams_ref_count[i]++;
776 break;
777 }
778 }
779 spin_unlock_irqrestore(&isys->streams_lock, flags);
780
781 return stream;
782 }
783
get_remote_pad_stream(struct media_pad * r_pad)784 static u32 get_remote_pad_stream(struct media_pad *r_pad)
785 {
786 struct v4l2_subdev_state *state;
787 struct v4l2_subdev *sd;
788 u32 stream_id = 0;
789 unsigned int i;
790
791 sd = media_entity_to_v4l2_subdev(r_pad->entity);
792 state = v4l2_subdev_lock_and_get_active_state(sd);
793 if (!state)
794 return 0;
795
796 for (i = 0; i < state->stream_configs.num_configs; i++) {
797 struct v4l2_subdev_stream_config *cfg =
798 &state->stream_configs.configs[i];
799 if (cfg->pad == r_pad->index) {
800 stream_id = cfg->stream;
801 break;
802 }
803 }
804
805 v4l2_subdev_unlock_state(state);
806
807 return stream_id;
808 }
809
ipu7_isys_video_set_streaming(struct ipu7_isys_video * av,int state,struct ipu7_isys_buffer_list * bl)810 int ipu7_isys_video_set_streaming(struct ipu7_isys_video *av, int state,
811 struct ipu7_isys_buffer_list *bl)
812 {
813 struct ipu7_isys_stream *stream = av->stream;
814 struct device *dev = &av->isys->adev->auxdev.dev;
815 struct media_pad *r_pad;
816 struct v4l2_subdev *sd;
817 u32 r_stream;
818 int ret = 0;
819
820 dev_dbg(dev, "set stream: %d\n", state);
821
822 if (WARN(!stream->source_entity, "No source entity for stream\n"))
823 return -ENODEV;
824
825 sd = &stream->asd->sd;
826 r_pad = media_pad_remote_pad_first(&av->pad);
827 r_stream = get_remote_pad_stream(r_pad);
828 if (!state) {
829 stop_streaming_firmware(av);
830
831 /* stop sub-device which connects with video */
832 dev_dbg(dev, "disable streams %s pad:%d mask:0x%llx\n",
833 sd->name, r_pad->index, BIT_ULL(r_stream));
834 ret = v4l2_subdev_disable_streams(sd, r_pad->index,
835 BIT_ULL(r_stream));
836 if (ret) {
837 dev_err(dev, "disable streams %s failed with %d\n",
838 sd->name, ret);
839 return ret;
840 }
841
842 close_streaming_firmware(av);
843 } else {
844 ret = start_stream_firmware(av, bl);
845 if (ret) {
846 dev_err(dev, "start stream of firmware failed\n");
847 return ret;
848 }
849
850 /* start sub-device which connects with video */
851 dev_dbg(dev, "enable streams %s pad: %d mask:0x%llx\n",
852 sd->name, r_pad->index, BIT_ULL(r_stream));
853 ret = v4l2_subdev_enable_streams(sd, r_pad->index,
854 BIT_ULL(r_stream));
855 if (ret) {
856 dev_err(dev, "enable streams %s failed with %d\n",
857 sd->name, ret);
858 goto out_media_entity_stop_streaming_firmware;
859 }
860 }
861
862 av->streaming = state;
863
864 return 0;
865
866 out_media_entity_stop_streaming_firmware:
867 stop_streaming_firmware(av);
868
869 return ret;
870 }
871
872 static const struct v4l2_ioctl_ops ipu7_v4l2_ioctl_ops = {
873 .vidioc_querycap = ipu7_isys_vidioc_querycap,
874 .vidioc_enum_fmt_vid_cap = ipu7_isys_vidioc_enum_fmt,
875 .vidioc_enum_framesizes = ipu7_isys_vidioc_enum_framesizes,
876 .vidioc_g_fmt_vid_cap = ipu7_isys_vidioc_g_fmt_vid_cap,
877 .vidioc_s_fmt_vid_cap = ipu7_isys_vidioc_s_fmt_vid_cap,
878 .vidioc_try_fmt_vid_cap = ipu7_isys_vidioc_try_fmt_vid_cap,
879 .vidioc_reqbufs = ipu7_isys_vidioc_reqbufs,
880 .vidioc_create_bufs = ipu7_isys_vidioc_create_bufs,
881 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
882 .vidioc_querybuf = vb2_ioctl_querybuf,
883 .vidioc_qbuf = vb2_ioctl_qbuf,
884 .vidioc_dqbuf = vb2_ioctl_dqbuf,
885 .vidioc_streamon = vb2_ioctl_streamon,
886 .vidioc_streamoff = vb2_ioctl_streamoff,
887 .vidioc_expbuf = vb2_ioctl_expbuf,
888 };
889
890 static const struct media_entity_operations entity_ops = {
891 .link_validate = link_validate,
892 };
893
894 static const struct v4l2_file_operations isys_fops = {
895 .owner = THIS_MODULE,
896 .poll = vb2_fop_poll,
897 .unlocked_ioctl = video_ioctl2,
898 .mmap = vb2_fop_mmap,
899 .open = video_open,
900 .release = vb2_fop_release,
901 };
902
ipu7_isys_fw_open(struct ipu7_isys * isys)903 int ipu7_isys_fw_open(struct ipu7_isys *isys)
904 {
905 struct ipu7_bus_device *adev = isys->adev;
906 int ret;
907
908 ret = pm_runtime_resume_and_get(&adev->auxdev.dev);
909 if (ret < 0)
910 return ret;
911
912 mutex_lock(&isys->mutex);
913
914 if (isys->ref_count++)
915 goto unlock;
916
917 /*
918 * Buffers could have been left to wrong queue at last closure.
919 * Move them now back to empty buffer queue.
920 */
921 ipu7_cleanup_fw_msg_bufs(isys);
922
923 ret = ipu7_fw_isys_open(isys);
924 if (ret < 0)
925 goto out;
926
927 unlock:
928 mutex_unlock(&isys->mutex);
929
930 return 0;
931 out:
932 isys->ref_count--;
933 mutex_unlock(&isys->mutex);
934 pm_runtime_put(&adev->auxdev.dev);
935
936 return ret;
937 }
938
ipu7_isys_fw_close(struct ipu7_isys * isys)939 void ipu7_isys_fw_close(struct ipu7_isys *isys)
940 {
941 mutex_lock(&isys->mutex);
942
943 isys->ref_count--;
944
945 if (!isys->ref_count)
946 ipu7_fw_isys_close(isys);
947
948 mutex_unlock(&isys->mutex);
949 }
950
ipu7_isys_setup_video(struct ipu7_isys_video * av,struct media_entity ** source_entity,int * nr_queues)951 int ipu7_isys_setup_video(struct ipu7_isys_video *av,
952 struct media_entity **source_entity, int *nr_queues)
953 {
954 const struct ipu7_isys_pixelformat *pfmt =
955 ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
956 struct device *dev = &av->isys->adev->auxdev.dev;
957 struct media_pad *source_pad, *remote_pad;
958 struct v4l2_mbus_frame_desc_entry entry;
959 struct v4l2_subdev_route *route = NULL;
960 struct v4l2_subdev_route *r;
961 struct v4l2_subdev_state *state;
962 struct ipu7_isys_subdev *asd;
963 struct v4l2_subdev *remote_sd;
964 struct media_pipeline *pipeline;
965 int ret = -EINVAL;
966
967 *nr_queues = 0;
968
969 remote_pad = media_pad_remote_pad_unique(&av->pad);
970 if (IS_ERR(remote_pad)) {
971 dev_dbg(dev, "failed to get remote pad\n");
972 return PTR_ERR(remote_pad);
973 }
974
975 remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
976 asd = to_ipu7_isys_subdev(remote_sd);
977
978 source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]);
979 if (!source_pad) {
980 dev_dbg(dev, "No external source entity\n");
981 return -ENODEV;
982 }
983
984 *source_entity = source_pad->entity;
985
986 state = v4l2_subdev_lock_and_get_active_state(remote_sd);
987 for_each_active_route(&state->routing, r) {
988 if (r->source_pad == remote_pad->index)
989 route = r;
990 }
991
992 if (!route) {
993 v4l2_subdev_unlock_state(state);
994 dev_dbg(dev, "Failed to find route\n");
995 return -ENODEV;
996 }
997
998 v4l2_subdev_unlock_state(state);
999
1000 ret = ipu7_isys_csi2_get_remote_desc(route->sink_stream,
1001 to_ipu7_isys_csi2(asd),
1002 *source_entity, &entry,
1003 nr_queues);
1004 if (ret == -ENOIOCTLCMD) {
1005 av->vc = 0;
1006 av->dt = ipu7_isys_mbus_code_to_mipi(pfmt->code);
1007 if (av->dt == 0xff)
1008 return -EINVAL;
1009 *nr_queues = 1;
1010 } else if (*nr_queues && !ret) {
1011 dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
1012 entry.stream, entry.length, entry.bus.csi2.vc,
1013 entry.bus.csi2.dt);
1014
1015 av->vc = entry.bus.csi2.vc;
1016 av->dt = entry.bus.csi2.dt;
1017 } else {
1018 dev_err(dev, "failed to get remote frame desc\n");
1019 return ret;
1020 }
1021
1022 pipeline = media_entity_pipeline(&av->vdev.entity);
1023 if (!pipeline)
1024 ret = video_device_pipeline_alloc_start(&av->vdev);
1025 else
1026 ret = video_device_pipeline_start(&av->vdev, pipeline);
1027 if (ret < 0) {
1028 dev_dbg(dev, "media pipeline start failed\n");
1029 return ret;
1030 }
1031
1032 av->stream = ipu7_isys_get_stream(av, asd);
1033 if (!av->stream) {
1034 video_device_pipeline_stop(&av->vdev);
1035 dev_err(dev, "no available stream for firmware\n");
1036 return -EINVAL;
1037 }
1038
1039 return 0;
1040 }
1041
1042 /*
1043 * Do everything that's needed to initialise things related to video
1044 * buffer queue, video node, and the related media entity. The caller
1045 * is expected to assign isys field and set the name of the video
1046 * device.
1047 */
ipu7_isys_video_init(struct ipu7_isys_video * av)1048 int ipu7_isys_video_init(struct ipu7_isys_video *av)
1049 {
1050 struct v4l2_format format = {
1051 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
1052 .fmt.pix = {
1053 .width = 1920,
1054 .height = 1080,
1055 },
1056 };
1057 int ret;
1058
1059 mutex_init(&av->mutex);
1060 av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC |
1061 V4L2_CAP_VIDEO_CAPTURE;
1062 av->vdev.vfl_dir = VFL_DIR_RX;
1063
1064 ret = ipu7_isys_queue_init(&av->aq);
1065 if (ret)
1066 goto out_mutex_destroy;
1067
1068 av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
1069 ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad);
1070 if (ret)
1071 goto out_vb2_queue_cleanup;
1072
1073 av->vdev.entity.ops = &entity_ops;
1074 av->vdev.release = video_device_release_empty;
1075 av->vdev.fops = &isys_fops;
1076 av->vdev.v4l2_dev = &av->isys->v4l2_dev;
1077 av->vdev.dev_parent = &av->isys->adev->isp->pdev->dev;
1078 av->vdev.ioctl_ops = &ipu7_v4l2_ioctl_ops;
1079 av->vdev.queue = &av->aq.vbq;
1080 av->vdev.lock = &av->mutex;
1081
1082 __ipu_isys_vidioc_try_fmt_vid_cap(av, &format);
1083 av->pix_fmt = format.fmt.pix;
1084
1085 set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags);
1086 video_set_drvdata(&av->vdev, av);
1087
1088 ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1);
1089 if (ret)
1090 goto out_media_entity_cleanup;
1091
1092 return ret;
1093
1094 out_media_entity_cleanup:
1095 vb2_video_unregister_device(&av->vdev);
1096 media_entity_cleanup(&av->vdev.entity);
1097
1098 out_vb2_queue_cleanup:
1099 vb2_queue_release(&av->aq.vbq);
1100
1101 out_mutex_destroy:
1102 mutex_destroy(&av->mutex);
1103
1104 return ret;
1105 }
1106
ipu7_isys_video_cleanup(struct ipu7_isys_video * av)1107 void ipu7_isys_video_cleanup(struct ipu7_isys_video *av)
1108 {
1109 vb2_video_unregister_device(&av->vdev);
1110 media_entity_cleanup(&av->vdev.entity);
1111 mutex_destroy(&av->mutex);
1112 }
1113