808 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013--2024 Intel Corporation4 */5#include <linux/atomic.h>6#include <linux/bug.h>7#include <linux/device.h>8#include <linux/list.h>9#include <linux/lockdep.h>10#include <linux/mutex.h>11#include <linux/spinlock.h>12#include <linux/types.h>13 14#include <media/media-entity.h>15#include <media/v4l2-subdev.h>16#include <media/videobuf2-dma-contig.h>17#include <media/videobuf2-v4l2.h>18 19#include "ipu6-bus.h"20#include "ipu6-fw-isys.h"21#include "ipu6-isys.h"22#include "ipu6-isys-video.h"23 24static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers,25 unsigned int *num_planes, unsigned int sizes[],26 struct device *alloc_devs[])27{28 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);29 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);30 struct device *dev = &av->isys->adev->auxdev.dev;31 u32 size = ipu6_isys_get_data_size(av);32 33 /* num_planes == 0: we're being called through VIDIOC_REQBUFS */34 if (!*num_planes) {35 sizes[0] = size;36 } else if (sizes[0] < size) {37 dev_dbg(dev, "%s: queue setup: size %u < %u\n",38 av->vdev.name, sizes[0], size);39 return -EINVAL;40 }41 42 *num_planes = 1;43 44 return 0;45}46 47static int ipu6_isys_buf_prepare(struct vb2_buffer *vb)48{49 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);50 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);51 struct device *dev = &av->isys->adev->auxdev.dev;52 u32 bytesperline = ipu6_isys_get_bytes_per_line(av);53 u32 height = ipu6_isys_get_frame_height(av);54 u32 size = ipu6_isys_get_data_size(av);55 56 dev_dbg(dev, "buffer: %s: configured size %u, buffer size %lu\n",57 av->vdev.name, size, vb2_plane_size(vb, 0));58 59 if (size > vb2_plane_size(vb, 0))60 return -EINVAL;61 62 vb2_set_plane_payload(vb, 0, bytesperline * height);63 64 return 0;65}66 67/*68 * Queue a buffer list back to incoming or active queues. The buffers69 * are removed from the buffer list.70 */71void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,72 unsigned long op_flags,73 enum vb2_buffer_state state)74{75 struct ipu6_isys_buffer *ib, *ib_safe;76 unsigned long flags;77 bool first = true;78 79 if (!bl)80 return;81 82 WARN_ON_ONCE(!bl->nbufs);83 WARN_ON_ONCE(op_flags & IPU6_ISYS_BUFFER_LIST_FL_ACTIVE &&84 op_flags & IPU6_ISYS_BUFFER_LIST_FL_INCOMING);85 86 list_for_each_entry_safe(ib, ib_safe, &bl->head, head) {87 struct ipu6_isys_video *av;88 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);89 struct ipu6_isys_queue *aq =90 vb2_queue_to_isys_queue(vb->vb2_queue);91 struct device *dev;92 93 av = ipu6_isys_queue_to_video(aq);94 dev = &av->isys->adev->auxdev.dev;95 spin_lock_irqsave(&aq->lock, flags);96 list_del(&ib->head);97 if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_ACTIVE)98 list_add(&ib->head, &aq->active);99 else if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_INCOMING)100 list_add_tail(&ib->head, &aq->incoming);101 spin_unlock_irqrestore(&aq->lock, flags);102 103 if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_SET_STATE)104 vb2_buffer_done(vb, state);105 106 if (first) {107 dev_dbg(dev,108 "queue buf list %p flags %lx, s %d, %d bufs\n",109 bl, op_flags, state, bl->nbufs);110 first = false;111 }112 113 bl->nbufs--;114 }115 116 WARN_ON(bl->nbufs);117}118 119/*120 * flush_firmware_streamon_fail() - Flush in cases where requests may121 * have been queued to firmware and the *firmware streamon fails for a122 * reason or another.123 */124static void flush_firmware_streamon_fail(struct ipu6_isys_stream *stream)125{126 struct device *dev = &stream->isys->adev->auxdev.dev;127 struct ipu6_isys_queue *aq;128 unsigned long flags;129 130 lockdep_assert_held(&stream->mutex);131 132 list_for_each_entry(aq, &stream->queues, node) {133 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);134 struct ipu6_isys_buffer *ib, *ib_safe;135 136 spin_lock_irqsave(&aq->lock, flags);137 list_for_each_entry_safe(ib, ib_safe, &aq->active, head) {138 struct vb2_buffer *vb =139 ipu6_isys_buffer_to_vb2_buffer(ib);140 141 list_del(&ib->head);142 if (av->streaming) {143 dev_dbg(dev,144 "%s: queue buffer %u back to incoming\n",145 av->vdev.name, vb->index);146 /* Queue already streaming, return to driver. */147 list_add(&ib->head, &aq->incoming);148 continue;149 }150 /* Queue not yet streaming, return to user. */151 dev_dbg(dev, "%s: return %u back to videobuf2\n",152 av->vdev.name, vb->index);153 vb2_buffer_done(ipu6_isys_buffer_to_vb2_buffer(ib),154 VB2_BUF_STATE_QUEUED);155 }156 spin_unlock_irqrestore(&aq->lock, flags);157 }158}159 160/*161 * Attempt obtaining a buffer list from the incoming queues, a list of buffers162 * that contains one entry from each video buffer queue. If a buffer can't be163 * obtained from every queue, the buffers are returned back to the queue.164 */165static int buffer_list_get(struct ipu6_isys_stream *stream,166 struct ipu6_isys_buffer_list *bl)167{168 struct device *dev = &stream->isys->adev->auxdev.dev;169 struct ipu6_isys_queue *aq;170 unsigned long flags;171 unsigned long buf_flag = IPU6_ISYS_BUFFER_LIST_FL_INCOMING;172 173 bl->nbufs = 0;174 INIT_LIST_HEAD(&bl->head);175 176 list_for_each_entry(aq, &stream->queues, node) {177 struct ipu6_isys_buffer *ib;178 179 spin_lock_irqsave(&aq->lock, flags);180 if (list_empty(&aq->incoming)) {181 spin_unlock_irqrestore(&aq->lock, flags);182 if (!list_empty(&bl->head))183 ipu6_isys_buffer_list_queue(bl, buf_flag, 0);184 return -ENODATA;185 }186 187 ib = list_last_entry(&aq->incoming,188 struct ipu6_isys_buffer, head);189 190 dev_dbg(dev, "buffer: %s: buffer %u\n",191 ipu6_isys_queue_to_video(aq)->vdev.name,192 ipu6_isys_buffer_to_vb2_buffer(ib)->index);193 list_del(&ib->head);194 list_add(&ib->head, &bl->head);195 spin_unlock_irqrestore(&aq->lock, flags);196 197 bl->nbufs++;198 }199 200 dev_dbg(dev, "get buffer list %p, %u buffers\n", bl, bl->nbufs);201 202 return 0;203}204 205static void206ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,207 struct ipu6_fw_isys_frame_buff_set_abi *set)208{209 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);210 211 set->output_pins[aq->fw_output].addr =212 vb2_dma_contig_plane_dma_addr(vb, 0);213 set->output_pins[aq->fw_output].out_buf_id = vb->index + 1;214}215 216/*217 * Convert a buffer list to a isys fw ABI framebuffer set. The218 * buffer list is not modified.219 */220#define IPU6_ISYS_FRAME_NUM_THRESHOLD (30)221void222ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set,223 struct ipu6_isys_stream *stream,224 struct ipu6_isys_buffer_list *bl)225{226 struct ipu6_isys_buffer *ib;227 228 WARN_ON(!bl->nbufs);229 230 set->send_irq_sof = 1;231 set->send_resp_sof = 1;232 set->send_irq_eof = 0;233 set->send_resp_eof = 0;234 235 if (stream->streaming)236 set->send_irq_capture_ack = 0;237 else238 set->send_irq_capture_ack = 1;239 set->send_irq_capture_done = 0;240 241 set->send_resp_capture_ack = 1;242 set->send_resp_capture_done = 1;243 if (atomic_read(&stream->sequence) >= IPU6_ISYS_FRAME_NUM_THRESHOLD) {244 set->send_resp_capture_ack = 0;245 set->send_resp_capture_done = 0;246 }247 248 list_for_each_entry(ib, &bl->head, head) {249 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);250 251 ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);252 }253}254 255/* Start streaming for real. The buffer list must be available. */256static int ipu6_isys_stream_start(struct ipu6_isys_video *av,257 struct ipu6_isys_buffer_list *bl, bool error)258{259 struct ipu6_isys_stream *stream = av->stream;260 struct device *dev = &stream->isys->adev->auxdev.dev;261 struct ipu6_isys_buffer_list __bl;262 int ret;263 264 mutex_lock(&stream->isys->stream_mutex);265 ret = ipu6_isys_video_set_streaming(av, 1, bl);266 mutex_unlock(&stream->isys->stream_mutex);267 if (ret)268 goto out_requeue;269 270 stream->streaming = 1;271 272 bl = &__bl;273 274 do {275 struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;276 struct isys_fw_msgs *msg;277 u16 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE;278 279 ret = buffer_list_get(stream, bl);280 if (ret < 0)281 break;282 283 msg = ipu6_get_fw_msg_buf(stream);284 if (!msg)285 return -ENOMEM;286 287 buf = &msg->fw_msg.frame;288 ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);289 ipu6_fw_isys_dump_frame_buff_set(dev, buf,290 stream->nr_output_pins);291 ipu6_isys_buffer_list_queue(bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE,292 0);293 ret = ipu6_fw_isys_complex_cmd(stream->isys,294 stream->stream_handle, buf,295 msg->dma_addr, sizeof(*buf),296 send_type);297 } while (!WARN_ON(ret));298 299 return 0;300 301out_requeue:302 if (bl && bl->nbufs)303 ipu6_isys_buffer_list_queue(bl,304 IPU6_ISYS_BUFFER_LIST_FL_INCOMING |305 (error ?306 IPU6_ISYS_BUFFER_LIST_FL_SET_STATE :307 0), error ? VB2_BUF_STATE_ERROR :308 VB2_BUF_STATE_QUEUED);309 flush_firmware_streamon_fail(stream);310 311 return ret;312}313 314static void buf_queue(struct vb2_buffer *vb)315{316 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);317 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);318 struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);319 struct ipu6_isys_video_buffer *ivb =320 vb2_buffer_to_ipu6_isys_video_buffer(vvb);321 struct ipu6_isys_buffer *ib = &ivb->ib;322 struct device *dev = &av->isys->adev->auxdev.dev;323 struct media_pipeline *media_pipe =324 media_entity_pipeline(&av->vdev.entity);325 struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;326 struct ipu6_isys_stream *stream = av->stream;327 struct ipu6_isys_buffer_list bl;328 struct isys_fw_msgs *msg;329 unsigned long flags;330 dma_addr_t dma;331 int ret;332 333 dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name);334 335 dma = vb2_dma_contig_plane_dma_addr(vb, 0);336 dev_dbg(dev, "iova: iova %pad\n", &dma);337 338 spin_lock_irqsave(&aq->lock, flags);339 list_add(&ib->head, &aq->incoming);340 spin_unlock_irqrestore(&aq->lock, flags);341 342 if (!media_pipe || !vb->vb2_queue->start_streaming_called) {343 dev_dbg(dev, "media pipeline is not ready for %s\n",344 av->vdev.name);345 return;346 }347 348 mutex_lock(&stream->mutex);349 350 if (stream->nr_streaming != stream->nr_queues) {351 dev_dbg(dev, "not streaming yet, adding to incoming\n");352 goto out;353 }354 355 /*356 * We just put one buffer to the incoming list of this queue357 * (above). Let's see whether all queues in the pipeline would358 * have a buffer.359 */360 ret = buffer_list_get(stream, &bl);361 if (ret < 0) {362 dev_dbg(dev, "No buffers available\n");363 goto out;364 }365 366 msg = ipu6_get_fw_msg_buf(stream);367 if (!msg) {368 ret = -ENOMEM;369 goto out;370 }371 372 buf = &msg->fw_msg.frame;373 ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);374 ipu6_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);375 376 if (!stream->streaming) {377 ret = ipu6_isys_stream_start(av, &bl, true);378 if (ret)379 dev_err(dev, "stream start failed.\n");380 goto out;381 }382 383 /*384 * We must queue the buffers in the buffer list to the385 * appropriate video buffer queues BEFORE passing them to the386 * firmware since we could get a buffer event back before we387 * have queued them ourselves to the active queue.388 */389 ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);390 391 ret = ipu6_fw_isys_complex_cmd(stream->isys, stream->stream_handle,392 buf, msg->dma_addr, sizeof(*buf),393 IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE);394 if (ret < 0)395 dev_err(dev, "send stream capture failed\n");396 397out:398 mutex_unlock(&stream->mutex);399}400 401static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq)402{403 struct v4l2_mbus_framefmt format;404 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);405 struct device *dev = &av->isys->adev->auxdev.dev;406 struct media_pad *remote_pad =407 media_pad_remote_pad_first(av->vdev.entity.pads);408 struct v4l2_subdev *sd;409 u32 r_stream, code;410 int ret;411 412 if (!remote_pad)413 return -ENOTCONN;414 415 sd = media_entity_to_v4l2_subdev(remote_pad->entity);416 r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, remote_pad->index);417 418 ret = ipu6_isys_get_stream_pad_fmt(sd, remote_pad->index, r_stream,419 &format);420 421 if (ret) {422 dev_dbg(dev, "failed to get %s: pad %d, stream:%d format\n",423 sd->entity.name, remote_pad->index, r_stream);424 return ret;425 }426 427 if (format.width != ipu6_isys_get_frame_width(av) ||428 format.height != ipu6_isys_get_frame_height(av)) {429 dev_dbg(dev, "wrong width or height %ux%u (%ux%u expected)\n",430 ipu6_isys_get_frame_width(av),431 ipu6_isys_get_frame_height(av), format.width,432 format.height);433 return -EINVAL;434 }435 436 code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code;437 if (format.code != code) {438 dev_dbg(dev, "wrong mbus code 0x%8.8x (0x%8.8x expected)\n",439 code, format.code);440 return -EINVAL;441 }442 443 return 0;444}445 446static void return_buffers(struct ipu6_isys_queue *aq,447 enum vb2_buffer_state state)448{449 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);450 struct ipu6_isys_buffer *ib;451 bool need_reset = false;452 unsigned long flags;453 454 spin_lock_irqsave(&aq->lock, flags);455 while (!list_empty(&aq->incoming)) {456 struct vb2_buffer *vb;457 458 ib = list_first_entry(&aq->incoming, struct ipu6_isys_buffer,459 head);460 vb = ipu6_isys_buffer_to_vb2_buffer(ib);461 list_del(&ib->head);462 spin_unlock_irqrestore(&aq->lock, flags);463 464 vb2_buffer_done(vb, state);465 466 spin_lock_irqsave(&aq->lock, flags);467 }468 469 /*470 * Something went wrong (FW crash / HW hang / not all buffers471 * returned from isys) if there are still buffers queued in active472 * queue. We have to clean up places a bit.473 */474 while (!list_empty(&aq->active)) {475 struct vb2_buffer *vb;476 477 ib = list_first_entry(&aq->active, struct ipu6_isys_buffer,478 head);479 vb = ipu6_isys_buffer_to_vb2_buffer(ib);480 481 list_del(&ib->head);482 spin_unlock_irqrestore(&aq->lock, flags);483 484 vb2_buffer_done(vb, state);485 486 spin_lock_irqsave(&aq->lock, flags);487 need_reset = true;488 }489 490 spin_unlock_irqrestore(&aq->lock, flags);491 492 if (need_reset) {493 mutex_lock(&av->isys->mutex);494 av->isys->need_reset = true;495 mutex_unlock(&av->isys->mutex);496 }497}498 499static void ipu6_isys_stream_cleanup(struct ipu6_isys_video *av)500{501 video_device_pipeline_stop(&av->vdev);502 ipu6_isys_put_stream(av->stream);503 av->stream = NULL;504}505 506static int start_streaming(struct vb2_queue *q, unsigned int count)507{508 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);509 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);510 struct device *dev = &av->isys->adev->auxdev.dev;511 const struct ipu6_isys_pixelformat *pfmt =512 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);513 struct ipu6_isys_buffer_list __bl, *bl = NULL;514 struct ipu6_isys_stream *stream;515 struct media_entity *source_entity = NULL;516 int nr_queues, ret;517 518 dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n",519 av->vdev.name, ipu6_isys_get_frame_width(av),520 ipu6_isys_get_frame_height(av), pfmt->css_pixelformat);521 522 ret = ipu6_isys_setup_video(av, &source_entity, &nr_queues);523 if (ret < 0) {524 dev_dbg(dev, "failed to setup video\n");525 goto out_return_buffers;526 }527 528 ret = ipu6_isys_link_fmt_validate(aq);529 if (ret) {530 dev_dbg(dev,531 "%s: link format validation failed (%d)\n",532 av->vdev.name, ret);533 goto out_pipeline_stop;534 }535 536 ret = ipu6_isys_fw_open(av->isys);537 if (ret)538 goto out_pipeline_stop;539 540 stream = av->stream;541 mutex_lock(&stream->mutex);542 if (!stream->nr_streaming) {543 ret = ipu6_isys_video_prepare_stream(av, source_entity,544 nr_queues);545 if (ret)546 goto out_fw_close;547 }548 549 stream->nr_streaming++;550 dev_dbg(dev, "queue %u of %u\n", stream->nr_streaming,551 stream->nr_queues);552 553 list_add(&aq->node, &stream->queues);554 ipu6_isys_configure_stream_watermark(av, true);555 ipu6_isys_update_stream_watermark(av, true);556 557 if (stream->nr_streaming != stream->nr_queues)558 goto out;559 560 bl = &__bl;561 ret = buffer_list_get(stream, bl);562 if (ret < 0) {563 dev_warn(dev, "no buffer available, DRIVER BUG?\n");564 goto out;565 }566 567 ret = ipu6_isys_stream_start(av, bl, false);568 if (ret)569 goto out_stream_start;570 571out:572 mutex_unlock(&stream->mutex);573 574 return 0;575 576out_stream_start:577 ipu6_isys_update_stream_watermark(av, false);578 list_del(&aq->node);579 stream->nr_streaming--;580 581out_fw_close:582 mutex_unlock(&stream->mutex);583 ipu6_isys_fw_close(av->isys);584 585out_pipeline_stop:586 ipu6_isys_stream_cleanup(av);587 588out_return_buffers:589 return_buffers(aq, VB2_BUF_STATE_QUEUED);590 591 return ret;592}593 594static void stop_streaming(struct vb2_queue *q)595{596 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);597 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);598 struct ipu6_isys_stream *stream = av->stream;599 600 mutex_lock(&stream->mutex);601 602 ipu6_isys_update_stream_watermark(av, false);603 604 mutex_lock(&av->isys->stream_mutex);605 if (stream->nr_streaming == stream->nr_queues && stream->streaming)606 ipu6_isys_video_set_streaming(av, 0, NULL);607 mutex_unlock(&av->isys->stream_mutex);608 609 stream->nr_streaming--;610 list_del(&aq->node);611 stream->streaming = 0;612 mutex_unlock(&stream->mutex);613 614 ipu6_isys_stream_cleanup(av);615 616 return_buffers(aq, VB2_BUF_STATE_ERROR);617 618 ipu6_isys_fw_close(av->isys);619}620 621static unsigned int622get_sof_sequence_by_timestamp(struct ipu6_isys_stream *stream,623 struct ipu6_fw_isys_resp_info_abi *info)624{625 u64 time = (u64)info->timestamp[1] << 32 | info->timestamp[0];626 struct ipu6_isys *isys = stream->isys;627 struct device *dev = &isys->adev->auxdev.dev;628 unsigned int i;629 630 /*631 * The timestamp is invalid as no TSC in some FPGA platform,632 * so get the sequence from pipeline directly in this case.633 */634 if (time == 0)635 return atomic_read(&stream->sequence) - 1;636 637 for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++)638 if (time == stream->seq[i].timestamp) {639 dev_dbg(dev, "sof: using seq nr %u for ts %llu\n",640 stream->seq[i].sequence, time);641 return stream->seq[i].sequence;642 }643 644 for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++)645 dev_dbg(dev, "sof: sequence %u, timestamp value %llu\n",646 stream->seq[i].sequence, stream->seq[i].timestamp);647 648 return 0;649}650 651static u64 get_sof_ns_delta(struct ipu6_isys_video *av,652 struct ipu6_fw_isys_resp_info_abi *info)653{654 struct ipu6_bus_device *adev = av->isys->adev;655 struct ipu6_device *isp = adev->isp;656 u64 delta, tsc_now;657 658 ipu6_buttress_tsc_read(isp, &tsc_now);659 if (!tsc_now)660 return 0;661 662 delta = tsc_now - ((u64)info->timestamp[1] << 32 | info->timestamp[0]);663 664 return ipu6_buttress_tsc_ticks_to_ns(delta, isp);665}666 667void ipu6_isys_buf_calc_sequence_time(struct ipu6_isys_buffer *ib,668 struct ipu6_fw_isys_resp_info_abi *info)669{670 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);671 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);672 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);673 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);674 struct device *dev = &av->isys->adev->auxdev.dev;675 struct ipu6_isys_stream *stream = av->stream;676 u64 ns;677 u32 sequence;678 679 ns = ktime_get_ns() - get_sof_ns_delta(av, info);680 sequence = get_sof_sequence_by_timestamp(stream, info);681 682 vbuf->vb2_buf.timestamp = ns;683 vbuf->sequence = sequence;684 685 dev_dbg(dev, "buf: %s: buffer done, CPU-timestamp:%lld, sequence:%d\n",686 av->vdev.name, ktime_get_ns(), sequence);687 dev_dbg(dev, "index:%d, vbuf timestamp:%lld\n", vb->index,688 vbuf->vb2_buf.timestamp);689}690 691void ipu6_isys_queue_buf_done(struct ipu6_isys_buffer *ib)692{693 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);694 695 if (atomic_read(&ib->str2mmio_flag)) {696 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);697 /*698 * Operation on buffer is ended with error and will be reported699 * to the userspace when it is de-queued700 */701 atomic_set(&ib->str2mmio_flag, 0);702 } else {703 vb2_buffer_done(vb, VB2_BUF_STATE_DONE);704 }705}706 707void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,708 struct ipu6_fw_isys_resp_info_abi *info)709{710 struct ipu6_isys_queue *aq = stream->output_pins[info->pin_id].aq;711 struct ipu6_isys *isys = stream->isys;712 struct device *dev = &isys->adev->auxdev.dev;713 struct ipu6_isys_buffer *ib;714 struct vb2_buffer *vb;715 unsigned long flags;716 bool first = true;717 struct vb2_v4l2_buffer *buf;718 719 spin_lock_irqsave(&aq->lock, flags);720 if (list_empty(&aq->active)) {721 spin_unlock_irqrestore(&aq->lock, flags);722 dev_err(dev, "active queue empty\n");723 return;724 }725 726 list_for_each_entry_reverse(ib, &aq->active, head) {727 dma_addr_t addr;728 729 vb = ipu6_isys_buffer_to_vb2_buffer(ib);730 addr = vb2_dma_contig_plane_dma_addr(vb, 0);731 732 if (info->pin.addr != addr) {733 if (first)734 dev_err(dev, "Unexpected buffer address %pad\n",735 &addr);736 first = false;737 continue;738 }739 740 if (info->error_info.error ==741 IPU6_FW_ISYS_ERROR_HW_REPORTED_STR2MMIO) {742 /*743 * Check for error message:744 * 'IPU6_FW_ISYS_ERROR_HW_REPORTED_STR2MMIO'745 */746 atomic_set(&ib->str2mmio_flag, 1);747 }748 dev_dbg(dev, "buffer: found buffer %pad\n", &addr);749 750 buf = to_vb2_v4l2_buffer(vb);751 buf->field = V4L2_FIELD_NONE;752 753 list_del(&ib->head);754 spin_unlock_irqrestore(&aq->lock, flags);755 756 ipu6_isys_buf_calc_sequence_time(ib, info);757 758 ipu6_isys_queue_buf_done(ib);759 760 return;761 }762 763 dev_err(dev, "Failed to find a matching video buffer");764 765 spin_unlock_irqrestore(&aq->lock, flags);766}767 768static const struct vb2_ops ipu6_isys_queue_ops = {769 .queue_setup = queue_setup,770 .wait_prepare = vb2_ops_wait_prepare,771 .wait_finish = vb2_ops_wait_finish,772 .buf_prepare = ipu6_isys_buf_prepare,773 .start_streaming = start_streaming,774 .stop_streaming = stop_streaming,775 .buf_queue = buf_queue,776};777 778int ipu6_isys_queue_init(struct ipu6_isys_queue *aq)779{780 struct ipu6_isys *isys = ipu6_isys_queue_to_video(aq)->isys;781 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);782 int ret;783 784 /* no support for userptr */785 if (!aq->vbq.io_modes)786 aq->vbq.io_modes = VB2_MMAP | VB2_DMABUF;787 788 aq->vbq.drv_priv = aq;789 aq->vbq.ops = &ipu6_isys_queue_ops;790 aq->vbq.lock = &av->mutex;791 aq->vbq.mem_ops = &vb2_dma_contig_memops;792 aq->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;793 aq->vbq.min_queued_buffers = 1;794 aq->vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;795 796 ret = vb2_queue_init(&aq->vbq);797 if (ret)798 return ret;799 800 aq->dev = &isys->adev->auxdev.dev;801 aq->vbq.dev = &isys->adev->auxdev.dev;802 spin_lock_init(&aq->lock);803 INIT_LIST_HEAD(&aq->active);804 INIT_LIST_HEAD(&aq->incoming);805 806 return 0;807}808