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